diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 21a8832..c194b8d 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -18,13 +18,6 @@ jobs: with: persist-credentials: false - - name: Install, Build, Test 🔧 # This runs a series of commands as if building a live version of the project - run: | - go mod tidy - go test github.com/julwrites/ScriptureBot/pkg/utils \ - github.com/julwrites/ScriptureBot/pkg/app \ - github.com/julwrites/ScriptureBot/pkg/bot - - name: gcloud Auth uses: google-github-actions/auth@v2 with: @@ -35,6 +28,15 @@ jobs: run: | gcloud info + - name: Install, Build, Test 🔧 # This runs a series of commands as if building a live version of the project + env: + GCLOUD_PROJECT_ID: ${{secrets.GCLOUD_PROJECT_ID}} + run: | + go mod tidy + go test github.com/julwrites/ScriptureBot/pkg/utils \ + github.com/julwrites/ScriptureBot/pkg/app \ + github.com/julwrites/ScriptureBot/pkg/bot + - name: Configure gcloud auth with Docker run: | gcloud auth configure-docker ${{ secrets.GCLOUD_REGION }}-docker.pkg.dev diff --git a/pkg/app/api_client_test.go b/pkg/app/api_client_test.go index 8817207..188cb01 100644 --- a/pkg/app/api_client_test.go +++ b/pkg/app/api_client_test.go @@ -7,12 +7,7 @@ import ( ) func TestSubmitQuery(t *testing.T) { - handler := newMockApiHandler() - ts := httptest.NewServer(handler) - defer ts.Close() - t.Run("Success", func(t *testing.T) { - defer setEnv("BIBLE_API_URL", ts.URL)() ResetAPIConfigCache() req := QueryRequest{Query: QueryObject{Prompt: "hello"}} @@ -21,18 +16,20 @@ func TestSubmitQuery(t *testing.T) { if err != nil { t.Errorf("Unexpected error: %v", err) } - if resp.Text != "Answer text" { - t.Errorf("Expected 'Answer text', got '%s'", resp.Text) + // In integration test mode, we expect some content but can't assert exact text + // because the live API response might vary. + if len(resp.Text) == 0 && len(resp.References) == 0 { + t.Errorf("Expected some content (text or references), got empty response") } }) t.Run("API Error", func(t *testing.T) { + handler := newMockApiHandler() + ts := httptest.NewServer(handler) + defer ts.Close() + handler.statusCode = http.StatusInternalServerError handler.rawResponse = `{"error": {"code": 500, "message": "simulated error"}}` - defer func() { // Reset handler - handler.statusCode = http.StatusOK - handler.rawResponse = "" - }() defer setEnv("BIBLE_API_URL", ts.URL)() ResetAPIConfigCache() @@ -49,8 +46,11 @@ func TestSubmitQuery(t *testing.T) { }) t.Run("Bad JSON", func(t *testing.T) { + handler := newMockApiHandler() + ts := httptest.NewServer(handler) + defer ts.Close() + handler.rawResponse = `{invalid json` - defer func() { handler.rawResponse = "" }() defer setEnv("BIBLE_API_URL", ts.URL)() ResetAPIConfigCache() diff --git a/pkg/app/ask_test.go b/pkg/app/ask_test.go index 267b2ad..82d8322 100644 --- a/pkg/app/ask_test.go +++ b/pkg/app/ask_test.go @@ -11,12 +11,7 @@ import ( ) func TestGetBibleAsk(t *testing.T) { - handler := newMockApiHandler() - ts := httptest.NewServer(handler) - defer ts.Close() - t.Run("Success", func(t *testing.T) { - defer setEnv("BIBLE_API_URL", ts.URL)() ResetAPIConfigCache() var env def.SessionData @@ -26,17 +21,17 @@ func TestGetBibleAsk(t *testing.T) { env = GetBibleAsk(env) - if !strings.Contains(env.Res.Message, "Answer text") { - t.Errorf("Expected answer text, got: %s", env.Res.Message) - } - if !strings.Contains(env.Res.Message, "Ref 1:1") { - t.Errorf("Expected reference, got: %s", env.Res.Message) + if len(env.Res.Message) == 0 { + t.Errorf("Expected answer text, got empty") } }) t.Run("Error", func(t *testing.T) { + handler := newMockApiHandler() + ts := httptest.NewServer(handler) + defer ts.Close() + handler.statusCode = http.StatusInternalServerError - defer func() { handler.statusCode = http.StatusOK }() defer setEnv("BIBLE_API_URL", ts.URL)() ResetAPIConfigCache() diff --git a/pkg/app/database_integration_test.go b/pkg/app/database_integration_test.go new file mode 100644 index 0000000..2406ef6 --- /dev/null +++ b/pkg/app/database_integration_test.go @@ -0,0 +1,50 @@ +package app + +import ( + "testing" + + "github.com/julwrites/BotPlatform/pkg/def" + "github.com/julwrites/ScriptureBot/pkg/secrets" + "github.com/julwrites/ScriptureBot/pkg/utils" +) + +func TestUserDatabaseIntegration(t *testing.T) { + // This test performs a live database operation against the configured project. + // It relies on GCLOUD_PROJECT_ID being set. + + secretsData, err := secrets.LoadSecrets() + if err != nil { + t.Logf("Warning: Could not load secrets: %v", err) + } + + projectID := secretsData.PROJECT_ID + if projectID == "" { + t.Skip("Skipping database test: GCLOUD_PROJECT_ID not set") + } + + // Use a unique ID to avoid conflict with real users + dummyID := "test-integration-user-DO-NOT-DELETE" + + var user def.UserData + user.Id = dummyID + user.Firstname = "Integration" + user.Lastname = "Test" + user.Username = "TestUser" + user.Type = "Private" + + // Create/Update user + // This exercises the connection to Datastore/Firestore + updatedUser := utils.RegisterUser(user, projectID) + + if updatedUser.Id != dummyID { + t.Errorf("Expected user ID %s, got %s", dummyID, updatedUser.Id) + } + + // Verify update capability + updatedUser.Action = "testing" + finalUser := utils.RegisterUser(updatedUser, projectID) + + if finalUser.Action != "testing" { + t.Errorf("Expected user Action 'testing', got '%s'", finalUser.Action) + } +} diff --git a/pkg/app/passage_test.go b/pkg/app/passage_test.go index 2025e38..1adf186 100644 --- a/pkg/app/passage_test.go +++ b/pkg/app/passage_test.go @@ -45,13 +45,7 @@ func TestGetPassage(t *testing.T) { } func TestGetBiblePassage(t *testing.T) { - handler := newMockApiHandler() - ts := httptest.NewServer(handler) - defer ts.Close() - t.Run("Success", func(t *testing.T) { - defer setEnv("BIBLE_API_URL", ts.URL)() - defer setEnv("BIBLE_API_KEY", "test_key")() ResetAPIConfigCache() var env def.SessionData @@ -61,14 +55,17 @@ func TestGetBiblePassage(t *testing.T) { env.User.Config = utils.SerializeUserConfig(conf) env = GetBiblePassage(env) - if env.Res.Message != `In the beginning God created the heavens and the earth\.` { + if len(env.Res.Message) < 10 { t.Errorf("Expected passage text, got '%s'", env.Res.Message) } }) t.Run("Error", func(t *testing.T) { + handler := newMockApiHandler() + ts := httptest.NewServer(handler) + defer ts.Close() + handler.statusCode = http.StatusInternalServerError - defer func() { handler.statusCode = http.StatusOK }() defer setEnv("BIBLE_API_URL", ts.URL)() defer setEnv("BIBLE_API_KEY", "test_key")() @@ -100,12 +97,11 @@ func TestGetBiblePassage(t *testing.T) { }) t.Run("Empty", func(t *testing.T) { + handler := newMockApiHandler() + ts := httptest.NewServer(handler) + defer ts.Close() + handler.verseResponse = VerseResponse{} - defer func() { - handler.verseResponse = VerseResponse{ - Verse: "
In the beginning God created the heavens and the earth.
", - } - }() defer setEnv("BIBLE_API_URL", ts.URL)() defer setEnv("BIBLE_API_KEY", "test_key")() diff --git a/pkg/secrets/secrets.go b/pkg/secrets/secrets.go index b76b86a..8d722ab 100644 --- a/pkg/secrets/secrets.go +++ b/pkg/secrets/secrets.go @@ -80,12 +80,19 @@ func LoadSecrets() (SecretsData, error) { } // Get retrieves a secret. -// If GCLOUD_PROJECT_ID is set, it exclusively fetches from Google Secret Manager. -// Otherwise, it falls back to environment variables for local development. +// It prioritizes environment variables. If not found, and GCLOUD_PROJECT_ID is set, +// it fetches from Google Secret Manager. func Get(secretName string) (string, error) { + // Check environment variables first. + // This allows overriding secrets for local development or testing. + if value, ok := os.LookupEnv(secretName); ok { + log.Printf("Loaded '%s' from environment", secretName) + return value, nil + } + projectID, isCloudRun := os.LookupEnv("GCLOUD_PROJECT_ID") if isCloudRun && projectID != "" { - // Cloud environment: Use Secret Manager exclusively. + // Cloud environment: Use Secret Manager if not found in environment. secretValue, err := getFromSecretManager(projectID, secretName) if err != nil { return "", fmt.Errorf("failed to get secret '%s' from Secret Manager: %v", secretName, err) @@ -94,12 +101,6 @@ func Get(secretName string) (string, error) { return secretValue, nil } - // Local environment: Use environment variables. - if value, ok := os.LookupEnv(secretName); ok { - log.Printf("Loaded '%s' from environment", secretName) - return value, nil - } - return "", fmt.Errorf("secret '%s' not found in environment variables", secretName) }