diff --git a/buildengine/deploy.go b/buildengine/deploy.go index d533195e0a..ced1152336 100644 --- a/buildengine/deploy.go +++ b/buildengine/deploy.go @@ -26,8 +26,16 @@ type deploymentArtefact struct { localPath string } +type DeployClient interface { + GetArtefactDiffs(context.Context, *connect.Request[ftlv1.GetArtefactDiffsRequest]) (*connect.Response[ftlv1.GetArtefactDiffsResponse], error) + UploadArtefact(context.Context, *connect.Request[ftlv1.UploadArtefactRequest]) (*connect.Response[ftlv1.UploadArtefactResponse], error) + CreateDeployment(context.Context, *connect.Request[ftlv1.CreateDeploymentRequest]) (*connect.Response[ftlv1.CreateDeploymentResponse], error) + ReplaceDeploy(context.Context, *connect.Request[ftlv1.ReplaceDeployRequest]) (*connect.Response[ftlv1.ReplaceDeployResponse], error) + Status(context.Context, *connect.Request[ftlv1.StatusRequest]) (*connect.Response[ftlv1.StatusResponse], error) +} + // Deploy a module to the FTL controller with the given number of replicas. Optionally wait for the deployment to become ready. -func Deploy(ctx context.Context, module Module, replicas int32, waitForDeployOnline bool, client ftlv1connect.ControllerServiceClient) error { +func Deploy(ctx context.Context, module Module, replicas int32, waitForDeployOnline bool, client DeployClient) error { logger := log.FromContext(ctx).Scope(module.Module) ctx = log.ContextWithLogger(ctx, logger) logger.Infof("Deploying module") @@ -221,7 +229,7 @@ func relToCWD(path string) string { return rel } -func checkReadiness(ctx context.Context, client ftlv1connect.ControllerServiceClient, deploymentName string, replicas int32) error { +func checkReadiness(ctx context.Context, client DeployClient, deploymentName string, replicas int32) error { ticker := time.NewTicker(time.Second) defer ticker.Stop() diff --git a/buildengine/deploy_test.go b/buildengine/deploy_test.go new file mode 100644 index 0000000000..e70f81f3e3 --- /dev/null +++ b/buildengine/deploy_test.go @@ -0,0 +1,84 @@ +package buildengine + +import ( + "context" + "os" + "testing" + + "connectrpc.com/connect" + ftlv1 "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1" + "github.com/TBD54566975/ftl/backend/schema" + "github.com/TBD54566975/ftl/internal/log" + "github.com/TBD54566975/ftl/internal/sha256" + "github.com/alecthomas/assert/v2" +) + +type mockDeployClient struct { + MissingDigests []string + DeploymentName string +} + +func (m *mockDeployClient) GetArtefactDiffs(context.Context, *connect.Request[ftlv1.GetArtefactDiffsRequest]) (*connect.Response[ftlv1.GetArtefactDiffsResponse], error) { + return connect.NewResponse(&ftlv1.GetArtefactDiffsResponse{ + MissingDigests: m.MissingDigests, + }), nil +} + +func (m *mockDeployClient) UploadArtefact(ctx context.Context, req *connect.Request[ftlv1.UploadArtefactRequest]) (*connect.Response[ftlv1.UploadArtefactResponse], error) { + sha256digest := sha256.Sum(req.Msg.Content) + return connect.NewResponse(&ftlv1.UploadArtefactResponse{Digest: sha256digest[:]}), nil +} + +func (m *mockDeployClient) CreateDeployment(context.Context, *connect.Request[ftlv1.CreateDeploymentRequest]) (*connect.Response[ftlv1.CreateDeploymentResponse], error) { + return connect.NewResponse(&ftlv1.CreateDeploymentResponse{DeploymentName: m.DeploymentName}), nil +} + +func (m *mockDeployClient) ReplaceDeploy(context.Context, *connect.Request[ftlv1.ReplaceDeployRequest]) (*connect.Response[ftlv1.ReplaceDeployResponse], error) { + return nil, nil +} + +func (m *mockDeployClient) Status(context.Context, *connect.Request[ftlv1.StatusRequest]) (*connect.Response[ftlv1.StatusResponse], error) { + resp := &ftlv1.StatusResponse{ + Deployments: []*ftlv1.StatusResponse_Deployment{ + {Key: m.DeploymentName, Replicas: 1}, + }, + } + return connect.NewResponse(resp), nil +} + +func TestDeploy(t *testing.T) { + sch := &schema.Schema{ + Modules: []*schema.Module{ + schema.Builtins(), + {Name: "another", Decls: []schema.Decl{ + &schema.Data{Name: "EchoRequest"}, + &schema.Data{Name: "EchoResponse"}, + &schema.Verb{ + Name: "echo", + Request: &schema.DataRef{Name: "EchoRequest"}, + Response: &schema.DataRef{Name: "EchoResponse"}, + }, + }}, + }, + } + ctx := log.ContextWithLogger(context.Background(), log.Configure(os.Stderr, log.Config{})) + + modulePath := "testdata/modules/another" + module, err := LoadModule(ctx, modulePath) + assert.NoError(t, err) + + // Build first to make sure the files are there. + err = Build(ctx, sch, module) + assert.NoError(t, err) + + sum, err := sha256.SumFile(modulePath + "/_ftl/main") + assert.NoError(t, err) + + client := &mockDeployClient{ + MissingDigests: []string{sum.String()}, + DeploymentName: "test-deployment", + } + + err = Deploy(ctx, module, int32(1), true, client) + assert.NoError(t, err) +}