test: comprehensive test coverage improvement (60% → 82.5%)#502
test: comprehensive test coverage improvement (60% → 82.5%)#502
Conversation
- Snapshot onJobComplete callback under s.mu.RLock in runWithCtx to prevent a data race if SetOnJobComplete is called concurrently - Document why DisableJob/EnableJob holding s.mu while calling go-cron's PauseEntryByName/ResumeEntryByName is deadlock-free - Document the concurrency semantics of concurrencySemaphore.resize (safe before Start, best-effort after) - Add rationale comment for BuildWorkflowDependencies fail-open design
- Fix TestSchedulerStart_TriggeredJobStartup: remove dead code (unused completedJobs map and completedMu), add assertions for regularStartup execution and completedCount callback verification - Fix TestStopWithTimeout_Timeout: add meaningful assertions verifying timeout error is returned, function returns promptly, and scheduler stops accepting new jobs after timeout - Add TestCollectDependencyEdges_NonBareJobSkipped: verify non-BareJob types are gracefully skipped (no edges, no panic) - Add TestCollectDependencyEdges_MixedJobTypes: verify mixed job types only collect edges from *BareJob instances - Add TestWireEdges_NonCycleError: verify ErrWorkflowInvalid is returned for non-cycle errors (entry not found in cron) - Add TestDisableJob_Idempotent: verify calling DisableJob twice on same job does not error and job state remains consistent - Add t.Parallel() to all 22 web/server_test.go top-level tests and verify workflow_test.go already has t.Parallel() everywhere
- Add validateJobName check to createJobHandler (was missing while other handlers already had it) - Protect Server.origins map with sync.RWMutex to prevent concurrent map access panics from HTTP handler goroutines - Add Collector.adjustGauge method to atomically read+write gauge values, fixing TOCTOU race in RecordJobStart, RecordJobComplete, JobMetrics.JobStarted, and JobMetrics.JobCompleted
- Guard IsRunning() against nil cron field, matching IsJobRunning() and EntryByName() patterns - Remove unused wg sync.WaitGroup field and its Wait() calls from StopWithTimeout and StopAndWait (no Add/Done calls exist after migration to go-cron lifecycle management) - Copy dockerOpsCount and dockerErrorsCount maps in GetDockerMetrics() before returning, preventing data races after the RLock is released
- Fix nil pointer dereference in authStatusHandler when ValidateToken returns nil data for expired/invalid tokens - Add POST method enforcement on all mutation endpoints (run, disable, enable, create, update, delete) to reject non-POST requests with 405 - Add done channel to rateLimiter to stop cleanup goroutine on shutdown, preventing goroutine leaks; close old rate limiter in RegisterHealthEndpoints before creating a new one
- Change ValidateCSRFToken from RLock to Lock since delete() is a write operation, fixing a data race - Also delete expired CSRF tokens in ValidateCSRFToken early-return path - Add done channel and Close() method to SecureTokenManager so the cleanup goroutine can be stopped, preventing goroutine leaks - Call tokenManager.Close() in Server.Shutdown for proper cleanup - Make rateLimiter.close() idempotent via sync.Once to prevent panics on double-close
…ator Add unit tests for previously uncovered easy-win targets: - core/domain: errors (typed errors + helpers), events, image parsing, task states, exec hijacked response - core/ports: Docker client functional options - test: all testlogger Handler methods and assertion helpers - test/testutil: T.Failed(), WithMessage, EventuallyWithT timeout, Never immediate-true - config: validateSliceField with string/int/empty/nil slices Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Add 102 unit tests across 6 files covering core job types: - runjob_unit_test.go: RunJob lifecycle (create, start, wait, logs, delete), container building, image handling, max runtime timeout - execjob_unit_test.go: ExecJob exit code handling, RunWithStreams, InitializeRuntimeFields - runservice_unit_test.go: RunServiceJob service lifecycle, build, task status tracking, timeout, delete with not-found handling - resilient_job_test.go: ResilientJobExecutor with retry, rate limiting, non-retryable errors, metrics recording - shutdown_unit_test.go: ShutdownManager signals, hook priorities, timeout, GracefulServer/Scheduler graceful stop, concurrent shutdown safety - clock_unit_test.go: RealClock, FakeClock, CronClock timers, tickers, sleep edge cases (zero/negative), multiple timer coordination All tests use table-driven subtests with t.Parallel() and the existing mock infrastructure (mock.DockerClient with type assertions, test.Handler). Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Add table-driven tests for webhook, preset, dedup, sanitize middleware packages plus ContinueOnStop method tests for all middleware types. Coverage targets: - webhook_test.go: WebhookManager.GetMiddlewares/GetGlobalMiddlewares, NewWebhookMiddleware, ContinueOnStop, Run dispatching, getJobType (all 5 variants), getExecutionStatus, ParseWebhookNames - preset_test.go: AddLocalPresetDir, loadFromFile (valid/missing/invalid), loadFromGitHub (remote disabled/untrusted), loadFromURL (httptest server, non-200, remote disabled, SSRF blocked), isTrustedSource, matchGlobPattern - dedup_test.go: DedupStore.Len, InitNotificationDedup, StartCleanupRoutine - sanitize_test.go: SanitizePath, SanitizeFilename package-level wrappers - ContinueOnStop: Mail (true), Overlap (false), Save (true), Slack (true) Signed-off-by: Sebastian Mendel <sebastian.mendel@netresearch.de> Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Phase 4 - CLI package: - config_validate_ext_test.go: validateDurationGTE (above/equal/below min, zero boundaries, large duration), invalid param, non-struct validation error path, formatValidationError all tag branches - daemon_ext_test.go: restoreJobHistory (disabled, enabled-no-files, nonexistent folder), waitForServerWithErrChan error channel, applyOptions (nil config, all fields), applyConfigDefaults, Config accessor - doctor_ext_test.go: checkDockerImages (no RunJobs skip, config parse error, Docker init error), checkDocker (no Docker jobs skip, config parse error), checkSchedules config error, checkWebAuth (missing username, missing password, auth disabled), outputJSON, outputHuman - config_ext_test.go: BuildFromFile (invalid glob, missing file, invalid INI, multiple files), BuildFromString (invalid syntax, unknown keys), resolveConfigFiles, latestChanged, iniConfigUpdate, parseGlobalAndDocker, getKnownKeysForJobType, logUnknownKeyWarnings, logJobUnknownKeyWarnings - progress_ext_test.go: ProgressIndicator update/stop/start terminal and non-terminal modes, ProgressReporter step/complete/renderProgressBar Phase 5 - Web package: - auth_secure_ext_test.go: CleanupOldLimiters, ValidateCSRFToken (valid, one-time, missing, expired), cleanup expired tokens/CSRF, HashPassword, empty secret key, Close multiple, RevokeToken, getClientIP - server_ext_test.go: csrfTokenHandler (no auth, with auth), authStatusHandler (unauthenticated, no auth, invalid token), method-not-allowed for run/disable/enable job handlers Phase 6 - Metrics package: - prometheus_ext_test.go: RecordJobStart counter+gauge, RecordJobComplete all fields including panic/zero/large duration, RecordJobScheduled, adjustGauge (non-existent, wrong type), full lifecycle integrity Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
… (phases 7-8) Phase 7: Docker adapter conversion function tests (pure, no Docker daemon) - container_convert_test.go: convertToContainerConfig, convertToHostConfig, convertToNetworkingConfig, convertToEndpointSettings, convertToPortMap, convertToMount - service_convert_test.go: convertToSwarmSpec, convertFromSwarmService, convertFromSwarmTask Phase 8: Extend partial coverage across cli and middleware packages - cli/config_decode_test.go: weakDecodeConsistent, extractMapstructureKeys, mergeUsedKeys - middlewares/mail_test.go: from() formatting, ContinueOnStop, only-on-error, executionLabel - middlewares/save_test.go: ContinueOnStop, RestoreHistory config, save-on-error with failure - middlewares/restore_test.go: empty job name, non-JSON files, multi-job, corrupted fields - middlewares/preset_cache_test.go: corrupted metadata, URL collision, expired disk, isMetaFile - middlewares/webhook_config_test.go: negative values, URL-only, all triggers, preserve defaults - middlewares/webhook_security_test.go: whitelist blocking, invalid schemes, test overrides Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
- Remove Go 1.22+ copyloopvar in shutdown test - Fix misspelling (sanitises -> sanitizes) - Use testifylint-compliant assertions (InDelta, Less, Positive, Empty, require.Error) - Fix gci/gofumpt import ordering and formatting - Refactor duplicate enable/disable handlers into toggleJobHandler Signed-off-by: Sebastian Mendel <sebastian.mendel@netresearch.de> Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Signed-off-by: Sebastian Mendel <sebastian.mendel@netresearch.de> Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
✅ Mutation Testing ResultsMutation Score: 86.67% (threshold: 60%)
What is mutation testing?Mutation testing measures test quality by introducing small changes (mutations) to the code and checking if tests detect them. A higher score means better test effectiveness.
|
There was a problem hiding this comment.
Pull request overview
This PR substantially increases automated test coverage across the Ofelia codebase while also hardening several runtime paths (web server request handling, token/rate-limiter lifecycle, scheduler concurrency, and metrics gauge updates).
Changes:
- Add extensive new/extended unit tests across core, web, middlewares, cli, config, metrics, and adapter packages to raise total coverage to ~82.5%.
- Harden web server behavior: validate job names, enforce HTTP methods, improve status codes, prevent auth/status panic, and add shutdown cleanup for background goroutines.
- Improve concurrency safety in several components (origins map locking, CSRF token validation mutation locking, atomic gauge adjustments, scheduler callback snapshotting, map-copying in metrics).
Reviewed changes
Copilot reviewed 51 out of 51 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| web/server.go | Adds job-name validation, method checks, safer error/status handling, origins map locking, and cleanup of token/rate-limiter goroutines on shutdown. |
| web/middleware.go | Adds stoppable rate-limiter cleanup goroutine and documents X-Forwarded-For trust assumptions. |
| web/auth_secure.go | Makes CSRF validation safe for one-time-use + expiry cleanup; adds Close() to stop cleanup goroutine. |
| web/server_test.go | Marks many existing web server tests as parallel; updates expectations for new HTTP status semantics. |
| web/server_more_test.go | Aligns run/update handler expectations with new status-code behavior. |
| web/server_mutation_test.go | Adds validateJobName edge-case coverage. |
| web/server_ext_test.go | Adds coverage for CSRF/auth endpoints and method-not-allowed paths. |
| web/auth_secure_ext_test.go | Adds unit coverage for secure auth helpers (CSRF, token cleanup, hashing, IP parsing). |
| test/testutil/eventually_test.go | Adds tests for Eventually/Never helpers and error-collecting test harness behavior. |
| test/testlogger_test.go | Adds comprehensive tests for test logger/handler utilities. |
| middlewares/webhook_test.go | Adds additional table-driven coverage for webhook manager/middleware helpers. |
| middlewares/webhook_security_test.go | Adds coverage for additional validation branches and test override hooks. |
| middlewares/webhook_config_test.go | Adds coverage for config validation/default behaviors and triggers. |
| middlewares/slack_test.go | Adds ContinueOnStop coverage. |
| middlewares/save_test.go | Adds ContinueOnStop + restore/save edge-case coverage. |
| middlewares/sanitize_test.go | Adds package-level sanitizer function coverage. |
| middlewares/restore_test.go | Adds coverage for restore edge cases (skips, multi-job matching, corrupted JSON). |
| middlewares/preset_test.go | Adds coverage for preset loader paths (file, GitHub/url, trust matching, parsing defaults). |
| middlewares/preset_cache_test.go | Adds coverage for cache disk error paths and isMetaFile classification. |
| middlewares/overlap_test.go | Adds ContinueOnStop coverage. |
| middlewares/mail_test.go | Adds ContinueOnStop + additional mail/config logic coverage. |
| middlewares/dedup_test.go | Adds coverage for store length, init behavior, and cleanup routine. |
| metrics/prometheus.go | Introduces atomic gauge adjustment helper to avoid TOCTOU races for running-gauge updates. |
| metrics/prometheus_test.go | Adds unit coverage for RecordJobStart/Complete/Scheduled lifecycle hooks. |
| metrics/prometheus_ext_test.go | Adds additional edge-case coverage for job lifecycle metrics and adjustGauge behavior. |
| core/scheduler.go | Adds nil-safe IsRunning, improves onJobComplete callback race safety, updates concurrency comments, and enables idempotent EnableJob for already-active jobs. |
| core/scheduler_mutation_test.go | Extends scheduler mutation coverage (startup behavior, idempotency, stop timeout determinism, job lookup fallbacks, active/any job getters). |
| core/workflow_test.go | Adds edge-case coverage for workflow edge collection and wiring error classification. |
| core/performance_metrics.go | Avoids post-lock data races by returning copies of internal docker ops/error maps. |
| core/common.go | Replaces magic struct-tag string with a constant for hashing tag checks. |
| core/shutdown_unit_test.go | Adds unit coverage for shutdown manager + graceful server/scheduler behavior. |
| core/clock_unit_test.go | Adds coverage for real/fake/cron clock behavior. |
| core/execjob_unit_test.go | Adds unit coverage for ExecJob behavior and exit-code handling using mocks. |
| core/runservice_unit_test.go | Adds unit coverage for RunServiceJob behavior and error paths using mocks. |
| core/resilient_job_test.go | Adds coverage for resilient executor behavior (retry, rate limit, metrics recording). |
| core/ports/docker_test.go | Adds unit coverage for docker client option helpers. |
| core/domain/errors_test.go | Adds unit coverage for domain errors and helper predicates. |
| core/domain/event_test.go | Adds unit coverage for event helper methods. |
| core/domain/exec_test.go | Adds unit coverage for HijackedResponse close semantics. |
| core/domain/image_test.go | Adds unit coverage for repository/tag parsing behavior. |
| core/domain/service_test.go | Adds unit coverage for terminal task state classification. |
| core/adapters/docker/service_convert_test.go | Adds broad conversion coverage between domain and swarm types. |
| config/validator_test.go | Adds coverage for slice-field validation behavior. |
| cli/config_ext_test.go | Adds coverage for config build/update, glob resolution, warnings, and metadata handling. |
| cli/config_decode_test.go | Adds coverage for weak decode and metadata extraction/merging edge cases. |
| cli/config_validate_ext_test.go | Adds coverage for duration validator + error formatting branches. |
| cli/daemon_ext_test.go | Adds coverage for daemon option application and history restore behavior. |
| cli/doctor_ext_test.go | Adds coverage for doctor command checks and output formatting paths. |
| cli/progress_ext_test.go | Adds coverage for terminal/non-terminal progress indicator and reporter logic. |
Merging this PR will improve performance by ×18
Performance Changes
Comparing |
|
🚀 Released in v0.21.0 Thank you for your contribution! 🙏 This is now available in the latest release. Please test and verify everything works as expected in your environment. If you encounter any issues, please open a new issue. |
Summary
toggleJobHandlerCoverage by Package
core/domaincore/portsmetricstestconfigcore/adapters/mocktest/testutilcoremiddlewareswebcliNew Test Files (26 files)
Phase 1 - Domain & Ports:
core/domain/{errors,event,exec,image,service}_test.gocore/ports/docker_test.go,test/testlogger_test.goPhase 2 - Core Jobs:
core/{runjob,execjob,runservice}_unit_test.gocore/{resilient_job,shutdown_unit,clock_unit}_test.goPhase 3 - Middlewares:
middlewares/{webhook,preset,dedup,sanitize,mail,overlap,save,slack}_test.goPhase 4-6 - CLI, Web, Metrics:
cli/{config_ext,config_validate_ext,daemon_ext,doctor_ext,progress_ext}_test.goweb/{auth_secure_ext,server_ext}_test.go,metrics/prometheus_ext_test.goPhase 7-8 - Docker Adapter & Partials:
core/adapters/docker/{container_convert,service_convert}_test.gocli/config_decode_test.go,middlewares/{restore,preset_cache,webhook_config,webhook_security}_test.goTest plan
go test ./... -count=1(14 packages OK)golangci-lint run ./...(0 issues)t.Parallel()throughout