Skip to content

Commit

Permalink
fix: AdminService: move to admin package, add tests (#1656)
Browse files Browse the repository at this point in the history
  • Loading branch information
safeer authored Jun 5, 2024
1 parent 42d6bed commit f04a921
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package controller
package admin

import (
"context"
Expand Down
141 changes: 141 additions & 0 deletions backend/controller/admin/admin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package admin

import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"testing"

"connectrpc.com/connect"
ftlv1 "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1"
cf "github.com/TBD54566975/ftl/common/configuration"
"github.com/TBD54566975/ftl/internal/log"
"github.com/alecthomas/assert/v2"
"github.com/alecthomas/types/optional"
)

func TestAdminService(t *testing.T) {
config := tempConfigPath(t, "testdata/ftl-project.toml", "admin")
ctx := log.ContextWithNewDefaultLogger(context.Background())

cm, err := cf.NewConfigurationManager(ctx, cf.ProjectConfigResolver[cf.Configuration]{Config: []string{config}})
assert.NoError(t, err)

sm, err := cf.New(ctx,
cf.ProjectConfigResolver[cf.Secrets]{Config: []string{config}},
[]cf.Provider[cf.Secrets]{
cf.EnvarProvider[cf.Secrets]{},
cf.InlineProvider[cf.Secrets]{},
})
assert.NoError(t, err)
admin := NewAdminService(cm, sm)
assert.NotZero(t, admin)

expectedEnvarValue, err := json.MarshalIndent(map[string]string{"bar": "barfoo"}, "", " ")
assert.NoError(t, err)

testAdminConfigs(t, ctx, "FTL_CONFIG_YmFy", admin, []expectedEntry{
{Ref: cf.Ref{Name: "bar"}, Value: string(expectedEnvarValue)},
{Ref: cf.Ref{Name: "foo"}, Value: `"foobar"`},
{Ref: cf.Ref{Name: "mutable"}, Value: `"helloworld"`},
{Ref: cf.Ref{Module: optional.Some[string]("echo"), Name: "default"}, Value: `"anonymous"`},
})

testAdminSecrets(t, ctx, "FTL_SECRET_YmFy", admin, []expectedEntry{
{Ref: cf.Ref{Name: "bar"}, Value: string(expectedEnvarValue)},
{Ref: cf.Ref{Name: "foo"}, Value: `"foobarsecret"`},
})
}

type expectedEntry struct {
Ref cf.Ref
Value string
}

func tempConfigPath(t *testing.T, existingPath string, prefix string) string {
t.Helper()
config := filepath.Join(t.TempDir(), fmt.Sprintf("%s-ftl-project.toml", prefix))
var existing []byte
var err error
if existingPath == "" {
existing = []byte{}
} else {
existing, err = os.ReadFile(existingPath)
assert.NoError(t, err)
}
err = os.WriteFile(config, existing, 0600)
assert.NoError(t, err)
return config
}

// nolint
func testAdminConfigs(
t *testing.T,
ctx context.Context,
envarName string,
admin *AdminService,
entries []expectedEntry,
) {
t.Helper()
t.Setenv(envarName, "eyJiYXIiOiJiYXJmb28ifQ") // bar={"bar": "barfoo"}

module := ""
includeValues := true
resp, err := admin.ConfigList(ctx, connect.NewRequest(&ftlv1.ListConfigRequest{
Module: &module,
IncludeValues: &includeValues,
}))
assert.NoError(t, err)
assert.NotZero(t, resp)

configs := resp.Msg.Configs
assert.Equal(t, len(entries), len(configs))

for _, entry := range entries {
module := entry.Ref.Module.Default("")
ref := &ftlv1.ConfigRef{
Module: &module,
Name: entry.Ref.Name,
}
resp, err := admin.ConfigGet(ctx, connect.NewRequest(&ftlv1.GetConfigRequest{Ref: ref}))
assert.NoError(t, err)
assert.Equal(t, entry.Value, string(resp.Msg.Value))
}
}

// nolint
func testAdminSecrets(
t *testing.T,
ctx context.Context,
envarName string,
admin *AdminService,
entries []expectedEntry,
) {
t.Helper()
t.Setenv(envarName, "eyJiYXIiOiJiYXJmb28ifQ") // bar={"bar": "barfoo"}

module := ""
includeValues := true
resp, err := admin.SecretsList(ctx, connect.NewRequest(&ftlv1.ListSecretsRequest{
Module: &module,
IncludeValues: &includeValues,
}))
assert.NoError(t, err)
assert.NotZero(t, resp)

secrets := resp.Msg.Secrets
assert.Equal(t, len(entries), len(secrets))

for _, entry := range entries {
module := entry.Ref.Module.Default("")
ref := &ftlv1.ConfigRef{
Module: &module,
Name: entry.Ref.Name,
}
resp, err := admin.SecretGet(ctx, connect.NewRequest(&ftlv1.GetSecretRequest{Ref: ref}))
assert.NoError(t, err)
assert.Equal(t, entry.Value, string(resp.Msg.Value))
}
}
14 changes: 14 additions & 0 deletions backend/controller/admin/testdata/ftl-project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[global]
[global.secrets]
bar = "envar://baza"
foo = "inline://ImZvb2JhcnNlY3JldCI"

[global.configuration]
bar = "envar://bazb"
foo = "inline://ImZvb2JhciI"
mutable = "inline://ImhlbGxvd29ybGQi"

[modules]
[modules.echo]
[modules.echo.configuration]
default = "inline://ImFub255bW91cyI"
3 changes: 2 additions & 1 deletion backend/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"google.golang.org/protobuf/types/known/timestamppb"

"github.com/TBD54566975/ftl"
"github.com/TBD54566975/ftl/backend/controller/admin"
"github.com/TBD54566975/ftl/backend/controller/cronjobs"
"github.com/TBD54566975/ftl/backend/controller/dal"
"github.com/TBD54566975/ftl/backend/controller/ingress"
Expand Down Expand Up @@ -134,7 +135,7 @@ func Start(ctx context.Context, config Config, runnerScaling scaling.RunnerScali
cm := cf.ConfigFromContext(ctx)
sm := cf.SecretsFromContext(ctx)

admin := NewAdminService(cm, sm)
admin := admin.NewAdminService(cm, sm)
console := NewConsoleService(dal)

ingressHandler := http.Handler(svc)
Expand Down
15 changes: 8 additions & 7 deletions common/projectconfig/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,21 @@ import (
)

func TestCmdsCreateProjectTomlFilesIfNonexistent(t *testing.T) {
cwd, err := os.Getwd()
assert.NoError(t, err)

fileName := "ftl-project-nonexistent.toml"
configPath := filepath.Join(cwd, "testdata", "go", fileName)

in.Run(t, fileName,
in.CopyModule("echo"),
in.Exec("ftl", "config", "set", "key", "--inline", "value"),
in.FileContains(configPath, "key"),
in.FileContains(configPath, "InZhbHVlIg"),
)

// The FTL config path is special-cased to use the testdata directory
// instead of tmpDir.
configPath := filepath.Join("testdata", "go", fileName)

fmt.Printf("Checking that %s exists\n", configPath)
_, err := os.Stat(configPath)
assert.NoError(t, err)

// instead of tmpDir, so we need to clean it up manually.
fmt.Printf("Removing config file %s\n", configPath)
err = os.Remove(configPath)
assert.NoError(t, err)
Expand Down

0 comments on commit f04a921

Please sign in to comment.