diff --git a/.github/actions/go/pre-merge/action.yml b/.github/actions/go/pre-merge/action.yml index 56e0162b70..53a381edcd 100644 --- a/.github/actions/go/pre-merge/action.yml +++ b/.github/actions/go/pre-merge/action.yml @@ -141,6 +141,8 @@ runs: if: inputs.task == 'e2e' env: IGGY_TCP_ADDRESS: 127.0.0.1:8090 + IGGY_ROOT_USERNAME: iggy + IGGY_ROOT_PASSWORD: iggy run: | echo "🧪 Running Go e2e tests..." diff --git a/.github/actions/php/pre-merge/action.yml b/.github/actions/php/pre-merge/action.yml index 789e9db400..4205d465cf 100644 --- a/.github/actions/php/pre-merge/action.yml +++ b/.github/actions/php/pre-merge/action.yml @@ -161,10 +161,9 @@ runs: shell: bash working-directory: foreign/php env: - IGGY_HOST: 127.0.0.1 - IGGY_PORT: 8090 - IGGY_USERNAME: iggy - IGGY_PASSWORD: iggy + IGGY_TCP_ADDRESS: 127.0.0.1:8090 + IGGY_ROOT_USERNAME: iggy + IGGY_ROOT_PASSWORD: iggy run: | mkdir -p ../../reports ./scripts/test.sh --log-junit ../../reports/php-junit.xml @@ -194,8 +193,7 @@ runs: shell: bash working-directory: foreign/php env: - IGGY_HOST: 127.0.0.1 - IGGY_PORT: 8090 + IGGY_TCP_ADDRESS: 127.0.0.1:8090 IGGY_TLS_CONNECTION_STRING: iggy+tcp://iggy:iggy@127.0.0.1:8090?tls=true&tls_domain=localhost&tls_ca_file=${{ github.workspace }}/core/certs/iggy_ca_cert.pem IGGY_TLS_PLAINTEXT_ADDRESS: 127.0.0.1:8090 run: ./scripts/test.sh --log-junit ../../reports/php-tls-junit.xml tests/TlsTest.php diff --git a/.github/workflows/coverage-baseline.yml b/.github/workflows/coverage-baseline.yml index a980c1564d..049ea42985 100644 --- a/.github/workflows/coverage-baseline.yml +++ b/.github/workflows/coverage-baseline.yml @@ -510,6 +510,10 @@ jobs: go test -v -race -coverprofile=../../reports/go-coverage-unit.out ./... - name: Run BDD tests with coverage + env: + IGGY_TCP_ADDRESS: 127.0.0.1:8090 + IGGY_ROOT_USERNAME: iggy + IGGY_ROOT_PASSWORD: iggy run: | cd bdd/go mkdir -p ../../reports diff --git a/bdd/cpp/features/step_definitions/background_steps.cpp b/bdd/cpp/features/step_definitions/background_steps.cpp index 5100fde086..3fc539d92e 100644 --- a/bdd/cpp/features/step_definitions/background_steps.cpp +++ b/bdd/cpp/features/step_definitions/background_steps.cpp @@ -27,23 +27,26 @@ #include #include +#include #include #include "world.hpp" namespace { -std::string env_or(const char *name, const std::string &fallback) { +std::string required_env(const char *name) { const char *value = std::getenv(name); - return value != nullptr ? std::string(value) : fallback; + if (value == nullptr || *value == '\0') { + throw std::runtime_error(std::string(name) + + " must be set; run the suite via scripts/run-bdd-tests.sh"); + } + return std::string(value); } } // namespace GIVEN("^I have a running Iggy server$") { cucumber::ScenarioScope context; - // Empty address makes the SDK fall back to its default TCP endpoint; in CI the address - // is supplied via IGGY_TCP_ADDRESS (e.g. iggy-server:8090). - const std::string address = env_or("IGGY_TCP_ADDRESS", ""); + const std::string address = required_env("IGGY_TCP_ADDRESS"); iggy::ffi::Client *client = iggy::ffi::new_connection(address); ASSERT_NE(client, nullptr); context->client = client; @@ -54,7 +57,7 @@ GIVEN("^I am authenticated as the root user$") { cucumber::ScenarioScope context; ASSERT_NE(context->client, nullptr); - const std::string username = env_or("IGGY_ROOT_USERNAME", "iggy"); - const std::string password = env_or("IGGY_ROOT_PASSWORD", "iggy"); + const std::string username = required_env("IGGY_ROOT_USERNAME"); + const std::string password = required_env("IGGY_ROOT_PASSWORD"); context->client->login_user(username, password); } diff --git a/bdd/docker-compose.server.yml b/bdd/docker-compose.server.yml index e22484533c..16005db3b1 100644 --- a/bdd/docker-compose.server.yml +++ b/bdd/docker-compose.server.yml @@ -79,6 +79,9 @@ services: python-bdd: <<: *server-bdd-deps + php-bdd: + <<: *server-bdd-deps + go-bdd: <<: *server-bdd-deps diff --git a/bdd/docker-compose.yml b/bdd/docker-compose.yml index 9d577ab191..01dee92925 100644 --- a/bdd/docker-compose.yml +++ b/bdd/docker-compose.yml @@ -77,14 +77,9 @@ services: build: context: .. dockerfile: bdd/php/Dockerfile - depends_on: - iggy-server: - condition: service_healthy environment: - - IGGY_HOST=iggy-server - - IGGY_PORT=8090 - - IGGY_USERNAME=iggy - - IGGY_PASSWORD=iggy + - IGGY_ROOT_USERNAME=iggy + - IGGY_ROOT_PASSWORD=iggy - BDD_FEATURE=${BDD_FEATURE:-all} volumes: - ./scenarios/basic_messaging.feature:/app/features/basic_messaging.feature diff --git a/bdd/go/tests/basic_messaging.go b/bdd/go/tests/basic_messaging.go index e5d7089f68..21ad3e12b7 100644 --- a/bdd/go/tests/basic_messaging.go +++ b/bdd/go/tests/basic_messaging.go @@ -21,8 +21,8 @@ import ( "context" "errors" "fmt" - "os" + "github.com/apache/iggy/bdd/go/tests/env" "github.com/apache/iggy/foreign/go/client" "github.com/apache/iggy/foreign/go/client/tcp" iggcon "github.com/apache/iggy/foreign/go/contracts" @@ -52,10 +52,7 @@ type basicMessagingSteps struct{} func (s basicMessagingSteps) givenRunningServer(ctx context.Context) error { c := getBasicMessagingCtx(ctx) - addr := os.Getenv("IGGY_TCP_ADDRESS") - if addr == "" { - addr = "127.0.0.1:8090" - } + addr := env.ServerAddress() c.serverAddr = &addr return nil } @@ -80,7 +77,8 @@ func (s basicMessagingSteps) givenAuthenticationAsRoot(ctx context.Context) erro return fmt.Errorf("error pinging client: %w", err) } - if _, err = cli.LoginUser(ctx, "iggy", "iggy"); err != nil { + username, password := env.RootCredentials() + if _, err = cli.LoginUser(ctx, username, password); err != nil { return fmt.Errorf("error logging in: %v", err) } diff --git a/bdd/go/tests/env/env.go b/bdd/go/tests/env/env.go new file mode 100644 index 0000000000..002c9bfceb --- /dev/null +++ b/bdd/go/tests/env/env.go @@ -0,0 +1,55 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +// Package env reads the endpoints and credentials the BDD suites run +// against. A default here would turn a dropped compose variable into a run +// against whatever happens to listen on the fallback address, so a missing +// value aborts the suite instead. +package env + +import ( + "fmt" + "os" +) + +func required(name string) string { + value, ok := os.LookupEnv(name) + if !ok || value == "" { + panic(fmt.Sprintf("%s must be set; run the suite via scripts/run-bdd-tests.sh", name)) + } + return value +} + +// ServerAddress returns the address of the single-node server. +func ServerAddress() string { + return required("IGGY_TCP_ADDRESS") +} + +// LeaderAddress returns the address of the cluster leader. +func LeaderAddress() string { + return required("IGGY_TCP_ADDRESS_LEADER") +} + +// FollowerAddress returns the address of the cluster follower. +func FollowerAddress() string { + return required("IGGY_TCP_ADDRESS_FOLLOWER") +} + +// RootCredentials returns the root username and password. +func RootCredentials() (string, string) { + return required("IGGY_ROOT_USERNAME"), required("IGGY_ROOT_PASSWORD") +} diff --git a/bdd/go/tests/leader_redirection.go b/bdd/go/tests/leader_redirection.go index cca2aa66b7..8593f55127 100644 --- a/bdd/go/tests/leader_redirection.go +++ b/bdd/go/tests/leader_redirection.go @@ -22,12 +22,11 @@ import ( "errors" "fmt" "net" - "os" "regexp" - "strconv" "strings" "time" + "github.com/apache/iggy/bdd/go/tests/env" "github.com/apache/iggy/foreign/go/client" "github.com/apache/iggy/foreign/go/client/tcp" iggcon "github.com/apache/iggy/foreign/go/contracts" @@ -35,9 +34,6 @@ import ( "github.com/cucumber/godog" ) -const defaultRootUsername = "iggy" -const defaultRootPassword = "iggy" - type leaderCtxKey struct{} type leaderCtx struct { Clients map[string]iggcon.Client @@ -90,25 +86,16 @@ func resolveServerAddress(role string, port uint16) string { switch { case role == "leader" && port == 8091: - if addr, ok := os.LookupEnv("IGGY_TCP_ADDRESS_LEADER"); ok { - return addr - } - return "iggy-leader:8091" + return env.LeaderAddress() case role == "follower" && port == 8092: - if addr, ok := os.LookupEnv("IGGY_TCP_ADDRESS_FOLLOWER"); ok { - return addr - } - return "iggy-follower:8092" + return env.FollowerAddress() case port == 8090: - if addr, ok := os.LookupEnv("IGGY_TCP_ADDRESS"); ok { - return addr - } - return "iggy-server:8090" + return env.ServerAddress() default: - return "iggy-server:" + strconv.Itoa(int(port)) + panic(fmt.Sprintf("no address mapping for role %q on port %d", role, port)) } } @@ -323,12 +310,13 @@ func (s leaderSteps) whenAuthenticateRoot(ctx context.Context) error { names = []string{"main"} } + username, password := env.RootCredentials() for _, name := range names { cli, ok := c.Clients[name] if !ok { return fmt.Errorf("client %s should be created", name) } - if _, err := cli.LoginUser(ctx, defaultRootUsername, defaultRootPassword); err != nil { + if _, err := cli.LoginUser(ctx, username, password); err != nil { return err } // Small delay between multiple authentications to avoid race conditions diff --git a/bdd/go/tests/raw_command.go b/bdd/go/tests/raw_command.go index 8bafdf1c13..290dfe3252 100644 --- a/bdd/go/tests/raw_command.go +++ b/bdd/go/tests/raw_command.go @@ -21,8 +21,8 @@ import ( "context" "errors" "fmt" - "os" + "github.com/apache/iggy/bdd/go/tests/env" "github.com/apache/iggy/foreign/go/client" "github.com/apache/iggy/foreign/go/client/tcp" iggcon "github.com/apache/iggy/foreign/go/contracts" @@ -46,11 +46,7 @@ func getRawCommandCtx(ctx context.Context) *rawCommandCtx { type rawCommandSteps struct{} func (rawCommandSteps) givenRunningServer(ctx context.Context) error { - address := os.Getenv("IGGY_TCP_ADDRESS") - if address == "" { - address = "127.0.0.1:8090" - } - getRawCommandCtx(ctx).serverAddr = address + getRawCommandCtx(ctx).serverAddr = env.ServerAddress() return nil } @@ -63,7 +59,8 @@ func (rawCommandSteps) givenAuthenticationAsRoot(ctx context.Context) error { if err = iggyClient.Connect(ctx); err != nil { return fmt.Errorf("connect client: %w", err) } - if _, err = iggyClient.LoginUser(ctx, "iggy", "iggy"); err != nil { + username, password := env.RootCredentials() + if _, err = iggyClient.LoginUser(ctx, username, password); err != nil { return fmt.Errorf("authenticate client: %w", err) } state.client = iggyClient diff --git a/bdd/go/tests/tcp_test/session_feature_login.go b/bdd/go/tests/tcp_test/session_feature_login.go index ccb1b08e51..9d6315178c 100644 --- a/bdd/go/tests/tcp_test/session_feature_login.go +++ b/bdd/go/tests/tcp_test/session_feature_login.go @@ -20,16 +20,19 @@ package tcp_test import ( "context" + "github.com/apache/iggy/bdd/go/tests/env" iggcon "github.com/apache/iggy/foreign/go/contracts" "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" ) var _ = ginkgo.Describe("LOGIN FEATURE:", func() { + rootUsername, rootPassword := env.RootCredentials() + ginkgo.When("user is already logged in", func() { ginkgo.Context("and tries to log with correct data", func() { client := createAuthorizedConnection() - user, err := client.LoginUser(context.Background(), "iggy", "iggy") + user, err := client.LoginUser(context.Background(), rootUsername, rootPassword) itShouldNotReturnError(err) itShouldReturnUserId(user, 0) @@ -47,7 +50,7 @@ var _ = ginkgo.Describe("LOGIN FEATURE:", func() { ginkgo.When("user is not logged in", func() { ginkgo.Context("and tries to log with correct data", func() { client := createClient() - user, err := client.LoginUser(context.Background(), "iggy", "iggy") + user, err := client.LoginUser(context.Background(), rootUsername, rootPassword) itShouldNotReturnError(err) itShouldReturnUserId(user, 0) diff --git a/bdd/go/tests/tcp_test/test_helpers.go b/bdd/go/tests/tcp_test/test_helpers.go index efcdd18310..b122b8c4b4 100644 --- a/bdd/go/tests/tcp_test/test_helpers.go +++ b/bdd/go/tests/tcp_test/test_helpers.go @@ -20,10 +20,10 @@ package tcp_test import ( "context" "math/rand" - "os" "strings" "time" + "github.com/apache/iggy/bdd/go/tests/env" "github.com/apache/iggy/foreign/go/client" iggcon "github.com/apache/iggy/foreign/go/contracts" @@ -32,7 +32,8 @@ import ( func createAuthorizedConnection() iggcon.Client { cli := createClient() - _, err := cli.LoginUser(context.Background(), "iggy", "iggy") + username, password := env.RootCredentials() + _, err := cli.LoginUser(context.Background(), username, password) if err != nil { panic(err) } @@ -40,13 +41,9 @@ func createAuthorizedConnection() iggcon.Client { } func createClient() iggcon.Client { - addr := os.Getenv("IGGY_TCP_ADDRESS") - if addr == "" { - addr = "127.0.0.1:8090" - } cli, err := client.NewIggyClient( client.WithTcp( - tcp.WithServerAddress(addr), + tcp.WithServerAddress(env.ServerAddress()), ), ) if err != nil { diff --git a/bdd/java/src/test/java/org/apache/iggy/bdd/BasicMessagingSteps.java b/bdd/java/src/test/java/org/apache/iggy/bdd/BasicMessagingSteps.java index 8cc810960d..0fc05c28c0 100644 --- a/bdd/java/src/test/java/org/apache/iggy/bdd/BasicMessagingSteps.java +++ b/bdd/java/src/test/java/org/apache/iggy/bdd/BasicMessagingSteps.java @@ -54,7 +54,7 @@ public class BasicMessagingSteps { @Given("I have a running Iggy server") public void runningServer() { - context.serverAddr = getenvOrDefault("IGGY_TCP_ADDRESS", "127.0.0.1:8090"); + context.serverAddr = TestEnvironment.serverAddress(); HostPort hostPort = HostPort.parse(context.serverAddr); IggyTcpClient client = @@ -67,9 +67,7 @@ public void runningServer() { @Given("I am authenticated as the root user") public void authenticatedRootUser() { - String username = getenvOrDefault("IGGY_ROOT_USERNAME", "iggy"); - String password = getenvOrDefault("IGGY_ROOT_PASSWORD", "iggy"); - getClient().users().login(username, password); + getClient().users().login(TestEnvironment.rootUsername(), TestEnvironment.rootPassword()); } @Given("I have no streams in the system") @@ -301,11 +299,6 @@ private IggyBaseClient getClient() { return context.client; } - private static String getenvOrDefault(String key, String defaultValue) { - String value = System.getenv(key); - return value == null || value.isBlank() ? defaultValue : value; - } - private static final class HostPort { private final String host; private final int port; diff --git a/bdd/java/src/test/java/org/apache/iggy/bdd/LeaderRedirectionSteps.java b/bdd/java/src/test/java/org/apache/iggy/bdd/LeaderRedirectionSteps.java index 4f9645377a..23f556e8f4 100644 --- a/bdd/java/src/test/java/org/apache/iggy/bdd/LeaderRedirectionSteps.java +++ b/bdd/java/src/test/java/org/apache/iggy/bdd/LeaderRedirectionSteps.java @@ -208,8 +208,8 @@ private void createAndConnectClient(String name, String address) { } private void authenticateAllClients() { - String username = getenvOrDefault("IGGY_ROOT_USERNAME", "iggy"); - String password = getenvOrDefault("IGGY_ROOT_PASSWORD", "iggy"); + String username = TestEnvironment.rootUsername(); + String password = TestEnvironment.rootPassword(); for (IggyTcpClient client : clients.values()) { String initialAddress = client.getConnectionInfo().serverAddress(); client.users().login(username, password); @@ -275,8 +275,8 @@ private static void assertAddressMatchesPort(String address, int port, String de private static String addressForRole(String role) { return switch (role) { - case "leader" -> getenvOrDefault("IGGY_TCP_ADDRESS_LEADER", "127.0.0.1:8091"); - case "follower" -> getenvOrDefault("IGGY_TCP_ADDRESS_FOLLOWER", "127.0.0.1:8092"); + case "leader" -> TestEnvironment.leaderAddress(); + case "follower" -> TestEnvironment.followerAddress(); default -> throw new IllegalArgumentException("Unknown role: " + role); }; } @@ -291,11 +291,6 @@ private static String addressForPort(int port) { } private static String singleServerAddress() { - return getenvOrDefault("IGGY_TCP_ADDRESS", "127.0.0.1:8090"); - } - - private static String getenvOrDefault(String key, String defaultValue) { - String value = System.getenv(key); - return value == null || value.isBlank() ? defaultValue : value; + return TestEnvironment.serverAddress(); } } diff --git a/bdd/java/src/test/java/org/apache/iggy/bdd/TestEnvironment.java b/bdd/java/src/test/java/org/apache/iggy/bdd/TestEnvironment.java new file mode 100644 index 0000000000..0a3cdc9aae --- /dev/null +++ b/bdd/java/src/test/java/org/apache/iggy/bdd/TestEnvironment.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iggy.bdd; + +/** + * Endpoints and credentials the BDD suite runs against. + * + *

