|
| 1 | +package main |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "net/http" |
| 6 | + "net/http/httptest" |
| 7 | + "os/exec" |
| 8 | + "testing" |
| 9 | + "time" |
| 10 | + |
| 11 | + "forge.lthn.ai/core/go-scm/manifest" |
| 12 | + "github.com/stretchr/testify/assert" |
| 13 | + "github.com/stretchr/testify/require" |
| 14 | +) |
| 15 | + |
| 16 | +func TestFindFreePort_Good(t *testing.T) { |
| 17 | + port, err := findFreePort() |
| 18 | + require.NoError(t, err) |
| 19 | + assert.Greater(t, port, 0) |
| 20 | + assert.Less(t, port, 65536) |
| 21 | +} |
| 22 | + |
| 23 | +func TestFindFreePort_UniquePerCall(t *testing.T) { |
| 24 | + port1, err := findFreePort() |
| 25 | + require.NoError(t, err) |
| 26 | + port2, err := findFreePort() |
| 27 | + require.NoError(t, err) |
| 28 | + // Two consecutive calls should very likely return different ports. |
| 29 | + // (Not guaranteed, but effectively always true.) |
| 30 | + assert.NotEqual(t, port1, port2) |
| 31 | +} |
| 32 | + |
| 33 | +func TestWaitForHealth_Good(t *testing.T) { |
| 34 | + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 35 | + w.WriteHeader(http.StatusOK) |
| 36 | + })) |
| 37 | + defer srv.Close() |
| 38 | + |
| 39 | + err := waitForHealth(srv.URL, 5*time.Second) |
| 40 | + assert.NoError(t, err) |
| 41 | +} |
| 42 | + |
| 43 | +func TestWaitForHealth_Bad_Timeout(t *testing.T) { |
| 44 | + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 45 | + w.WriteHeader(http.StatusServiceUnavailable) |
| 46 | + })) |
| 47 | + defer srv.Close() |
| 48 | + |
| 49 | + err := waitForHealth(srv.URL, 500*time.Millisecond) |
| 50 | + require.Error(t, err) |
| 51 | + assert.Contains(t, err.Error(), "timed out") |
| 52 | +} |
| 53 | + |
| 54 | +func TestWaitForHealth_Bad_NoServer(t *testing.T) { |
| 55 | + err := waitForHealth("http://127.0.0.1:1", 500*time.Millisecond) |
| 56 | + require.Error(t, err) |
| 57 | + assert.Contains(t, err.Error(), "timed out") |
| 58 | +} |
| 59 | + |
| 60 | +func TestDefaultProvidersDir_Good(t *testing.T) { |
| 61 | + dir := defaultProvidersDir() |
| 62 | + assert.Contains(t, dir, ".core") |
| 63 | + assert.Contains(t, dir, "providers") |
| 64 | +} |
| 65 | + |
| 66 | +func TestRuntimeManager_List_Good_Empty(t *testing.T) { |
| 67 | + rm := NewRuntimeManager(nil) |
| 68 | + infos := rm.List() |
| 69 | + assert.Empty(t, infos) |
| 70 | +} |
| 71 | + |
| 72 | +func TestRuntimeManager_List_Good_WithProviders(t *testing.T) { |
| 73 | + rm := NewRuntimeManager(nil) |
| 74 | + rm.providers = []*RuntimeProvider{ |
| 75 | + { |
| 76 | + Dir: "/tmp/test-provider", |
| 77 | + Port: 12345, |
| 78 | + Manifest: &manifest.Manifest{ |
| 79 | + Code: "test-svc", |
| 80 | + Name: "Test Service", |
| 81 | + Version: "1.0.0", |
| 82 | + Namespace: "test", |
| 83 | + }, |
| 84 | + }, |
| 85 | + } |
| 86 | + |
| 87 | + infos := rm.List() |
| 88 | + require.Len(t, infos, 1) |
| 89 | + assert.Equal(t, "test-svc", infos[0].Code) |
| 90 | + assert.Equal(t, "Test Service", infos[0].Name) |
| 91 | + assert.Equal(t, "1.0.0", infos[0].Version) |
| 92 | + assert.Equal(t, "test", infos[0].Namespace) |
| 93 | + assert.Equal(t, 12345, infos[0].Port) |
| 94 | + assert.Equal(t, "/tmp/test-provider", infos[0].Dir) |
| 95 | +} |
| 96 | + |
| 97 | +func TestRuntimeManager_StopAll_Good_Empty(t *testing.T) { |
| 98 | + rm := NewRuntimeManager(nil) |
| 99 | + // Should not panic with no providers. |
| 100 | + rm.StopAll() |
| 101 | + assert.Empty(t, rm.providers) |
| 102 | +} |
| 103 | + |
| 104 | +func TestRuntimeManager_StopAll_Good_WithProcess(t *testing.T) { |
| 105 | + // Start a real process so we can test graceful stop. |
| 106 | + cmd := exec.CommandContext(context.Background(), "sleep", "60") |
| 107 | + require.NoError(t, cmd.Start()) |
| 108 | + |
| 109 | + rm := NewRuntimeManager(nil) |
| 110 | + rm.providers = []*RuntimeProvider{ |
| 111 | + { |
| 112 | + Manifest: &manifest.Manifest{Code: "sleeper"}, |
| 113 | + Cmd: cmd, |
| 114 | + }, |
| 115 | + } |
| 116 | + |
| 117 | + rm.StopAll() |
| 118 | + assert.Nil(t, rm.providers) |
| 119 | +} |
| 120 | + |
| 121 | +func TestRuntimeManager_StartAll_Good_EmptyDir(t *testing.T) { |
| 122 | + rm := NewRuntimeManager(nil) |
| 123 | + // StartAll with a non-existent providers dir should return an error |
| 124 | + // because the default dir won't have providers (at most it logs and returns nil). |
| 125 | + err := rm.StartAll(context.Background()) |
| 126 | + // Depending on whether ~/.core/providers/ exists, this either returns |
| 127 | + // nil (no providers found) or an error (dir doesn't exist). |
| 128 | + // Either outcome is acceptable — no panic. |
| 129 | + _ = err |
| 130 | +} |
0 commit comments