package runtime_test import ( "context" "encoding/base64" "encoding/json" "net/http" "net/http/httptest" "net/url" "os" "path/filepath" "testing" "time" "git.sendico.io/tech/sxchnge/product/app/api" "git.sendico.io/tech/sxchnge/product/app/profile" sharedruntime "git.sendico.io/tech/sxchnge/product/app/runtime" "git.sendico.io/tech/sxchnge/product/providers/sendico" "git.sendico.io/tech/sxchnge/shared/database" sharedmodel "git.sendico.io/tech/sxchnge/shared/model" "github.com/go-chi/chi/v5" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go/modules/mongodb" "go.uber.org/zap" "gopkg.in/yaml.v3" ) func TestProfileStartsOnEmptyDatabase(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() container, err := mongodb.Run(ctx, "mongo:latest", mongodb.WithReplicaSet("rs")) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, container.Terminate(context.Background())) }) uri, err := container.ConnectionString(ctx) require.NoError(t, err) endpoint, err := url.Parse(uri) require.NoError(t, err) query := endpoint.Query() query.Set("directConnection", "true") endpoint.RawQuery = query.Encode() uri = endpoint.String() factory, err := db.NewConnection(zap.NewNop(), &db.Config{Driver: db.Mongo, Settings: sharedmodel.SettingsT{"uri": uri, "database": "sxchnge_runtime"}}) require.NoError(t, err) t.Cleanup(factory.CloseConnection) data, err := os.ReadFile("../../config.example.yml") require.NoError(t, err) var example struct { API api.Config `yaml:"api"` } require.NoError(t, yaml.Unmarshal(data, &example)) t.Setenv("SXCHNGE_DOMAIN", "localhost") t.Setenv("SXCHNGE_API_PROTOCOL", "http") t.Setenv("SXCHNGE_API_ENDPOINT", "/api/v1") t.Setenv("SXCHNGE_JWT_SECRET", "test-only-signing-key-at-least-32-bytes") example.API.Notifications.CAFile = "" // This startup test makes no notification RPCs. root, routes := chi.NewRouter(), chi.NewRouter() runtime, err := sharedruntime.CreateAPI(ctx, zap.NewNop(), &example.API, factory, root, routes, false, profile.Runtime()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, runtime.Finish(context.Background())) }) root.Mount("/", routes) result := httptest.NewRecorder() root.ServeHTTP(result, httptest.NewRequest(http.MethodGet, "/api/v1/health", nil)) require.Equal(t, http.StatusOK, result.Code) // Runtime auth routes are installed even with zero customers and no seed. result = httptest.NewRecorder() root.ServeHTTP(result, httptest.NewRequest(http.MethodPost, "/api/v1/accounts/login", nil)) require.Equal(t, http.StatusBadRequest, result.Code) // Enabling the adapter validates credentials, composes once, and does not // register any provider resource until a customer starts sign-up. const source = "507f1f77bcf86cd799439011" claims, err := json.Marshal(map[string]any{"id": source, "exp": time.Now().Add(time.Hour).Unix()}) require.NoError(t, err) file := filepath.Join(t.TempDir(), "credential") require.NoError(t, os.WriteFile(file, []byte("header."+base64.RawURLEncoding.EncodeToString(claims)+".signature"), 0600)) example.API.Sendico = &sendico.Config{APIURL: "https://api.example/api/v1", OrganizationID: source, SourceID: source, TokenFile: file} dependencies, finish, err := sharedruntime.OpenDependencies(ctx, zap.NewNop(), &example.API, factory) require.NoError(t, err) require.NotNil(t, dependencies.Auth.Facts) require.NoError(t, finish(ctx)) example.API.Sendico.TokenFile = "" _, _, err = sharedruntime.OpenDependencies(ctx, zap.NewNop(), &example.API, factory) require.Error(t, err) example.API.Notifications = nil _, _, err = sharedruntime.OpenDependencies(ctx, zap.NewNop(), &example.API, factory) require.Error(t, err) }