A default here would turn a dropped compose variable into a run against whatever happens to + * listen on the fallback address, so a missing value aborts the suite instead. + */ +final class TestEnvironment { + + private TestEnvironment() {} + + static String require(String name) { + String value = System.getenv(name); + if (value == null || value.isBlank()) { + throw new IllegalStateException(name + " must be set; run the suite via scripts/run-bdd-tests.sh"); + } + return value; + } + + static String serverAddress() { + return require("IGGY_TCP_ADDRESS"); + } + + static String leaderAddress() { + return require("IGGY_TCP_ADDRESS_LEADER"); + } + + static String followerAddress() { + return require("IGGY_TCP_ADDRESS_FOLLOWER"); + } + + static String rootUsername() { + return require("IGGY_ROOT_USERNAME"); + } + + static String rootPassword() { + return require("IGGY_ROOT_PASSWORD"); + } +} diff --git a/bdd/php/Dockerfile b/bdd/php/Dockerfile index a8ee4a135f..0990e770ee 100644 --- a/bdd/php/Dockerfile +++ b/bdd/php/Dockerfile @@ -45,8 +45,6 @@ ENV RUSTUP_HOME=/usr/local/rustup ENV PATH=/usr/local/cargo/bin:$PATH ENV PHP=/usr/bin/php8.3 ENV PHP_CONFIG=/usr/bin/php-config8.3 -ENV IGGY_HOST=iggy-server -ENV IGGY_PORT=8090 ENV BDD_FEATURE_FILE=/workspace/bdd/scenarios/basic_messaging.feature RUN rustup component add llvm-tools-preview \ diff --git a/bdd/php/tests/BasicMessagingFeatureTest.php b/bdd/php/tests/BasicMessagingFeatureTest.php index d47b09f609..8c4f8b068b 100644 --- a/bdd/php/tests/BasicMessagingFeatureTest.php +++ b/bdd/php/tests/BasicMessagingFeatureTest.php @@ -19,6 +19,7 @@ declare(strict_types=1); require_once __DIR__ . '/SharedFeatureParser.php'; +require_once __DIR__ . '/TestEnvironment.php'; use Iggy\Client as IggyClient; use Iggy\PollingStrategy; @@ -71,7 +72,7 @@ public static function scenarioCases(): array private function runStep(string $step): void { if ($step === 'I have a running Iggy server') { - $this->client = new IggyClient(server_host() . ':' . server_port()); + $this->client = new IggyClient(TestEnvironment::serverAddress()); $this->client->connect(); $this->client->ping(); @@ -79,7 +80,7 @@ private function runStep(string $step): void } if ($step === 'I am authenticated as the root user') { - $this->requireClient()->loginUser(env_or_default('IGGY_USERNAME', 'iggy'), env_or_default('IGGY_PASSWORD', 'iggy')); + $this->requireClient()->loginUser(TestEnvironment::rootUsername(), TestEnvironment::rootPassword()); return; } diff --git a/bdd/php/tests/RawCommandFeatureTest.php b/bdd/php/tests/RawCommandFeatureTest.php index db9aeb8f87..181ca9bcdb 100644 --- a/bdd/php/tests/RawCommandFeatureTest.php +++ b/bdd/php/tests/RawCommandFeatureTest.php @@ -19,6 +19,7 @@ declare(strict_types=1); require_once __DIR__ . '/SharedFeatureParser.php'; +require_once __DIR__ . '/TestEnvironment.php'; use Iggy\Client as IggyClient; use Iggy\Exception\IggyException; @@ -52,15 +53,15 @@ public static function scenarioCases(): array private function runStep(string $step): void { if ($step === 'I have a running Iggy server') { - $this->client = new IggyClient(server_host() . ':' . server_port()); + $this->client = new IggyClient(TestEnvironment::serverAddress()); $this->client->connect(); $this->client->ping(); return; } if ($step === 'I am authenticated as the root user') { $this->requireClient()->loginUser( - env_or_default('IGGY_USERNAME', 'iggy'), - env_or_default('IGGY_PASSWORD', 'iggy'), + TestEnvironment::rootUsername(), + TestEnvironment::rootPassword(), ); return; } diff --git a/bdd/php/tests/TestEnvironment.php b/bdd/php/tests/TestEnvironment.php new file mode 100644 index 0000000000..3c999fe2bc --- /dev/null +++ b/bdd/php/tests/TestEnvironment.php @@ -0,0 +1,53 @@ + str: + """Read a variable the suite cannot run without. + + A default here would turn a dropped compose variable into a run against + whatever happens to listen on the fallback address, so a missing value + aborts the suite instead. + """ + value = os.environ.get(name) + if not value: + raise RuntimeError( + f"{name} must be set; run the suite via scripts/run-bdd-tests.sh" + ) + return value + + +@pytest.fixture(scope="session") +def root_credentials() -> tuple[str, str]: + """Root username and password the server was started with.""" + return required_env("IGGY_ROOT_USERNAME"), required_env("IGGY_ROOT_PASSWORD") + + @pytest.fixture(scope="session") def event_loop(): """Create an instance of the default event loop for the test session.""" @@ -57,7 +78,6 @@ def context(): """Create a fresh context for each test scenario.""" ctx = GlobalContext() - # Get server address from environment or use default - ctx.server_addr = os.environ.get("IGGY_TCP_ADDRESS", "127.0.0.1:8090") + ctx.server_addr = required_env("IGGY_TCP_ADDRESS") yield ctx diff --git a/bdd/python/tests/test_basic_messaging.py b/bdd/python/tests/test_basic_messaging.py index cbaf3869a4..b34d0cdc79 100644 --- a/bdd/python/tests/test_basic_messaging.py +++ b/bdd/python/tests/test_basic_messaging.py @@ -52,11 +52,11 @@ async def _connect(): @given("I am authenticated as the root user") -def authenticated_root_user(context): +def authenticated_root_user(context, root_credentials): """Authenticate as root user""" async def _login(): - await context.client.login_user("iggy", "iggy") + await context.client.login_user(*root_credentials) asyncio.run(_login()) diff --git a/bdd/python/tests/test_raw_command.py b/bdd/python/tests/test_raw_command.py index cc0842530b..e2b040d30b 100644 --- a/bdd/python/tests/test_raw_command.py +++ b/bdd/python/tests/test_raw_command.py @@ -41,9 +41,9 @@ async def connect(): @given("I am authenticated as the root user") -def authenticated_root_user(context): +def authenticated_root_user(context, root_credentials): async def login(): - await context.client.login_user("iggy", "iggy") + await context.client.login_user(*root_credentials) asyncio.run(login()) diff --git a/bdd/rust/tests/helpers/cluster.rs b/bdd/rust/tests/helpers/cluster.rs index 195bcb9a83..b705de2e1d 100644 --- a/bdd/rust/tests/helpers/cluster.rs +++ b/bdd/rust/tests/helpers/cluster.rs @@ -15,22 +15,17 @@ // specific language governing permissions and limitations // under the License. +use crate::helpers::env::{follower_address, leader_address, server_address}; use iggy::prelude::*; -use std::env; use std::sync::Arc; -/// Resolves server address based on role and port, checking environment variables first +/// Resolves the server address for a role and port from the environment pub fn resolve_server_address(role: &str, port: u16) -> String { match (role.to_lowercase().as_str(), port) { - ("leader", 8091) => { - env::var("IGGY_TCP_ADDRESS_LEADER").unwrap_or_else(|_| "iggy-leader:8091".to_string()) - } - ("follower", 8092) => env::var("IGGY_TCP_ADDRESS_FOLLOWER") - .unwrap_or_else(|_| "iggy-follower:8092".to_string()), - ("single", 8090) | (_, 8090) => { - env::var("IGGY_TCP_ADDRESS").unwrap_or_else(|_| "iggy-server:8090".to_string()) - } - _ => format!("iggy-server:{}", port), + ("leader", 8091) => leader_address(), + ("follower", 8092) => follower_address(), + (_, 8090) => server_address(), + _ => panic!("no address mapping for role '{role}' on port {port}"), } } diff --git a/bdd/rust/tests/helpers/env.rs b/bdd/rust/tests/helpers/env.rs new file mode 100644 index 0000000000..75c65683a0 --- /dev/null +++ b/bdd/rust/tests/helpers/env.rs @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::env; + +/// Reads a variable the suite cannot run without. +/// +/// A default here would turn a dropped compose variable into a run against +/// whatever happens to listen on the fallback address, so a missing value +/// aborts the suite instead. +fn required_env(name: &str) -> String { + match env::var(name) { + Ok(value) if !value.is_empty() => value, + _ => panic!("{name} must be set; run the suite via scripts/run-bdd-tests.sh"), + } +} + +pub fn server_address() -> String { + required_env("IGGY_TCP_ADDRESS") +} + +pub fn leader_address() -> String { + required_env("IGGY_TCP_ADDRESS_LEADER") +} + +pub fn follower_address() -> String { + required_env("IGGY_TCP_ADDRESS_FOLLOWER") +} + +pub fn root_username() -> String { + required_env("IGGY_ROOT_USERNAME") +} + +pub fn root_password() -> String { + required_env("IGGY_ROOT_PASSWORD") +} diff --git a/bdd/rust/tests/helpers/mod.rs b/bdd/rust/tests/helpers/mod.rs index 26173fc631..7521d25264 100644 --- a/bdd/rust/tests/helpers/mod.rs +++ b/bdd/rust/tests/helpers/mod.rs @@ -16,4 +16,5 @@ // under the License. pub mod cluster; +pub mod env; pub mod test_data; diff --git a/bdd/rust/tests/steps/auth.rs b/bdd/rust/tests/steps/auth.rs index f5fc554bee..bca0c06876 100644 --- a/bdd/rust/tests/steps/auth.rs +++ b/bdd/rust/tests/steps/auth.rs @@ -16,6 +16,7 @@ // under the License. use crate::common::global_context::GlobalContext; +use crate::helpers::env::{root_password, root_username}; use cucumber::given; use iggy::prelude::*; use std::sync::Arc; @@ -42,7 +43,7 @@ pub async fn given_authenticated_as_root(world: &mut GlobalContext) { client.ping().await.expect("Server should respond to ping"); client - .login_user(DEFAULT_ROOT_USERNAME, DEFAULT_ROOT_PASSWORD) + .login_user(&root_username(), &root_password()) .await .expect("Failed to login as root"); diff --git a/bdd/rust/tests/steps/leader_redirection.rs b/bdd/rust/tests/steps/leader_redirection.rs index 1f6bcc5ad5..3d7d95b325 100644 --- a/bdd/rust/tests/steps/leader_redirection.rs +++ b/bdd/rust/tests/steps/leader_redirection.rs @@ -17,6 +17,7 @@ use crate::common::leader_context::LeaderContext; use crate::helpers::cluster; +use crate::helpers::env::{root_password, root_username}; use cucumber::{given, then, when}; use iggy::prelude::*; use std::time::Duration; @@ -160,7 +161,7 @@ async fn when_authenticate_root(world: &mut LeaderContext) { .unwrap_or_else(|| panic!("Client {} should be created", client_name)); client - .login_user(DEFAULT_ROOT_USERNAME, DEFAULT_ROOT_PASSWORD) + .login_user(&root_username(), &root_password()) .await .expect("Failed to login as root"); diff --git a/bdd/rust/tests/steps/server.rs b/bdd/rust/tests/steps/server.rs index d621b699cc..73e8b7491e 100644 --- a/bdd/rust/tests/steps/server.rs +++ b/bdd/rust/tests/steps/server.rs @@ -16,12 +16,11 @@ // under the License. use crate::common::global_context::GlobalContext; +use crate::helpers::env::server_address; use cucumber::given; #[given("I have a running Iggy server")] pub async fn given_running_server(world: &mut GlobalContext) { // External server mode - connect to server from environment - let server_addr = - std::env::var("IGGY_TCP_ADDRESS").unwrap_or_else(|_| "localhost:8090".to_string()); - world.server_addr = Some(server_addr); + world.server_addr = Some(server_address()); } diff --git a/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestContext.cs b/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestContext.cs index 81c12f2e82..27a08f5555 100644 --- a/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestContext.cs +++ b/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestContext.cs @@ -24,9 +24,9 @@ namespace Apache.Iggy.Tests.BDD.Context; public class TestContext { public IIggyClient IggyClient { get; set; } = null!; - public string TcpUrl { get; set; } = string.Empty; - public string LeaderTcpUrl { get; set; } = string.Empty; - public string FollowerTcpUrl { get; set; } = string.Empty; + public string TcpUrl => TestEnvironment.TcpAddress; + public string LeaderTcpUrl => TestEnvironment.LeaderTcpAddress; + public string FollowerTcpUrl => TestEnvironment.FollowerTcpAddress; public Dictionary Clients { get; } = new(); public StreamResponse? CreatedStream { get; set; } public TopicResponse? CreatedTopic { get; set; } diff --git a/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestEnvironment.cs b/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestEnvironment.cs new file mode 100644 index 0000000000..cfb89a9643 --- /dev/null +++ b/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestEnvironment.cs @@ -0,0 +1,44 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +namespace Apache.Iggy.Tests.BDD.Context; + +///

+/// Endpoints and credentials the BDD suite runs against. A default here would turn a dropped +/// compose variable into a run against whatever happens to listen on the fallback address, so a +/// missing value aborts the suite instead. +/// +public static class TestEnvironment +{ + public static string TcpAddress => Require("IGGY_TCP_ADDRESS"); + public static string LeaderTcpAddress => Require("IGGY_TCP_ADDRESS_LEADER"); + public static string FollowerTcpAddress => Require("IGGY_TCP_ADDRESS_FOLLOWER"); + public static string RootUsername => Require("IGGY_ROOT_USERNAME"); + public static string RootPassword => Require("IGGY_ROOT_PASSWORD"); + + private static string Require(string name) + { + var value = Environment.GetEnvironmentVariable(name); + if (string.IsNullOrWhiteSpace(value)) + { + throw new InvalidOperationException( + $"{name} must be set; run the suite via scripts/run-bdd-tests.sh"); + } + + return value; + } +} diff --git a/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestHooks.cs b/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestHooks.cs index 58c5debdb6..d63f2cd6b1 100644 --- a/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestHooks.cs +++ b/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestHooks.cs @@ -32,9 +32,6 @@ public TestHooks(TestContext context) [BeforeScenario] public void BeforeScenario() { - _context.TcpUrl = Environment.GetEnvironmentVariable("IGGY_TCP_ADDRESS") ?? "127.0.0.1:8090"; - _context.LeaderTcpUrl = Environment.GetEnvironmentVariable("IGGY_TCP_ADDRESS_LEADER") ?? "127.0.0.1:8091"; - _context.FollowerTcpUrl = Environment.GetEnvironmentVariable("IGGY_TCP_ADDRESS_FOLLOWER") ?? "127.0.0.1:8092"; _context.Clients.Clear(); _context.CreatedStream = null; _context.RedirectionOccurred = false; diff --git a/foreign/csharp/Iggy_SDK.Tests.BDD/README.md b/foreign/csharp/Iggy_SDK.Tests.BDD/README.md index 78ed769703..bf1de4ed42 100644 --- a/foreign/csharp/Iggy_SDK.Tests.BDD/README.md +++ b/foreign/csharp/Iggy_SDK.Tests.BDD/README.md @@ -4,20 +4,35 @@ Scenario are located at [/bdd/scenarios](../../../bdd/scenarios) ## env var -use env var `IGGY_TCP_ADDRESS="host:port"` to set expected server address for bdd test suite. +the bdd test suite has no defaults and fails when any of these is missing: -## Run via docker +- `IGGY_TCP_ADDRESS="host:port"` - server address +- `IGGY_ROOT_USERNAME` / `IGGY_ROOT_PASSWORD` - root credentials +- `IGGY_TCP_ADDRESS_LEADER` / `IGGY_TCP_ADDRESS_FOLLOWER` - cluster addresses, leader redirection scenarios only -see [/bdd/README.md](../../../bdd/README.md) +## Run (recommended) + +from the repository root run + +```bash +./scripts/run-bdd-tests.sh csharp +``` + +the script starts the server, brings up the leader and follower for the cluster +scenarios, and sets every variable above, so none of them have to be exported by +hand. see [/bdd/README.md](../../../bdd/README.md) for the sdk and feature +matrix. ## Run locally -note: bdd test expect an iggy-server at tcp://127.0.0.1:8090 +for iterating against a server you started yourself. note: bdd test expect an +iggy-server started with the same root credentials from [/foreign/csharp/Iggy_SDK.Tests.BDD](.) run ```bash -dotnet test +IGGY_TCP_ADDRESS=127.0.0.1:8090 IGGY_ROOT_USERNAME=iggy IGGY_ROOT_PASSWORD=iggy \ + dotnet test ``` ## Troubleshooting diff --git a/foreign/csharp/Iggy_SDK.Tests.BDD/StepDefinitions/BasicMessagingOperationsSteps.cs b/foreign/csharp/Iggy_SDK.Tests.BDD/StepDefinitions/BasicMessagingOperationsSteps.cs index 3012d3e995..f0f44b539a 100644 --- a/foreign/csharp/Iggy_SDK.Tests.BDD/StepDefinitions/BasicMessagingOperationsSteps.cs +++ b/foreign/csharp/Iggy_SDK.Tests.BDD/StepDefinitions/BasicMessagingOperationsSteps.cs @@ -26,6 +26,7 @@ using Shouldly; using Partitioning = Apache.Iggy.Kinds.Partitioning; using TestContext = Apache.Iggy.Tests.BDD.Context.TestContext; +using TestEnvironment = Apache.Iggy.Tests.BDD.Context.TestEnvironment; namespace Apache.Iggy.Tests.BDD.StepDefinitions; @@ -55,7 +56,7 @@ public async Task GivenIHaveARunningIggyServer() [Given(@"I am authenticated as the root user")] public async Task GivenIAmAuthenticatedAsTheRootUser() { - var loginResult = await _context.IggyClient.LoginUserAsync("iggy", "iggy"); + var loginResult = await _context.IggyClient.LoginUserAsync(TestEnvironment.RootUsername, TestEnvironment.RootPassword); loginResult.ShouldNotBeNull(); loginResult.UserId.ShouldBe(0); diff --git a/foreign/csharp/Iggy_SDK.Tests.BDD/StepDefinitions/LeaderRedirectionSteps.cs b/foreign/csharp/Iggy_SDK.Tests.BDD/StepDefinitions/LeaderRedirectionSteps.cs index a02934d03c..e23d2fc87f 100644 --- a/foreign/csharp/Iggy_SDK.Tests.BDD/StepDefinitions/LeaderRedirectionSteps.cs +++ b/foreign/csharp/Iggy_SDK.Tests.BDD/StepDefinitions/LeaderRedirectionSteps.cs @@ -25,15 +25,13 @@ using Reqnroll; using Shouldly; using TestContext = Apache.Iggy.Tests.BDD.Context.TestContext; +using TestEnvironment = Apache.Iggy.Tests.BDD.Context.TestEnvironment; namespace Apache.Iggy.Tests.BDD.StepDefinitions; [Binding] public class LeaderRedirectionSteps { - private const string RootUsername = "iggy"; - private const string RootPassword = "iggy"; - private readonly TestContext _context; public LeaderRedirectionSteps(TestContext context) @@ -141,7 +139,7 @@ private async Task AuthenticateAllClients() { var client = GetClient(name); var initialAddress = client.GetCurrentAddress(); - var result = await client.LoginUserAsync(RootUsername, RootPassword); + var result = await client.LoginUserAsync(TestEnvironment.RootUsername, TestEnvironment.RootPassword); result.ShouldNotBeNull("Failed to login as root"); // RedirectAsync runs inside LoginUserAsync; if address changed, redirection happened. diff --git a/foreign/node/README.md b/foreign/node/README.md index 169500437f..0deb555e20 100644 --- a/foreign/node/README.md +++ b/foreign/node/README.md @@ -122,7 +122,7 @@ npm run build ### test note: use env var `IGGY_TCP_ADDRESS="host:port"` to set the server -address for bdd and e2e tests. +address for e2e tests. bdd tests need more variables, see below. #### unit tests @@ -140,15 +140,27 @@ npm run test:e2e #### bdd tests -bdd test expect an iggy-server at tcp://127.0.0.1:8090 +the bdd suite has no defaults and fails when `IGGY_TCP_ADDRESS`, +`IGGY_ROOT_USERNAME` or `IGGY_ROOT_PASSWORD` is missing. from the repository +root run ```bash -npm run test:bdd +./scripts/run-bdd-tests.sh node ``` +the script starts the server and sets every variable, so none of them have to be +exported by hand. to iterate against a server you started yourself, see +[src/bdd/README.md](./src/bdd/README.md). + #### run all test -`npm run test` runs unit, bdd and e2e tests suite (expect an iggy-server at tcp://127.0.0.1:8090) +`npm run test` runs unit, bdd and e2e tests suite against an iggy-server at +tcp://127.0.0.1:8090, started with the same root credentials + +```bash +IGGY_TCP_ADDRESS=127.0.0.1:8090 IGGY_ROOT_USERNAME=iggy IGGY_ROOT_PASSWORD=iggy \ + npm run test +``` ### lint diff --git a/foreign/node/src/bdd/README.md b/foreign/node/src/bdd/README.md index b7ec9eac04..4bdd5c81b3 100644 --- a/foreign/node/src/bdd/README.md +++ b/foreign/node/src/bdd/README.md @@ -6,19 +6,32 @@ scenario are located at [/bdd/scenarios](../../../../bdd/scenarios) ## env var -use env var `IGGY_TCP_ADDRESS="host:port"` to set expected server address for bdd test suite. +the bdd test suite has no defaults and fails when any of these is missing: -## Run via docker +- `IGGY_TCP_ADDRESS="host:port"` - server address +- `IGGY_ROOT_USERNAME` / `IGGY_ROOT_PASSWORD` - root credentials -see [/bdd/README.md](../../../../bdd/README.md) +## Run (recommended) + +from the repository root run + +```bash +./scripts/run-bdd-tests.sh node +``` + +the script starts the server and sets every variable above, so none of them have +to be exported by hand. see [/bdd/README.md](../../../../bdd/README.md) for the +sdk and feature matrix. ## Run locally -note: bdd test expect an iggy-server at tcp://127.0.0.1:8090 +for iterating against a server you started yourself. note: bdd test expect an +iggy-server started with the same root credentials from [/foreign/node](../../) run ```bash npm ci # if not already done -npm run test:bdd +IGGY_TCP_ADDRESS=127.0.0.1:8090 IGGY_ROOT_USERNAME=iggy IGGY_ROOT_PASSWORD=iggy \ + npm run test:bdd ``` diff --git a/foreign/node/src/bdd/auth.ts b/foreign/node/src/bdd/auth.ts index 147327ee1d..c841fb078d 100644 --- a/foreign/node/src/bdd/auth.ts +++ b/foreign/node/src/bdd/auth.ts @@ -20,10 +20,10 @@ import assert from 'node:assert/strict'; import { Client } from '../client/index.js'; import { Given } from "@cucumber/cucumber"; import type { TestWorld } from './world.js'; -import { getIggyAddress } from '../tcp.sm.utils.js'; +import { getRootCredentials, getServerAddress } from './env.js'; -const credentials = { username: 'iggy', password: 'iggy' }; -const [host, port] = getIggyAddress(); +const credentials = getRootCredentials(); +const [host, port] = getServerAddress(); const opt = { transport: 'TCP' as const, diff --git a/foreign/node/src/bdd/env.ts b/foreign/node/src/bdd/env.ts new file mode 100644 index 0000000000..8643b3acc4 --- /dev/null +++ b/foreign/node/src/bdd/env.ts @@ -0,0 +1,40 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +// A default here would turn a dropped compose variable into a run against +// whatever happens to listen on the fallback address, so a missing value +// aborts the suite instead. +const requiredEnv = (name: string): string => { + const value = process.env[name]; + if (!value) + throw new Error(`${name} must be set; run the suite via scripts/run-bdd-tests.sh`); + return value; +}; + +export const getServerAddress = (): [string, number] => { + const address = requiredEnv('IGGY_TCP_ADDRESS'); + const [host, port] = address.split(':'); + if (!host || !port) + throw new Error(`IGGY_TCP_ADDRESS must be "host:port", got "${address}"`); + return [host, parseInt(port, 10)]; +}; + +export const getRootCredentials = () => ({ + username: requiredEnv('IGGY_ROOT_USERNAME'), + password: requiredEnv('IGGY_ROOT_PASSWORD') +}); diff --git a/foreign/php/Dockerfile.test b/foreign/php/Dockerfile.test index 5e759ad45a..0788e43763 100644 --- a/foreign/php/Dockerfile.test +++ b/foreign/php/Dockerfile.test @@ -36,8 +36,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ENV PHP=/usr/bin/php ENV PHP_CONFIG=/usr/bin/php-config -ENV IGGY_HOST=iggy-server -ENV IGGY_PORT=8090 +ENV IGGY_TCP_ADDRESS=iggy-server:8090 WORKDIR /workspace diff --git a/foreign/php/README.md b/foreign/php/README.md index 73a31cfa42..2971890bc1 100644 --- a/foreign/php/README.md +++ b/foreign/php/README.md @@ -80,7 +80,7 @@ The tests assume: - username: `iggy` - password: `iggy` -Override them with `IGGY_HOST`, `IGGY_PORT`, `IGGY_USERNAME`, and `IGGY_PASSWORD`. +Override them with `IGGY_TCP_ADDRESS`, `IGGY_ROOT_USERNAME`, and `IGGY_ROOT_PASSWORD`. ## Usage diff --git a/foreign/php/docker-compose.test.yml b/foreign/php/docker-compose.test.yml index 3831e39bde..6c5903950a 100644 --- a/foreign/php/docker-compose.test.yml +++ b/foreign/php/docker-compose.test.yml @@ -61,10 +61,9 @@ services: networks: - php-test-network environment: - - IGGY_HOST=iggy-server - - IGGY_PORT=8090 - - IGGY_USERNAME=iggy - - IGGY_PASSWORD=iggy + - IGGY_TCP_ADDRESS=iggy-server:8090 + - IGGY_ROOT_USERNAME=iggy + - IGGY_ROOT_PASSWORD=iggy volumes: - ./test-results:/workspace/foreign/php/test-results diff --git a/foreign/php/scripts/test.sh b/foreign/php/scripts/test.sh index effe9e7a06..f01ec8516b 100755 --- a/foreign/php/scripts/test.sh +++ b/foreign/php/scripts/test.sh @@ -21,12 +21,13 @@ set -euo pipefail echo "PHP SDK Test Runner" echo "===================" -IGGY_HOST="${IGGY_HOST:-127.0.0.1}" -IGGY_PORT="${IGGY_PORT:-8090}" +IGGY_TCP_ADDRESS="${IGGY_TCP_ADDRESS:-127.0.0.1:8090}" +host="${IGGY_TCP_ADDRESS%%:*}" +port="${IGGY_TCP_ADDRESS##*:}" -echo "Waiting for Iggy server at ${IGGY_HOST}:${IGGY_PORT}..." +echo "Waiting for Iggy server at ${host}:${port}..." timeout 60 bash -c " - until timeout 5 bash -c 'connect(); - $client->loginUser(env_or_default('IGGY_USERNAME', 'iggy'), env_or_default('IGGY_PASSWORD', 'iggy')); + $client->loginUser(env_or_default('IGGY_ROOT_USERNAME', 'iggy'), env_or_default('IGGY_ROOT_PASSWORD', 'iggy')); $client->ping(); assert_true($client instanceof IggyClient); diff --git a/foreign/php/tests/bootstrap.php b/foreign/php/tests/bootstrap.php index de0866f691..88f63f86e7 100644 --- a/foreign/php/tests/bootstrap.php +++ b/foreign/php/tests/bootstrap.php @@ -84,14 +84,19 @@ function env_or_default(string $name, string $default): string return $value === false || $value === '' ? $default : $value; } +function server_address(): string +{ + return env_or_default('IGGY_TCP_ADDRESS', '127.0.0.1:8090'); +} + function server_host(): string { - return env_or_default('IGGY_HOST', '127.0.0.1'); + return explode(':', server_address(), 2)[0]; } function server_port(): int { - return (int) env_or_default('IGGY_PORT', '8090'); + return (int) (explode(':', server_address(), 2)[1] ?? '8090'); } function wait_for_server(string $host, int $port, int $timeoutSeconds = 30): void @@ -116,9 +121,9 @@ function wait_for_server(string $host, int $port, int $timeoutSeconds = 30): voi function new_client(): IggyClient { - $client = new IggyClient(server_host() . ':' . server_port()); + $client = new IggyClient(server_address()); $client->connect(); - $client->loginUser(env_or_default('IGGY_USERNAME', 'iggy'), env_or_default('IGGY_PASSWORD', 'iggy')); + $client->loginUser(env_or_default('IGGY_ROOT_USERNAME', 'iggy'), env_or_default('IGGY_ROOT_PASSWORD', 'iggy')); return $client; } @@ -127,8 +132,8 @@ function new_connection_string_client(): IggyClient { $host = server_host(); $port = server_port(); - $username = rawurlencode(env_or_default('IGGY_USERNAME', 'iggy')); - $password = rawurlencode(env_or_default('IGGY_PASSWORD', 'iggy')); + $username = rawurlencode(env_or_default('IGGY_ROOT_USERNAME', 'iggy')); + $password = rawurlencode(env_or_default('IGGY_ROOT_PASSWORD', 'iggy')); $client = IggyClient::fromConnectionString("iggy+tcp://{$username}:{$password}@{$host}:{$port}"); $client->connect();