feat: basic functionality - #3
Merged
Merged
Conversation
…guration management
Add initial implementation of gtool CLI with basic commands and configuration
…SQL integration tests
Feature/initial project
Extract Docker client, plugin registry and mock manager wiring into a package-level depsFactory (newServiceDeps). Command bodies now depend on a serviceManager interface instead of the concrete *mock.Manager, so the RunE handlers can be unit-tested with a Docker-free fake. No behavior change: error messages, the up-only daemon ping and the per-command loggers are preserved.
Cover internal/core/mock and internal/cli/services, the Phase 2 code that previously had 0% coverage: - mock.Manager: start/stop lifecycle, health-check retries, context cancellation, status, logs, ListRunning and parallel/sequential StartAll (89.9% coverage, runs clean under -race). - services commands: up/down/status/logs RunE paths via an injected fake manager, plus formatDuration and loadConfigOrDefault (86.8%).
Implement the Mountebank ServicePlugin following the PostgreSQL pattern: container lifecycle via the Docker client, an HTTP readiness probe against the admin API (port 2525) and imposter loading from JSON files posted to /imposters. Register it in RegisterAll alongside PostgreSQL. Includes unit tests for the Docker-free surface and a build-tagged integration test with a sample imposter fixture.
logger.NewDevelopment does not exist in pkg/logger, so the integration test failed to compile under -tags=integration (unnoticed because the build tag excludes it from the default suite). Switch to logger.Default().Logger.
Implement a single-node Kafka broker plugin in KRaft mode following the established ServicePlugin pattern. Uses dual PLAINTEXT listeners: INTERNAL for in-container admin operations (readiness probe and topic creation via kafka-topics.sh) and EXTERNAL advertised on the configured host port for host clients, so it works regardless of the host port mapping. Supports configurable topics and partitions, created on launch. Register it in RegisterAll alongside PostgreSQL and Mountebank. Includes unit tests for the Docker-free surface (config parsing, broker env, connection info) and a build-tagged integration test.
Implement a single-node Couchbase Server plugin following the established ServicePlugin pattern. Unlike the other services, Couchbase requires post-start cluster provisioning: initializeCluster runs couchbase-cli cluster-init with retries (it fails until the REST API is up and succeeds once ready, doubling as the readiness wait), then a bucket is created. Health checks use couchbase-cli server-info. Configurable image, ports, credentials, services, RAM quotas and bucket. Register it in RegisterAll. Includes unit tests for the Docker-free surface and a build-tagged integration test. Scopes/collections and JSON data loading are deferred to a follow-up.
added 27 commits
June 27, 2026 02:10
Move the local-process launch/stop/restart/readiness logic out of GenericLauncher into a reusable processLauncher parameterized by a readiness probe. GenericLauncher now embeds it and supplies a TCP probe. No behavior change; existing tests pass via method promotion. Prepares for additional technology launchers that differ only in their readiness check.
Add GolangLauncher for running a compiled Go application as the application under test. It embeds the shared processLauncher and supplies an HTTP readiness probe: any HTTP response (including 4xx/5xx) means the server is accepting requests, distinguishing it from the generic TCP probe. Unit-tested with a real httptest server (91% package coverage, clean under -race).
Add DockerManager: runs the application under test as a labelled Docker container so separate CLI invocations can find it (start/stop/restart/ status/logs), mirroring the mock services lifecycle. The Docker client is accessed through a small interface so it is unit-tested with a fake (88% package coverage).
Replace the app command stubs with a real implementation wired to the Docker-backed app manager, following the services command pattern: thin RunE handlers over an injectable deps factory, with --docker-image/--port/ --env flags overriding the file config. Unit-tested with a fake manager (87% coverage).
DockerManager.Status reported Ports[0], which can be an unmapped exposed port (PublicPort 0) — e.g. nginx exposes 80/tcp ahead of the published mapping, so status showed no port. Pick the first port with a non-zero PublicPort instead. Found while validating the lifecycle against a real nginx container.
Implement the Phase 5 orchestrator: it starts the configured mocks, starts the application, runs the tests, and always tears everything down in reverse order — including on failure or context cancellation (cleanup uses a fresh context). Mocks/app/tests are accessed through interfaces so the pipeline is unit-tested with fakes (96% coverage). Test execution is a StubTestRunner that logs and returns an empty result until the Phase 4 Karate executor lands.
Wire the orchestrator behind a single 'gtool test' command: it loads the config, builds the real mock manager, app manager and stub test runner via an injectable factory, and runs the pipeline with SIGINT/SIGTERM handling so Ctrl-C triggers an orderly teardown. Validated end-to-end against Docker (postgresql mock + nginx app). Unit-tested with a fake pipeline.
The persistent --config flag is parsed after the commands are constructed, so copying *configFile at construction captured an empty string and the flag was silently ignored. Keep the pointer and dereference it at run time (matching the test command), so 'gtool services'/'gtool app --config X' actually load X. Found while validating the test pipeline.
Add KarateRunner, which runs the test-launcher-back container against the already-running app and mocks (host networking so tests reach localhost), mounting the feature files and reports directory per the launcher contract and passing TAGS. The outcome is derived from the container exit code; a non-zero code yields a failure carrying the log tail. With no features-path configured it skips gracefully. Satisfies the orchestrator TestRunner interface. Unit-tested with a fake Docker client (pass/fail/skip/infra errors, 86% coverage). The launcher image is internal, so end-to-end validation against the real image is left to the team.
Replace the stub test runner with the Karate executor in the test pipeline, and make 'gtool test' exit non-zero when tests fail (so CI catches failures). Validated end-to-end: the pipeline starts mocks and the app, and the Karate runner skips cleanly when no features are configured.
Add examples/postgres-app: a minimal Go HTTP service backed by PostgreSQL (health, list/create users) with its own go.mod, a Dockerfile, seed SQL, a Karate feature and a gtool component-config.yml. It serves as a realistic application under test for the gtool pipeline (mock PostgreSQL -> app -> tests). Validated end to end against a real PostgreSQL: /health, /users and POST /users all work. Update the CLAUDE.md directive to allow self-contained sample apps under examples/ (each with its own go.mod) instead of forbidding examples outright.
Reproduce the legacy "go-tool u" workflow inside gtool: generate the mocks declared in build-config.yml (mockgen, resolving <COMMON-LIB> and sibling wildcards from go.mod) and run the unit suite with Ginkgo using the same flags (recursive, coverage profile and JUnit report under ./coverage). Tool versions are pinned to match the legacy behaviour.
Add EnsureImage/ImageExists so containers reuse a locally present image instead of always pulling (required for private STABLE images and freshly built ones), and wire the postgresql, pubsub and mountebank plugins to it. Also add RemoveContainerByName (exact-name match) and ContainerConfig.Init to support the legacy mock contract.
Add a stablemocks launcher and a 'gtool services up/down --stable' flag that drives the private third-party STABLE mock images with the exact legacy contract: postgresql (-p 5432, /data mount, log readiness), pubsub (-p 9085, PROJECT_ID + TOPICS built from config) and mountebank (host network, /imposters mount), using fixed container names, --init and the local image when available. The default native plugin path is unchanged.
Reproduce the legacy "component r/p" golang app launcher: 'gtool app start/stop --native' starts each binary listed in build-config.yml from $GOPATH/bin as a detached process on an incrementing port (8080+), with CUSTOM_SERVER_ADDRESS (7080+) and the PUBSUB/STORAGE emulator host env vars, and stops them by name. The default docker-image path is unchanged.
Reproduce the legacy "component e" test step: run the test-launcher-back (Karate) STABLE image on the host network against the already-running mocks and app, mounting test/component/features and writing the HTML report to test/component/reports. Uses the full image ref with skip-pull, sets PUBSUB_EMULATOR_HOST/TAGS/URLS_TO_BLOCK, and opens the generated karate-summary.html in the browser (disable with --no-open).
Add 'gtool test --stable', reproducing the legacy "component t" in one command: start the STABLE mocks, launch the native app and run Karate, then always tear app and mocks down (LIFO defers run on test failure and on Ctrl-C). Flags: --tags, --build-config and --no-open.
- stablekarate: hand the report tree back to the invoking user via a short-lived root container (chown), so the root-written report is readable/openable and the next run's cleanup succeeds. Replaces the legacy "sudo rm -rf". Adds Entrypoint/User support to the Docker client. - nativeapp: poll the primary service port until it accepts connections instead of a blind fixed sleep, then proceed (best-effort on timeout).
Replace the private test-launcher-back:STABLE image with an in-repo, drop-in launcher under test-launcher/ (JDK 21, Karate 1.5.2 via io.karatelabs), built as gtool/test-launcher-back:latest and now the default in karate.go and stablekarate/runner.go. Add a test-launcher-image Makefile target. Add redis, mongodb, mysql and minio mock service plugins (following the postgresql pattern), register them in RegisterAll, and extend the supported mocks in the config validator.
Move the Spanish README to docs/readme/README.es.md, add English as the primary root README, and cross-link both with a language selector.
…ooling Lead with what GTOOL is (a component-testing orchestrator), correct the mock count to 10, and mention unit tests and the plugin interface. Remove the legacy-flow reproduction section and its scattered references across both README languages.
- Switch `stablemocks` launcher to use official public Docker images for PostgreSQL, PubSub, and Mountebank instead of private STABLE images. - Add HTTP-based readiness checks to the launcher to support the PubSub emulator. - Provision PubSub topics and subscriptions dynamically via the emulator's REST API instead of using legacy environment variables. - Update `services up` and `services down` CLI help text for the `--stable` flag to reflect the shift to fixed-contract public mocks.
Match the module path to the canonical repository URL so the tool can be installed with 'go install github.com/oswaldom-code/gtool/cmd/gtool@latest'.
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 22285005 | Triggered | Generic Password | 568b82c | internal/cli/generate/templates/component-config.yml | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.