diff --git a/test/e2e/operator-walkthroughs/discourse_test.go b/test/e2e/operator-walkthroughs/discourse_test.go index e9ab2b0d..85e5c0ad 100644 --- a/test/e2e/operator-walkthroughs/discourse_test.go +++ b/test/e2e/operator-walkthroughs/discourse_test.go @@ -43,11 +43,9 @@ const walkthroughGroup = "walkthrough-members" // // The probe itself is the shared one in helpers_test.go, which FedWiki's // guard also binds; only the key and the operator-facing remedy differ. -// Leaves the page on the settings surface; callers must navigate onward -// themselves. -func skipUnlessForumReachable(t *testing.T, page *rod.Page, base string) { +func skipUnlessForumReachable(t *testing.T) { t.Helper() - skipUnlessIntegrationEndpointReachable(t, page, base, "discourse", "discourse-base-url", + skipUnlessIntegrationEndpointReachable(t, "discourse", "discourse-base-url", "start the discourse compose profile or the fakeserver (see this file's header)") } @@ -95,16 +93,13 @@ func submitMappingForm(page *rod.Page, groupName string) { func TestDiscourseMappingWalkthrough(t *testing.T) { defer browsertest.Recover(t) - page, base := browsertest.OpenOperator(t, "/operator/integrations/discourse") + page, _ := browsertest.OpenOperator(t, "/operator/integrations/discourse") if strings.Contains(page.MustElement(`#operator-body`).MustHTML(), "Discourse is not configured") { t.Skip("app booted without Discourse config; see this file's header for the fakeserver + flags bootstrap") } - skipUnlessForumReachable(t, page, base) - // The probe leaves the page on the settings surface; return to the - // mapping surface before driving the form phases. - page.Timeout(15 * time.Second).MustNavigate(base + "/operator/integrations/discourse") + skipUnlessForumReachable(t) page.Timeout(10 * time.Second).MustElement(`form[hx-post="/partials/operator/discourse/mappings"]`) t.Logf("phase 1a: empty group name → 422 + field error") diff --git a/test/e2e/operator-walkthroughs/fedwiki_sites_test.go b/test/e2e/operator-walkthroughs/fedwiki_sites_test.go index 6dc9d413..ca4fbfff 100644 --- a/test/e2e/operator-walkthroughs/fedwiki_sites_test.go +++ b/test/e2e/operator-walkthroughs/fedwiki_sites_test.go @@ -127,7 +127,7 @@ type sitesWalk struct { func TestFedWikiSitesWalkthrough(t *testing.T) { defer browsertest.Recover(t) page, base := browsertest.OpenOperator(t, "/operator/integrations") - skipUnlessFarmReachable(t, page, base) + skipUnlessFarmReachable(t) env := browsertest.EnvFromTestDir(t) farmURL, farmToken := env["MC_FEDWIKI_FARM_API_URL"], env["MC_FEDWIKI_ADMIN_TOKEN"] if farmURL == "" || farmToken == "" { diff --git a/test/e2e/operator-walkthroughs/helpers_test.go b/test/e2e/operator-walkthroughs/helpers_test.go index febd5150..ee896d32 100644 --- a/test/e2e/operator-walkthroughs/helpers_test.go +++ b/test/e2e/operator-walkthroughs/helpers_test.go @@ -65,15 +65,19 @@ func foundIn(html string, banned ...string) []string { } // skipUnlessIntegrationEndpointReachable probes the endpoint an integration is -// actually configured with — the effective value of key on that integration's -// settings page — and skips when it does not answer. It is the generic half of +// configured with and skips when it does not answer. It is the generic half of // the pattern skipUnlessForumReachable applies to Discourse: a walkthrough may // be pointed at a compose profile (or an external service) that simply is not // composed, and every service-touching phase would then fail on connection // errors instead of skipping. // -// Three outcomes, deliberately distinguished: -// - no effective value rendered → return, so a walkthrough's config-plumbing +// The endpoint comes from test/.env, the file the console's environment is +// built from (endpointEnvVar names the variable). The settings page cannot +// supply it: these keys are deployment-only, so the page shows static text +// and no field holding the URL. +// +// Four outcomes, deliberately distinguished: +// - no http value in test/.env → return, so a walkthrough's config-plumbing // phases still run against an integration nobody configured; // - configured but refusing connections → skip; // - configured but answering 5xx → skip (container up, service still booting @@ -82,27 +86,10 @@ func foundIn(html string, banned ...string) []string { // point at this machine that resolves elsewhere → fail, naming the // /etc/hosts lines that fix it (requireResolvesHere). // -// Reading the URL off the settings page rather than off test/.env keeps the -// probe truthful for every bootstrap — compose profile, fake server, or a -// service hosted outside compose entirely. Leaves the page on the settings -// surface; callers must navigate onward themselves. // hint names, in the caller's own words, what would make the endpoint answer. -func skipUnlessIntegrationEndpointReachable(t *testing.T, page *rod.Page, base, integrationKey, key, hint string) { +func skipUnlessIntegrationEndpointReachable(t *testing.T, integrationKey, key, hint string) { t.Helper() - page.Timeout(15 * time.Second).MustNavigate(base + "/operator/integrations/" + integrationKey + "/settings") - // The settings page is one declared form, one field per non-secret key - // (operator.integration.settings, forms-library lane D): the endpoint - // URL is a plain text field named for its key, not a table row, so its - // configured value is the field's own value. Wait for the form, then - // read the field; an absent or non-http value means the endpoint is not - // configured and the guard proceeds (the settings surface never dials - // the endpoint, so an unconfigured one still exercises the phases). - page.Timeout(10 * time.Second).MustElement(`form[data-form="operator.integration.settings"]`) - has, field, err := page.Has(`[name="` + key + `"]`) - if err != nil || !has { - return - } - endpoint := strings.TrimSpace(field.MustProperty("value").String()) + endpoint := strings.TrimSpace(browsertest.EnvFromTestDir(t)[endpointEnvVar(key)]) if !strings.HasPrefix(endpoint, "http") { return } @@ -118,6 +105,13 @@ func skipUnlessIntegrationEndpointReachable(t *testing.T, page *rod.Page, base, } } +// endpointEnvVar names the environment variable the console reads for a +// config key: the MC prefix, the key upper-cased, and "-" replaced by "_" +// (viper.SetEnvPrefix, SetEnvKeyReplacer and AutomaticEnv in cmd/root.go). +func endpointEnvVar(key string) string { + return "MC_" + strings.ToUpper(strings.ReplaceAll(key, "-", "_")) +} + // resolutionProblem says why host's lookup answer does not let a test reach // it, or "" when it does: the lookup failed, it returned no address, or a // name defined to point at this machine (localhost, *.localhost, @@ -176,9 +170,9 @@ func requireResolvesHere(t *testing.T, integrationKey, endpoint string) { // skipUnlessFarmReachable is the FedWiki binding of the guard above. The farm // API URL is the endpoint every FedWiki surface dials, and the `fedwiki` // compose profile is what composes a farm to answer it. -func skipUnlessFarmReachable(t *testing.T, page *rod.Page, base string) { +func skipUnlessFarmReachable(t *testing.T) { t.Helper() - skipUnlessIntegrationEndpointReachable(t, page, base, "fedwiki", "fedwiki-farm-api-url", + skipUnlessIntegrationEndpointReachable(t, "fedwiki", "fedwiki-farm-api-url", `add "fedwiki" to COMPOSE_PROFILES in test/.env, bring the stack up, and uncomment the MC_FEDWIKI_* block`) } diff --git a/test/e2e/operator-walkthroughs/integration_settings_test.go b/test/e2e/operator-walkthroughs/integration_settings_test.go index 1e36341a..b0123267 100644 --- a/test/e2e/operator-walkthroughs/integration_settings_test.go +++ b/test/e2e/operator-walkthroughs/integration_settings_test.go @@ -47,7 +47,7 @@ func TestIntegrationSettingsWalkthrough(t *testing.T) { // has always had. An unconfigured farm is not a skip: the settings surface // is config plumbing and never dials the farm, so the guard returns and // the phases run. - skipUnlessFarmReachable(t, page, base) + skipUnlessFarmReachable(t) settingsSaveOverride(t, page, base) originalInterval := settingsRefuseDuration(t, page) diff --git a/test/e2e/operator-walkthroughs/resolution_test.go b/test/e2e/operator-walkthroughs/resolution_test.go index 33bffb79..07ad843d 100644 --- a/test/e2e/operator-walkthroughs/resolution_test.go +++ b/test/e2e/operator-walkthroughs/resolution_test.go @@ -36,3 +36,14 @@ func TestResolutionProblem(t *testing.T) { }) } } + +func TestEndpointEnvVar(t *testing.T) { + for key, want := range map[string]string{ + "fedwiki-farm-api-url": "MC_FEDWIKI_FARM_API_URL", + "discourse-base-url": "MC_DISCOURSE_BASE_URL", + } { + if got := endpointEnvVar(key); got != want { + t.Errorf("endpointEnvVar(%q) = %q, want %q", key, got, want) + } + } +}