Skip to content

feat: basic functionality - #3

Merged
oswaldom-code merged 63 commits into
mainfrom
develop
Jul 30, 2026
Merged

feat: basic functionality#3
oswaldom-code merged 63 commits into
mainfrom
develop

Conversation

@oswaldom-code

Copy link
Copy Markdown
Owner

No description provided.

Oswaldo Montaño and others added 30 commits November 4, 2025 21:22
Add initial implementation of gtool CLI with basic commands and configuration
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.
Oswaldo Montaño 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'.
@oswaldom-code oswaldom-code changed the title feat: funcionalidad básica feat: basic functionality Jul 30, 2026
@gitguardian

gitguardian Bot commented Jul 30, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
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
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. 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


🦉 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.

@oswaldom-code
oswaldom-code merged commit 766bc74 into main Jul 30, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant