bcode_server 0.0.1-alpha.0

Local bcode daemon runtime
use crate::ServerState;
use bcode_workflow_store::representation::{self, attempts, graph};
use bcode_workflow_store::{
    ActivationDispatchOwner, ActivationDispatchPlan, PendingActivation, PreparedActivationDispatch,
    PreparedAttempt, WorkflowExecutionAuthority, WorkflowStoreError,
};

pub struct RejectingOwner;
impl ActivationDispatchOwner for RejectingOwner {
    fn plan<'a>(
        &'a self,
        _: &'a PendingActivation,
    ) -> std::pin::Pin<
        Box<
            dyn std::future::Future<
                    Output = Result<Option<ActivationDispatchPlan>, WorkflowStoreError>,
                > + Send
                + 'a,
        >,
    > {
        Box::pin(async { Ok(None) })
    }
    fn dispatch<'a>(
        &'a self,
        _: &'a PreparedActivationDispatch,
    ) -> std::pin::Pin<
        Box<
            dyn std::future::Future<Output = Result<serde_json::Value, WorkflowStoreError>>
                + Send
                + 'a,
        >,
    > {
        Box::pin(async {
            Err(WorkflowStoreError::InvalidData(
                "private injected failure".into(),
            ))
        })
    }
}

pub async fn prepare() -> (
    tempfile::TempDir,
    ServerState,
    switchy_database::rusqlite::RusqliteDatabase,
    WorkflowExecutionAuthority,
    PreparedActivationDispatch,
) {
    let root = tempfile::tempdir().unwrap();
    let store =
        bcode_workflow_store::WorkflowStore::create_coexistence_baseline(root.path()).unwrap();
    let path = store.path().to_path_buf();
    let state = crate::tests::test_server_state_with_fake_provider_and_workflow_store(
        bcode_session::SessionManager::default(),
        store,
    );
    let db = diagnostic_database(&path).await;
    let definition = bcode_workflow::WorkflowBuilder::new(
        "diagnostic",
        bcode_workflow::Step::task("worker", |v: u32, _| async move { Ok(v) }),
    )
    .build()
    .unwrap()
    .definition()
    .clone();
    let identity =
        bcode_workflow::WorkflowDefinitionIdentity::for_definition("diagnostic", &definition)
            .unwrap();
    let run = bcode_workflow_store::NewWorkflowRun {
        run_id: "diagnostic".into(),
        definition_id: identity.definition_id,
        definition_version: identity.definition_version,
        workspace_snapshot: "workspace".into(),
        parent_session_id: None,
        parent_session_generation: None,
        binding: None,
        authored_provenance: None,
        input: Some(serde_json::json!(1)),
        execution_authority: None,
        created_at_ms: 1,
        authorization_profile: bcode_workflow::WorkflowAuthorizationProfileIdentity {
            version: 1,
            provider_id: "fixture".into(),
            profile_id: "build".into(),
            policy_digest_sha256: "a".repeat(64),
        },
        authorization_ceiling: bcode_workflow::WorkflowToolCapability::ReadOnly,
        limits: bcode_workflow::WorkflowRunLimits::default(),
    };
    representation::admit(&db, &run, &definition).await.unwrap();
    let owner = WorkflowExecutionAuthority {
        target_artifact_id: crate::workflow_operations::current_artifact_id(&state),
        daemon_instance_id: state.daemon_status.instance_id.clone(),
        generation: 1,
        fencing_token: "token".into(),
    };
    attempts::claim_authority(&db, &run.run_id, &owner)
        .await
        .unwrap();
    let activation_id = graph::activation_id(&db, &run.run_id, "worker")
        .await
        .unwrap()
        .unwrap();
    let prepared = PreparedAttempt {
        run_id: run.run_id.clone(),
        node_id: "worker".into(),
        activation_id: activation_id.clone(),
        attempt: 1,
        side_effect: bcode_workflow::DispatchSideEffect::Mutating,
        intent: serde_json::json!({}),
        prepared_at_ms: 1,
    };
    let dispatch_identity = attempts::prepare(&db, &owner, &prepared).await.unwrap();
    let request = PreparedActivationDispatch {
        activation: PendingActivation {
            run_id: run.run_id,
            node_id: "worker".into(),
            activation_id,
            node: definition.nodes["worker"].clone(),
            input: Some(serde_json::json!(1)),
            dependency_generation: 1,
            created_at_ms: 1,
        },
        attempt: 1,
        dispatch_identity,
        intent: prepared.intent,
    };
    (root, state, db, owner, request)
}

async fn diagnostic_database(
    path: &std::path::Path,
) -> switchy_database::rusqlite::RusqliteDatabase {
    let db = switchy_database_connection::open_sqlite_rusqlite(
        path,
        &switchy_database_connection::SqliteOpenOptions {
            access: switchy_database_connection::SqliteAccess::ReadWrite,
            allow_uri: false,
            busy_timeout: std::time::Duration::ZERO,
            foreign_keys: true,
            connections: std::num::NonZeroUsize::MIN,
        },
    )
    .unwrap();
    representation::install(&db).await.unwrap();
    let tx = switchy_database::Database::begin_transaction_with_mode(
        &db,
        switchy_database::TransactionMode::Immediate,
    )
    .await
    .unwrap();
    representation::admission_observation::install_in(&*tx)
        .await
        .unwrap();
    tx.commit().await.unwrap();
    db
}