Skip to content

Commit cee2c5b

Browse files
authored
chore: unit tests for pg config (#4830)
1 parent 9b2f6f2 commit cee2c5b

File tree

6 files changed

+298
-33
lines changed

6 files changed

+298
-33
lines changed

internal/postgresConfig/delete/delete.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,15 @@ func Run(ctx context.Context, projectRef string, configKeys []string, noRestart
3535

3636
resp, err := utils.GetSupabase().V1UpdatePostgresConfigWithBodyWithResponse(ctx, projectRef, "application/json", bytes.NewReader(bts))
3737
if err != nil {
38-
return errors.Errorf("failed to update config overrides: %w", err)
39-
}
40-
if resp.JSON200 == nil {
41-
if resp.StatusCode() == 400 {
42-
return errors.Errorf("failed to update config overrides: %s (%s). This usually indicates that an unsupported or invalid config override was attempted. Please refer to https://supabase.com/docs/guides/platform/custom-postgres-config", resp.Status(), string(resp.Body))
43-
}
44-
return errors.Errorf("failed to update config overrides: %s (%s)", resp.Status(), string(resp.Body))
38+
return errors.Errorf("failed to delete config overrides: %w", err)
39+
} else if resp.JSON200 == nil {
40+
return errors.Errorf("unexpected delete config overrides status %d: %s", resp.StatusCode(), string(resp.Body))
4541
}
4642

47-
return get.Run(ctx, projectRef, fsys)
43+
var config map[string]any
44+
err = json.Unmarshal(resp.Body, &config)
45+
if err != nil {
46+
return errors.Errorf("failed to unmarshal delete response: %w", err)
47+
}
48+
return get.PrintOutPostgresConfigOverrides(config)
4849
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package delete
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"testing"
7+
8+
"github.com/go-errors/errors"
9+
"github.com/h2non/gock"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/supabase/cli/internal/testing/apitest"
12+
"github.com/supabase/cli/internal/testing/fstest"
13+
"github.com/supabase/cli/internal/utils"
14+
"github.com/supabase/cli/internal/utils/flags"
15+
"github.com/supabase/cli/pkg/api"
16+
"github.com/supabase/cli/pkg/cast"
17+
)
18+
19+
func TestDeleteConfig(t *testing.T) {
20+
flags.ProjectRef = apitest.RandomProjectRef()
21+
22+
t.Run("deletes postgres config", func(t *testing.T) {
23+
t.Cleanup(fstest.MockStdout(t, `
24+
25+
Parameter | Value
26+
-----------|-------
27+
28+
`))
29+
t.Cleanup(apitest.MockPlatformAPI(t))
30+
// Setup mock api
31+
gock.New(utils.DefaultApiHost).
32+
Get("v1/projects/" + flags.ProjectRef + "/config/database/postgres").
33+
Reply(http.StatusOK).
34+
JSON(api.PostgresConfigResponse{
35+
MaxConnections: cast.Ptr(100),
36+
})
37+
gock.New(utils.DefaultApiHost).
38+
Put("v1/projects/" + flags.ProjectRef + "/config/database/postgres").
39+
Reply(http.StatusOK).
40+
JSON(api.PostgresConfigResponse{})
41+
// Run test
42+
err := Run(context.Background(), flags.ProjectRef, []string{"max_connections"}, true, nil)
43+
assert.NoError(t, err)
44+
})
45+
46+
t.Run("throws error on missing project", func(t *testing.T) {
47+
errNetwork := errors.New("network error")
48+
t.Cleanup(apitest.MockPlatformAPI(t))
49+
// Setup mock api
50+
gock.New(utils.DefaultApiHost).
51+
Get("/v1/projects/" + flags.ProjectRef + "/config/database/postgres").
52+
ReplyError(errNetwork)
53+
// Run test
54+
err := Run(context.Background(), flags.ProjectRef, []string{}, false, nil)
55+
assert.ErrorIs(t, err, errNetwork)
56+
})
57+
58+
t.Run("throws error on network error", func(t *testing.T) {
59+
errNetwork := errors.New("network error")
60+
t.Cleanup(apitest.MockPlatformAPI(t))
61+
// Setup mock api
62+
gock.New(utils.DefaultApiHost).
63+
Get("v1/projects/" + flags.ProjectRef + "/config/database/postgres").
64+
Reply(http.StatusOK).
65+
JSON(api.PostgresConfigResponse{
66+
MaxConnections: cast.Ptr(100),
67+
})
68+
gock.New(utils.DefaultApiHost).
69+
Put("/v1/projects/" + flags.ProjectRef + "/config/database/postgres").
70+
ReplyError(errNetwork)
71+
// Run test
72+
err := Run(context.Background(), flags.ProjectRef, []string{}, false, nil)
73+
assert.ErrorIs(t, err, errNetwork)
74+
})
75+
76+
t.Run("throws error on service unavailable", func(t *testing.T) {
77+
utils.OutputFormat.Value = utils.OutputEnv
78+
t.Cleanup(func() { utils.OutputFormat.Value = utils.OutputPretty })
79+
t.Cleanup(apitest.MockPlatformAPI(t))
80+
// Setup mock api
81+
gock.New(utils.DefaultApiHost).
82+
Get("v1/projects/" + flags.ProjectRef + "/config/database/postgres").
83+
Reply(http.StatusOK).
84+
JSON(api.PostgresConfigResponse{
85+
MaxConnections: cast.Ptr(100),
86+
})
87+
gock.New(utils.DefaultApiHost).
88+
Put("/v1/projects/" + flags.ProjectRef + "/config/database/postgres").
89+
Reply(http.StatusServiceUnavailable)
90+
// Run test
91+
err := Run(context.Background(), flags.ProjectRef, []string{}, false, nil)
92+
assert.ErrorContains(t, err, "unexpected delete config overrides status 503:")
93+
})
94+
}

internal/postgresConfig/get/get.go

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7-
"io"
87
"os"
98
"strings"
109

@@ -14,23 +13,18 @@ import (
1413
)
1514

1615
func Run(ctx context.Context, projectRef string, fsys afero.Fs) error {
17-
// 1. get current config
1816
config, err := GetCurrentPostgresConfig(ctx, projectRef)
1917
if err != nil {
2018
return err
2119
}
22-
err = PrintOutPostgresConfigOverrides(config)
23-
if err != nil {
24-
return err
25-
}
26-
return nil
20+
return PrintOutPostgresConfigOverrides(config)
2721
}
2822

2923
func PrintOutPostgresConfigOverrides(config map[string]any) error {
3024
if utils.OutputFormat.Value != utils.OutputPretty {
3125
return utils.EncodeOutput(utils.OutputFormat.Value, os.Stdout, config)
3226
}
33-
fmt.Println("- Custom Postgres Config -")
27+
fmt.Fprintln(os.Stderr, "- Custom Postgres Config -")
3428
markdownTable := []string{
3529
"|Parameter|Value|\n|-|-|\n",
3630
}
@@ -43,26 +37,21 @@ func PrintOutPostgresConfigOverrides(config map[string]any) error {
4337
if err := utils.RenderTable(strings.Join(markdownTable, "")); err != nil {
4438
return err
4539
}
46-
fmt.Println("- End of Custom Postgres Config -")
40+
fmt.Fprintln(os.Stderr, "- End of Custom Postgres Config -")
4741
return nil
4842
}
4943

5044
func GetCurrentPostgresConfig(ctx context.Context, projectRef string) (map[string]any, error) {
51-
resp, err := utils.GetSupabase().V1GetPostgresConfig(ctx, projectRef)
45+
resp, err := utils.GetSupabase().V1GetPostgresConfigWithResponse(ctx, projectRef)
5246
if err != nil {
5347
return nil, errors.Errorf("failed to retrieve Postgres config overrides: %w", err)
54-
}
55-
if resp.StatusCode != 200 {
56-
return nil, errors.Errorf("error in retrieving Postgres config overrides: %s", resp.Status)
57-
}
58-
contents, err := io.ReadAll(resp.Body)
59-
if err != nil {
60-
return nil, errors.Errorf("failed to read response body: %w", err)
48+
} else if resp.JSON200 == nil {
49+
return nil, errors.Errorf("unexpected config overrides status %d: %s", resp.StatusCode(), string(resp.Body))
6150
}
6251
var config map[string]any
63-
err = json.Unmarshal(contents, &config)
52+
err = json.Unmarshal(resp.Body, &config)
6453
if err != nil {
65-
return nil, errors.Errorf("failed to unmarshal response body: %w. Contents were %s", err, contents)
54+
return nil, errors.Errorf("failed to unmarshal response body: %w", err)
6655
}
6756
return config, nil
6857
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package get
2+
3+
import (
4+
"context"
5+
"errors"
6+
"net/http"
7+
"testing"
8+
9+
"github.com/h2non/gock"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/supabase/cli/internal/testing/apitest"
12+
"github.com/supabase/cli/internal/testing/fstest"
13+
"github.com/supabase/cli/internal/utils"
14+
"github.com/supabase/cli/internal/utils/flags"
15+
"github.com/supabase/cli/pkg/api"
16+
"github.com/supabase/cli/pkg/cast"
17+
)
18+
19+
func TestPostgresConfig(t *testing.T) {
20+
flags.ProjectRef = apitest.RandomProjectRef()
21+
22+
t.Run("get postgres config", func(t *testing.T) {
23+
t.Cleanup(fstest.MockStdout(t, `
24+
25+
Parameter | Value
26+
-----------------|-------
27+
max_connections | 100
28+
29+
`))
30+
t.Cleanup(apitest.MockPlatformAPI(t))
31+
// Setup mock api
32+
gock.New(utils.DefaultApiHost).
33+
Get("v1/projects/" + flags.ProjectRef + "/config/database/postgres").
34+
Reply(http.StatusOK).
35+
JSON(api.PostgresConfigResponse{
36+
MaxConnections: cast.Ptr(100),
37+
})
38+
// Run test
39+
err := Run(context.Background(), flags.ProjectRef, nil)
40+
assert.NoError(t, err)
41+
})
42+
43+
t.Run("encodes toml output", func(t *testing.T) {
44+
utils.OutputFormat.Value = utils.OutputToml
45+
t.Cleanup(func() { utils.OutputFormat.Value = utils.OutputPretty })
46+
t.Cleanup(fstest.MockStdout(t, `max_connections = 100.0
47+
`))
48+
t.Cleanup(apitest.MockPlatformAPI(t))
49+
// Setup mock api
50+
gock.New(utils.DefaultApiHost).
51+
Get("v1/projects/" + flags.ProjectRef + "/config/database/postgres").
52+
Reply(http.StatusOK).
53+
JSON(api.PostgresConfigResponse{
54+
MaxConnections: cast.Ptr(100),
55+
})
56+
// Run test
57+
err := Run(context.Background(), flags.ProjectRef, nil)
58+
assert.NoError(t, err)
59+
})
60+
61+
t.Run("throws error on network error", func(t *testing.T) {
62+
errNetwork := errors.New("network error")
63+
t.Cleanup(apitest.MockPlatformAPI(t))
64+
// Setup mock api
65+
gock.New(utils.DefaultApiHost).
66+
Get("/v1/projects/" + flags.ProjectRef + "/config/database/postgres").
67+
ReplyError(errNetwork)
68+
// Run test
69+
err := Run(context.Background(), flags.ProjectRef, nil)
70+
assert.ErrorIs(t, err, errNetwork)
71+
})
72+
73+
t.Run("throws error on service unavailable", func(t *testing.T) {
74+
utils.OutputFormat.Value = utils.OutputEnv
75+
t.Cleanup(func() { utils.OutputFormat.Value = utils.OutputPretty })
76+
t.Cleanup(apitest.MockPlatformAPI(t))
77+
// Setup mock api
78+
gock.New(utils.DefaultApiHost).
79+
Get("/v1/projects/" + flags.ProjectRef + "/config/database/postgres").
80+
Reply(http.StatusServiceUnavailable)
81+
// Run test
82+
err := Run(context.Background(), flags.ProjectRef, nil)
83+
assert.ErrorContains(t, err, "unexpected config overrides status 503:")
84+
})
85+
}

internal/postgresConfig/update/update.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,14 @@ func Run(ctx context.Context, projectRef string, values []string, replaceOverrid
6767
resp, err := utils.GetSupabase().V1UpdatePostgresConfigWithBodyWithResponse(ctx, projectRef, "application/json", bytes.NewReader(bts))
6868
if err != nil {
6969
return errors.Errorf("failed to update config overrides: %w", err)
70+
} else if resp.JSON200 == nil {
71+
return errors.Errorf("unexpected update config overrides status %d: %s", resp.StatusCode(), string(resp.Body))
7072
}
71-
if resp.JSON200 == nil {
72-
if resp.StatusCode() == 400 {
73-
return errors.Errorf("failed to update config overrides: %s (%s). This usually indicates that an unsupported or invalid config override was attempted. Please refer to https://supabase.com/docs/guides/platform/custom-postgres-config", resp.Status(), string(resp.Body))
74-
}
75-
return errors.Errorf("failed to update config overrides: %s (%s)", resp.Status(), string(resp.Body))
73+
var config map[string]any
74+
err = json.Unmarshal(resp.Body, &config)
75+
if err != nil {
76+
return errors.Errorf("failed to unmarshal update response: %w", err)
7677
}
78+
return get.PrintOutPostgresConfigOverrides(config)
7779
}
78-
return get.Run(ctx, projectRef, fsys)
7980
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package update
2+
3+
import (
4+
"context"
5+
"errors"
6+
"net/http"
7+
"testing"
8+
9+
"github.com/h2non/gock"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/supabase/cli/internal/testing/apitest"
12+
"github.com/supabase/cli/internal/testing/fstest"
13+
"github.com/supabase/cli/internal/utils"
14+
"github.com/supabase/cli/internal/utils/flags"
15+
"github.com/supabase/cli/pkg/api"
16+
"github.com/supabase/cli/pkg/cast"
17+
)
18+
19+
func TestUpdatePostgresConfig(t *testing.T) {
20+
flags.ProjectRef = apitest.RandomProjectRef()
21+
22+
t.Run("updates postgres config", func(t *testing.T) {
23+
t.Cleanup(fstest.MockStdout(t, `
24+
25+
Parameter | Value
26+
-----------------|-------
27+
max_connections | 100
28+
29+
`))
30+
t.Cleanup(apitest.MockPlatformAPI(t))
31+
// Setup mock api
32+
gock.New(utils.DefaultApiHost).
33+
Put("v1/projects/" + flags.ProjectRef + "/config/database/postgres").
34+
Reply(http.StatusOK).
35+
JSON(api.PostgresConfigResponse{
36+
MaxConnections: cast.Ptr(100),
37+
})
38+
// Run test
39+
err := Run(context.Background(), flags.ProjectRef, []string{
40+
"max_connections=100",
41+
"track_commit_timestamp=true",
42+
"statement_timeout=600",
43+
"wal_keep_size=1GB",
44+
}, true, true, nil)
45+
assert.NoError(t, err)
46+
})
47+
48+
t.Run("throws error on missing key", func(t *testing.T) {
49+
err := Run(context.Background(), flags.ProjectRef, []string{"value"}, true, true, nil)
50+
assert.ErrorContains(t, err, "expected config value in key:value format")
51+
})
52+
53+
t.Run("throws error on missing project", func(t *testing.T) {
54+
errNetwork := errors.New("network error")
55+
t.Cleanup(apitest.MockPlatformAPI(t))
56+
// Setup mock api
57+
gock.New(utils.DefaultApiHost).
58+
Get("v1/projects/" + flags.ProjectRef + "/config/database/postgres").
59+
ReplyError(errNetwork)
60+
// Run test
61+
err := Run(context.Background(), flags.ProjectRef, []string{}, false, false, nil)
62+
assert.ErrorIs(t, err, errNetwork)
63+
})
64+
65+
t.Run("throws error on network error", func(t *testing.T) {
66+
errNetwork := errors.New("network error")
67+
t.Cleanup(apitest.MockPlatformAPI(t))
68+
// Setup mock api
69+
gock.New(utils.DefaultApiHost).
70+
Get("v1/projects/" + flags.ProjectRef + "/config/database/postgres").
71+
Reply(http.StatusOK).
72+
JSON(api.PostgresConfigResponse{
73+
MaxConnections: cast.Ptr(100),
74+
})
75+
gock.New(utils.DefaultApiHost).
76+
Put("/v1/projects/" + flags.ProjectRef + "/config/database/postgres").
77+
ReplyError(errNetwork)
78+
// Run test
79+
err := Run(context.Background(), flags.ProjectRef, []string{}, false, false, nil)
80+
assert.ErrorIs(t, err, errNetwork)
81+
})
82+
83+
t.Run("throws error on service unavailable", func(t *testing.T) {
84+
utils.OutputFormat.Value = utils.OutputEnv
85+
t.Cleanup(func() { utils.OutputFormat.Value = utils.OutputPretty })
86+
t.Cleanup(apitest.MockPlatformAPI(t))
87+
// Setup mock api
88+
gock.New(utils.DefaultApiHost).
89+
Put("/v1/projects/" + flags.ProjectRef + "/config/database/postgres").
90+
Reply(http.StatusServiceUnavailable)
91+
// Run test
92+
err := Run(context.Background(), flags.ProjectRef, []string{}, true, true, nil)
93+
assert.ErrorContains(t, err, "unexpected update config overrides status 503:")
94+
})
95+
}

0 commit comments

Comments
 (0)