Improve scheduler/oracle test coverage and stabilize CI workflow runtime/toolchain#2
Conversation
Agent-Logs-Url: https://github.com/ServerCrash358/NimbusX/sessions/1d7292c6-4e20-4944-a751-a6e58221bbff Co-authored-by: ServerCrash358 <148064357+ServerCrash358@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR improves reliability and confidence in the scheduler/oracle services by adding targeted Go unit tests and aligning CI tooling/runtime versions with the repo’s current Go/Node requirements.
Changes:
- Added new unit tests covering scheduler scoring/assignment paths, provider manager semantics/handlers, and oracle handlers/pricing helpers.
- Implemented
ProviderManager.GetCount()to support scheduler metrics and fix a build failure. - Updated GitHub Actions workflow to newer
actions/*versions and to use Go fromgo.modplus a pinned Node version for Hardhat.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| scheduler/scoring_test.go | Adds scoring tests for oracle overrides and clamping behavior. |
| scheduler/scheduler_test.go | Adds tests for job submission, handlers, and metrics output. |
| scheduler/provider_manager_test.go | Adds tests for provider lifecycle, handler validation, and JSON responses. |
| scheduler/provider_manager.go | Adds GetCount() for active provider counting (used by metrics). |
| oracle/pricing_test.go | Adds tests for pricing feed contents and jitter bounds. |
| oracle/oracle_test.go | Adds tests for oracle set/get semantics and HTTP endpoints. |
| .github/workflows/ci.yml | Updates action versions and toolchain configuration for Go/Node. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| var entries []PriceEntry | ||
| if err := json.Unmarshal(rec.Body.Bytes(), &entries); err != nil { | ||
| t.Fatalf("decode response: %v", err) | ||
| } | ||
| if len(entries) != 0 { | ||
| t.Fatalf("expected empty array, got %d entries", len(entries)) | ||
| } |
There was a problem hiding this comment.
This test doesn't validate the "array not null" behavior: unmarshalling null into a slice results in nil with len==0, so the test would pass even if the handler encoded null. To assert the response is an empty array, compare the raw body (trimmed) against [], or unmarshal into *[]PriceEntry and ensure the pointer is non-nil.
| s := NewScheduler(pm, "http://127.0.0.1:0", nil) | ||
| job, err := s.SubmitJob(JobSubmitRequest{ | ||
| ClientID: "c1", | ||
| CPURequired: 1, | ||
| MemoryMB: 512, | ||
| MaxDurationSecs: 60, | ||
| MaxPricePerHour: 1, | ||
| }) |
There was a problem hiding this comment.
This test submits a job while the scheduler is configured with oracleURL set to http://127.0.0.1:0. During assignment, fetchOraclePrice will attempt a real HTTP request to that address (connection error -> fallback), introducing unnecessary network dependency/slowness. Consider using an httptest.Server (even one returning 404/empty) for oracleURL so the test stays fully hermetic.
| if results[0].Provider.ID != "p1" { | ||
| t.Fatalf("expected p1 to score higher with oracle price override, got %s", results[0].Provider.ID) | ||
| } |
There was a problem hiding this comment.
ScoreProviders returns results in the same order as the input slice and does not rank/sort them. This test currently asserts results[0] is p1, which will be true even if p1 scores lower. Sort results by Score before asserting the top provider, or compare the computed scores directly (e.g., results[0].Score > results[1].Score after locating entries by ID).
| if results[0].Provider.ID != "p1" { | |
| t.Fatalf("expected p1 to score higher with oracle price override, got %s", results[0].Provider.ID) | |
| } | |
| var p1Result, p2Result *ScoredProvider | |
| for i := range results { | |
| switch results[i].Provider.ID { | |
| case "p1": | |
| p1Result = &results[i] | |
| case "p2": | |
| p2Result = &results[i] | |
| } | |
| } | |
| if p1Result == nil || p2Result == nil { | |
| t.Fatalf("expected results for both p1 and p2") | |
| } | |
| if p1Result.Score <= p2Result.Score { | |
| t.Fatalf("expected p1 to score higher with oracle price override, got p1=%f p2=%f", p1Result.Score, p2Result.Score) | |
| } |
| var providers []Provider | ||
| if err := json.Unmarshal(rec.Body.Bytes(), &providers); err != nil { | ||
| t.Fatalf("decode response: %v", err) | ||
| } | ||
| if len(providers) != 0 { | ||
| t.Fatalf("expected empty provider list, got %d", len(providers)) | ||
| } |
There was a problem hiding this comment.
This test doesn't actually distinguish between null and [] in the JSON response: unmarshalling null into a slice yields a nil slice with len==0, so the assertion still passes. To verify the handler returns an empty array, inspect the raw response bytes (after trimming whitespace) and assert it equals [], or unmarshal into *[]Provider and assert the pointer is non-nil.
| var providers []Provider | |
| if err := json.Unmarshal(rec.Body.Bytes(), &providers); err != nil { | |
| t.Fatalf("decode response: %v", err) | |
| } | |
| if len(providers) != 0 { | |
| t.Fatalf("expected empty provider list, got %d", len(providers)) | |
| } | |
| body := strings.TrimSpace(rec.Body.String()) | |
| if body != "[]" { | |
| t.Fatalf("expected empty JSON array [], got %q", body) | |
| } |
This PR addresses low Go test coverage in core runtime packages and resolves CI instability in the existing pipeline. It adds targeted unit coverage for scheduler/oracle logic and updates workflow runtime/toolchain configuration to match current project and ecosystem requirements.
Coverage expansion: scheduler core paths
Coverage expansion: scoring and oracle behavior
Build/CI correctness fixes
ProviderManager.GetCount()used by scheduler metrics (removes scheduler package build failure in test job).actions/checkout→ v4actions/setup-go→ v5 withgo-version-file: go.modactions/setup-node→ v4 with Node22.10.0(Hardhat-compatible)Example of the scheduler build fix: