//go:build integration package coredeno import ( "context" "os" "os/exec" "path/filepath" "testing" "time" pb "forge.lthn.ai/core/go/pkg/coredeno/proto" core "forge.lthn.ai/core/go/pkg/framework/core" "forge.lthn.ai/core/go/pkg/marketplace" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) // unused import guard var _ = pb.NewCoreServiceClient func findDeno(t *testing.T) string { t.Helper() denoPath, err := exec.LookPath("deno") if err != nil { home, _ := os.UserHomeDir() denoPath = filepath.Join(home, ".deno", "bin", "deno") if _, err := os.Stat(denoPath); err != nil { t.Skip("deno not installed") } } return denoPath } // runtimeEntryPoint returns the absolute path to runtime/main.ts. func runtimeEntryPoint(t *testing.T) string { t.Helper() // We're in pkg/coredeno/ during test, runtime is a subdir abs, err := filepath.Abs("runtime/main.ts") require.NoError(t, err) require.FileExists(t, abs) return abs } // testModulePath returns the absolute path to runtime/testdata/test-module.ts. func testModulePath(t *testing.T) string { t.Helper() abs, err := filepath.Abs("runtime/testdata/test-module.ts") require.NoError(t, err) require.FileExists(t, abs) return abs } func TestIntegration_FullBoot_Good(t *testing.T) { denoPath := findDeno(t) tmpDir := t.TempDir() sockPath := filepath.Join(tmpDir, "core.sock") // Write a manifest coreDir := filepath.Join(tmpDir, ".core") require.NoError(t, os.MkdirAll(coreDir, 0755)) require.NoError(t, os.WriteFile(filepath.Join(coreDir, "view.yml"), []byte(` code: integration-test name: Integration Test version: "1.0" permissions: read: ["./data/"] `), 0644)) entryPoint := runtimeEntryPoint(t) opts := Options{ DenoPath: denoPath, SocketPath: sockPath, AppRoot: tmpDir, StoreDBPath: ":memory:", SidecarArgs: []string{"run", "-A", entryPoint}, } c, err := core.New() require.NoError(t, err) factory := NewServiceFactory(opts) result, err := factory(c) require.NoError(t, err) svc := result.(*Service) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() err = svc.OnStartup(ctx) require.NoError(t, err) // Verify gRPC is working require.Eventually(t, func() bool { _, err := os.Stat(sockPath) return err == nil }, 5*time.Second, 50*time.Millisecond, "socket should appear") conn, err := grpc.NewClient( "unix://"+sockPath, grpc.WithTransportCredentials(insecure.NewCredentials()), ) require.NoError(t, err) defer conn.Close() client := pb.NewCoreServiceClient(conn) _, err = client.StoreSet(ctx, &pb.StoreSetRequest{ Group: "integration", Key: "boot", Value: "ok", }) require.NoError(t, err) resp, err := client.StoreGet(ctx, &pb.StoreGetRequest{ Group: "integration", Key: "boot", }) require.NoError(t, err) assert.Equal(t, "ok", resp.Value) assert.True(t, resp.Found) // Verify sidecar is running assert.True(t, svc.sidecar.IsRunning(), "Deno sidecar should be running") // Clean shutdown err = svc.OnShutdown(context.Background()) assert.NoError(t, err) assert.False(t, svc.sidecar.IsRunning(), "Deno sidecar should be stopped") } func TestIntegration_Tier2_Bidirectional_Good(t *testing.T) { denoPath := findDeno(t) tmpDir := t.TempDir() sockPath := filepath.Join(tmpDir, "core.sock") denoSockPath := filepath.Join(tmpDir, "deno.sock") // Write a manifest coreDir := filepath.Join(tmpDir, ".core") require.NoError(t, os.MkdirAll(coreDir, 0755)) require.NoError(t, os.WriteFile(filepath.Join(coreDir, "view.yml"), []byte(` code: tier2-test name: Tier 2 Test version: "1.0" permissions: read: ["./data/"] run: ["echo"] `), 0644)) entryPoint := runtimeEntryPoint(t) opts := Options{ DenoPath: denoPath, SocketPath: sockPath, DenoSocketPath: denoSockPath, AppRoot: tmpDir, StoreDBPath: ":memory:", SidecarArgs: []string{"run", "-A", "--unstable-worker-options", entryPoint}, } c, err := core.New() require.NoError(t, err) factory := NewServiceFactory(opts) result, err := factory(c) require.NoError(t, err) svc := result.(*Service) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() err = svc.OnStartup(ctx) require.NoError(t, err) // Verify both sockets appeared require.Eventually(t, func() bool { _, err := os.Stat(sockPath) return err == nil }, 10*time.Second, 50*time.Millisecond, "core socket should appear") require.Eventually(t, func() bool { _, err := os.Stat(denoSockPath) return err == nil }, 10*time.Second, 50*time.Millisecond, "deno socket should appear") // Verify sidecar is running assert.True(t, svc.sidecar.IsRunning(), "Deno sidecar should be running") // Verify DenoClient is connected require.NotNil(t, svc.DenoClient(), "DenoClient should be connected") // Test Go → Deno: LoadModule with real Worker modPath := testModulePath(t) loadResp, err := svc.DenoClient().LoadModule("test-module", modPath, ModulePermissions{ Read: []string{filepath.Dir(modPath) + "/"}, }) require.NoError(t, err) assert.True(t, loadResp.Ok) // Wait for module to finish loading (async Worker init) require.Eventually(t, func() bool { resp, err := svc.DenoClient().ModuleStatus("test-module") return err == nil && (resp.Status == "RUNNING" || resp.Status == "ERRORED") }, 5*time.Second, 50*time.Millisecond, "module should finish loading") statusResp, err := svc.DenoClient().ModuleStatus("test-module") require.NoError(t, err) assert.Equal(t, "test-module", statusResp.Code) assert.Equal(t, "RUNNING", statusResp.Status) // Test Go → Deno: UnloadModule unloadResp, err := svc.DenoClient().UnloadModule("test-module") require.NoError(t, err) assert.True(t, unloadResp.Ok) // Verify module is now STOPPED statusResp2, err := svc.DenoClient().ModuleStatus("test-module") require.NoError(t, err) assert.Equal(t, "STOPPED", statusResp2.Status) // Verify CoreService gRPC still works (Deno wrote health check data) conn, err := grpc.NewClient( "unix://"+sockPath, grpc.WithTransportCredentials(insecure.NewCredentials()), ) require.NoError(t, err) defer conn.Close() coreClient := pb.NewCoreServiceClient(conn) getResp, err := coreClient.StoreGet(ctx, &pb.StoreGetRequest{ Group: "_coredeno", Key: "status", }) require.NoError(t, err) assert.True(t, getResp.Found) assert.Equal(t, "connected", getResp.Value, "Deno should have written health check") // Clean shutdown err = svc.OnShutdown(context.Background()) assert.NoError(t, err) assert.False(t, svc.sidecar.IsRunning(), "Deno sidecar should be stopped") } func TestIntegration_Tier3_WorkerIsolation_Good(t *testing.T) { denoPath := findDeno(t) tmpDir := t.TempDir() sockPath := filepath.Join(tmpDir, "core.sock") denoSockPath := filepath.Join(tmpDir, "deno.sock") // Write a manifest coreDir := filepath.Join(tmpDir, ".core") require.NoError(t, os.MkdirAll(coreDir, 0755)) require.NoError(t, os.WriteFile(filepath.Join(coreDir, "view.yml"), []byte(` code: tier3-test name: Tier 3 Test version: "1.0" permissions: read: ["./data/"] `), 0644)) entryPoint := runtimeEntryPoint(t) modPath := testModulePath(t) opts := Options{ DenoPath: denoPath, SocketPath: sockPath, DenoSocketPath: denoSockPath, AppRoot: tmpDir, StoreDBPath: ":memory:", SidecarArgs: []string{"run", "-A", "--unstable-worker-options", entryPoint}, } c, err := core.New() require.NoError(t, err) factory := NewServiceFactory(opts) result, err := factory(c) require.NoError(t, err) svc := result.(*Service) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() err = svc.OnStartup(ctx) require.NoError(t, err) // Verify both sockets appeared require.Eventually(t, func() bool { _, err := os.Stat(denoSockPath) return err == nil }, 10*time.Second, 50*time.Millisecond, "deno socket should appear") require.NotNil(t, svc.DenoClient(), "DenoClient should be connected") // Load a real module — it writes to store via I/O bridge loadResp, err := svc.DenoClient().LoadModule("test-mod", modPath, ModulePermissions{ Read: []string{filepath.Dir(modPath) + "/"}, }) require.NoError(t, err) assert.True(t, loadResp.Ok) // Wait for module to reach RUNNING (Worker init + init() completes) require.Eventually(t, func() bool { resp, err := svc.DenoClient().ModuleStatus("test-mod") return err == nil && resp.Status == "RUNNING" }, 10*time.Second, 100*time.Millisecond, "module should be RUNNING") // Verify the module wrote to the store via the I/O bridge // Module calls: core.storeSet("test-module", "init", "ok") conn, err := grpc.NewClient( "unix://"+sockPath, grpc.WithTransportCredentials(insecure.NewCredentials()), ) require.NoError(t, err) defer conn.Close() coreClient := pb.NewCoreServiceClient(conn) // Poll for the store value — module init is async require.Eventually(t, func() bool { resp, err := coreClient.StoreGet(ctx, &pb.StoreGetRequest{ Group: "test-module", Key: "init", }) return err == nil && resp.Found && resp.Value == "ok" }, 5*time.Second, 100*time.Millisecond, "module should have written to store via I/O bridge") // Unload and verify unloadResp, err := svc.DenoClient().UnloadModule("test-mod") require.NoError(t, err) assert.True(t, unloadResp.Ok) statusResp, err := svc.DenoClient().ModuleStatus("test-mod") require.NoError(t, err) assert.Equal(t, "STOPPED", statusResp.Status) // Clean shutdown err = svc.OnShutdown(context.Background()) assert.NoError(t, err) assert.False(t, svc.sidecar.IsRunning(), "Deno sidecar should be stopped") } // createModuleRepo creates a git repo containing a test module with manifest + main.ts. // The module's init() writes to the store to prove the I/O bridge works. func createModuleRepo(t *testing.T, code string) string { t.Helper() dir := filepath.Join(t.TempDir(), code+"-repo") require.NoError(t, os.MkdirAll(filepath.Join(dir, ".core"), 0755)) require.NoError(t, os.WriteFile(filepath.Join(dir, ".core", "view.yml"), []byte(` code: `+code+` name: Test Module `+code+` version: "1.0" permissions: read: ["./"] `), 0644)) // Module that writes to store to prove it ran require.NoError(t, os.WriteFile(filepath.Join(dir, "main.ts"), []byte(` export async function init(core: any) { await core.storeSet("`+code+`", "installed", "yes"); } `), 0644)) gitCmd := func(args ...string) { t.Helper() cmd := exec.Command("git", append([]string{ "-C", dir, "-c", "user.email=test@test.com", "-c", "user.name=test", }, args...)...) out, err := cmd.CombinedOutput() require.NoError(t, err, "git %v: %s", args, string(out)) } gitCmd("init") gitCmd("add", ".") gitCmd("commit", "-m", "init") return dir } func TestIntegration_Tier4_MarketplaceInstall_Good(t *testing.T) { denoPath := findDeno(t) tmpDir := t.TempDir() sockPath := filepath.Join(tmpDir, "core.sock") denoSockPath := filepath.Join(tmpDir, "deno.sock") // Write app manifest coreDir := filepath.Join(tmpDir, ".core") require.NoError(t, os.MkdirAll(coreDir, 0755)) require.NoError(t, os.WriteFile(filepath.Join(coreDir, "view.yml"), []byte(` code: tier4-test name: Tier 4 Test version: "1.0" permissions: read: ["./"] `), 0644)) entryPoint := runtimeEntryPoint(t) opts := Options{ DenoPath: denoPath, SocketPath: sockPath, DenoSocketPath: denoSockPath, AppRoot: tmpDir, StoreDBPath: ":memory:", SidecarArgs: []string{"run", "-A", "--unstable-worker-options", entryPoint}, } c, err := core.New() require.NoError(t, err) factory := NewServiceFactory(opts) result, err := factory(c) require.NoError(t, err) svc := result.(*Service) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() err = svc.OnStartup(ctx) require.NoError(t, err) // Verify sidecar and Deno client are up require.Eventually(t, func() bool { _, err := os.Stat(denoSockPath) return err == nil }, 10*time.Second, 50*time.Millisecond, "deno socket should appear") require.NotNil(t, svc.DenoClient(), "DenoClient should be connected") require.NotNil(t, svc.Installer(), "Installer should be available") // Create a test module repo and install it moduleRepo := createModuleRepo(t, "market-mod") err = svc.Installer().Install(ctx, marketplace.Module{ Code: "market-mod", Repo: moduleRepo, }) require.NoError(t, err) // Verify the module was installed on disk modulesDir := filepath.Join(tmpDir, "modules", "market-mod") require.DirExists(t, modulesDir) // Verify Installed() returns it installed, err := svc.Installer().Installed() require.NoError(t, err) require.Len(t, installed, 1) assert.Equal(t, "market-mod", installed[0].Code) assert.Equal(t, "1.0", installed[0].Version) // Load the installed module into the Deno runtime mod := installed[0] loadResp, err := svc.DenoClient().LoadModule(mod.Code, mod.EntryPoint, ModulePermissions{ Read: mod.Permissions.Read, }) require.NoError(t, err) assert.True(t, loadResp.Ok) // Wait for module to reach RUNNING require.Eventually(t, func() bool { resp, err := svc.DenoClient().ModuleStatus("market-mod") return err == nil && resp.Status == "RUNNING" }, 10*time.Second, 100*time.Millisecond, "installed module should be RUNNING") // Verify the module wrote to the store via I/O bridge conn, err := grpc.NewClient( "unix://"+sockPath, grpc.WithTransportCredentials(insecure.NewCredentials()), ) require.NoError(t, err) defer conn.Close() coreClient := pb.NewCoreServiceClient(conn) require.Eventually(t, func() bool { resp, err := coreClient.StoreGet(ctx, &pb.StoreGetRequest{ Group: "market-mod", Key: "installed", }) return err == nil && resp.Found && resp.Value == "yes" }, 5*time.Second, 100*time.Millisecond, "installed module should have written to store via I/O bridge") // Unload and remove unloadResp, err := svc.DenoClient().UnloadModule("market-mod") require.NoError(t, err) assert.True(t, unloadResp.Ok) err = svc.Installer().Remove("market-mod") require.NoError(t, err) assert.NoDirExists(t, modulesDir, "module directory should be removed") installed2, err := svc.Installer().Installed() require.NoError(t, err) assert.Empty(t, installed2, "no modules should be installed after remove") // Clean shutdown err = svc.OnShutdown(context.Background()) assert.NoError(t, err) assert.False(t, svc.sidecar.IsRunning(), "Deno sidecar should be stopped") }