github.com/Redstoneguy129/cli@v0.0.0-20230211220159-15dca4e91917/internal/status/status_test.go (about) 1 package status 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "io" 8 "net/http" 9 "os" 10 "strings" 11 "testing" 12 13 "github.com/Redstoneguy129/cli/internal/testing/apitest" 14 "github.com/Redstoneguy129/cli/internal/utils" 15 "github.com/docker/docker/api/types" 16 "github.com/spf13/afero" 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 "gopkg.in/h2non/gock.v1" 20 ) 21 22 func TestStatusCommand(t *testing.T) { 23 t.Run("shows service status", func(t *testing.T) { 24 services := []string{ 25 "supabase_db_", 26 "supabase_kong_", 27 "supabase_auth_", 28 "supabase_inbucket_", 29 "realtime-dev.supabase_realtime_", 30 "supabase_rest_", 31 "supabase_storage_", 32 "storage_imgproxy_", 33 "supabase_pg_meta_", 34 "supabase_studio_", 35 } 36 // Setup in-memory fs 37 fsys := afero.NewMemMapFs() 38 require.NoError(t, utils.WriteConfig(fsys, false)) 39 // Setup mock docker 40 require.NoError(t, apitest.MockDocker(utils.Docker)) 41 defer gock.OffAll() 42 for _, container := range services { 43 gock.New(utils.Docker.DaemonHost()). 44 Get("/v" + utils.Docker.ClientVersion() + "/containers/" + container). 45 Reply(http.StatusOK). 46 JSON(types.ContainerJSON{ContainerJSONBase: &types.ContainerJSONBase{ 47 State: &types.ContainerState{Running: true}, 48 }}) 49 } 50 // Run test 51 assert.NoError(t, Run(context.Background(), CustomName{}, OutputPretty, fsys)) 52 // Check error 53 assert.Empty(t, apitest.ListUnmatchedRequests()) 54 }) 55 56 t.Run("throws error on missing config", func(t *testing.T) { 57 err := Run(context.Background(), CustomName{}, OutputPretty, afero.NewMemMapFs()) 58 assert.ErrorIs(t, err, os.ErrNotExist) 59 }) 60 61 t.Run("throws error on invalid config", func(t *testing.T) { 62 // Setup in-memory fs 63 fsys := afero.NewMemMapFs() 64 require.NoError(t, afero.WriteFile(fsys, utils.ConfigPath, []byte("malformed"), 0644)) 65 // Run test 66 err := Run(context.Background(), CustomName{}, OutputPretty, fsys) 67 // Check error 68 assert.ErrorContains(t, err, "toml: line 0: unexpected EOF; expected key separator '='") 69 }) 70 71 t.Run("throws error on missing docker", func(t *testing.T) { 72 // Setup in-memory fs 73 fsys := afero.NewMemMapFs() 74 require.NoError(t, utils.WriteConfig(fsys, false)) 75 // Setup mock docker 76 require.NoError(t, apitest.MockDocker(utils.Docker)) 77 defer gock.OffAll() 78 gock.New(utils.Docker.DaemonHost()). 79 Get("/v" + utils.Docker.ClientVersion() + "/containers/supabase_db_"). 80 ReplyError(errors.New("network error")) 81 // Run test 82 err := Run(context.Background(), CustomName{}, OutputPretty, fsys) 83 // Check error 84 assert.ErrorContains(t, err, "network error") 85 assert.Empty(t, apitest.ListUnmatchedRequests()) 86 }) 87 } 88 89 func TestServiceHealth(t *testing.T) { 90 services := []string{"supabase_db", "supabase_auth"} 91 92 t.Run("checks all services", func(t *testing.T) { 93 // Setup mock docker 94 require.NoError(t, apitest.MockDocker(utils.Docker)) 95 defer gock.OffAll() 96 gock.New(utils.Docker.DaemonHost()). 97 Get("/v" + utils.Docker.ClientVersion() + "/containers/" + services[0] + "/json"). 98 Reply(http.StatusOK). 99 JSON(types.ContainerJSON{ContainerJSONBase: &types.ContainerJSONBase{ 100 State: &types.ContainerState{ 101 Running: true, 102 Health: &types.Health{Status: "Unhealthy"}, 103 }, 104 }}) 105 gock.New(utils.Docker.DaemonHost()). 106 Get("/v" + utils.Docker.ClientVersion() + "/containers/" + services[1] + "/json"). 107 Reply(http.StatusOK). 108 JSON(types.ContainerJSON{ContainerJSONBase: &types.ContainerJSONBase{ 109 State: &types.ContainerState{Status: "exited"}, 110 }}) 111 // Run test 112 var stderr bytes.Buffer 113 stopped := checkServiceHealth(context.Background(), services, &stderr) 114 // Check error 115 assert.Empty(t, stopped) 116 lines := strings.Split(strings.TrimSpace(stderr.String()), "\n") 117 assert.ElementsMatch(t, []string{ 118 "supabase_db container is not ready: Unhealthy", 119 "supabase_auth container is not running: exited", 120 }, lines) 121 assert.Empty(t, apitest.ListUnmatchedRequests()) 122 }) 123 124 t.Run("throws error on missing container", func(t *testing.T) { 125 // Setup in-memory fs 126 fsys := afero.NewMemMapFs() 127 require.NoError(t, utils.WriteConfig(fsys, false)) 128 // Setup mock docker 129 require.NoError(t, apitest.MockDocker(utils.Docker)) 130 defer gock.OffAll() 131 for _, name := range services { 132 gock.New(utils.Docker.DaemonHost()). 133 Get("/v" + utils.Docker.ClientVersion() + "/containers/" + name + "/json"). 134 Reply(http.StatusNotFound) 135 } 136 // Run test 137 stopped := checkServiceHealth(context.Background(), services, io.Discard) 138 // Check error 139 assert.ElementsMatch(t, services, stopped) 140 assert.Empty(t, apitest.ListUnmatchedRequests()) 141 }) 142 } 143 144 func TestPrintStatus(t *testing.T) { 145 utils.Config.Db.Port = 0 146 exclude := []string{ 147 utils.ShortContainerImageName(utils.PostgrestImage), 148 utils.ShortContainerImageName(utils.StudioImage), 149 utils.GotrueId, 150 utils.InbucketId, 151 } 152 153 t.Run("outputs env var", func(t *testing.T) { 154 // Run test 155 var stdout bytes.Buffer 156 assert.NoError(t, printStatus(CustomName{DbURL: "DB_URL"}, OutputEnv, &stdout, exclude...)) 157 // Check error 158 assert.Equal(t, "DB_URL=\"postgresql://postgres:postgres@"+utils.Config.Hostname+":0/postgres\"\n", stdout.String()) 159 }) 160 161 t.Run("outputs json object", func(t *testing.T) { 162 // Run test 163 var stdout bytes.Buffer 164 assert.NoError(t, printStatus(CustomName{DbURL: "DB_URL"}, OutputJson, &stdout, exclude...)) 165 // Check error 166 assert.Equal(t, "{\"DB_URL\":\"postgresql://postgres:postgres@"+utils.Config.Hostname+":0/postgres\"}\n", stdout.String()) 167 }) 168 169 t.Run("outputs yaml properties", func(t *testing.T) { 170 // Run test 171 var stdout bytes.Buffer 172 assert.NoError(t, printStatus(CustomName{DbURL: "DB_URL"}, OutputYaml, &stdout, exclude...)) 173 // Check error 174 assert.Equal(t, "DB_URL: postgresql://postgres:postgres@"+utils.Config.Hostname+":0/postgres\n", stdout.String()) 175 }) 176 177 t.Run("outputs toml fields", func(t *testing.T) { 178 // Run test 179 var stdout bytes.Buffer 180 assert.NoError(t, printStatus(CustomName{DbURL: "DB_URL"}, OutputToml, &stdout, exclude...)) 181 // Check error 182 assert.Equal(t, "DB_URL = \"postgresql://postgres:postgres@"+utils.Config.Hostname+":0/postgres\"\n", stdout.String()) 183 }) 184 }