-
Notifications
You must be signed in to change notification settings - Fork 51
test(nvsnap): refuse to measure a cold start as a restore #965
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
a382620
69cc273
acf41fe
a555532
0469cda
ea340eb
f72f3f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| /* | ||
| SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| Licensed 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 agent | ||
|
|
||
| import ( | ||
| "context" | ||
| "strings" | ||
| "testing" | ||
| ) | ||
|
|
||
| // Whole-rootfs capture must not start by accident. It succeeds quietly -- | ||
| // producing a capture that restores -- so a cluster whose cachedir setting was | ||
| // dropped keeps running while diverging from every workload and benchmark that | ||
| // assumes cachedir. The agent refuses at startup instead. | ||
| func TestStartRootfsCaptureRefusesWholeRootfs(t *testing.T) { | ||
| a := &Agent{} | ||
| _, err := a.startRootfsCapture(context.Background(), RootfsCaptureConfig{ | ||
| Enabled: true, // no PodCacheDir, no override | ||
| }) | ||
| if err == nil { | ||
| t.Fatal("expected refusal when --pod-cache-dir is unset; whole-rootfs must be opt-in") | ||
| } | ||
| for _, want := range []string{"pod-cache-dir", "allow-whole-rootfs"} { | ||
| if !strings.Contains(err.Error(), want) { | ||
| t.Errorf("error should tell the operator about %q, got: %v", want, err) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // The override exists so an operator can still run that path deliberately. | ||
| // It must get past the guard -- failing later for an unrelated reason (no | ||
| // kube client in a unit test) is fine; failing *at the guard* is not. | ||
| func TestStartRootfsCaptureAllowsExplicitOptIn(t *testing.T) { | ||
| a := &Agent{} | ||
| _, err := a.startRootfsCapture(context.Background(), RootfsCaptureConfig{ | ||
| Enabled: true, | ||
| AllowWholeRootfs: true, | ||
| }) | ||
| if err != nil && strings.Contains(err.Error(), "whole-rootfs capture is not supported") { | ||
| t.Fatalf("explicit opt-in must pass the guard, got: %v", err) | ||
| } | ||
| } | ||
|
|
||
| // Disabled stays a clean no-op: the guard must not turn "capture off" into an | ||
| // error for every agent that does not run capture at all. | ||
| func TestStartRootfsCaptureDisabledIsNoop(t *testing.T) { | ||
| a := &Agent{} | ||
| b, err := a.startRootfsCapture(context.Background(), RootfsCaptureConfig{Enabled: false}) | ||
| if err != nil || b != nil { | ||
| t.Fatalf("disabled capture should be a no-op, got backend=%v err=%v", b, err) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -19,6 +19,7 @@ package agent | |||||||||||||||
|
|
||||||||||||||||
| import ( | ||||||||||||||||
| "context" | ||||||||||||||||
| "strings" | ||||||||||||||||
| "testing" | ||||||||||||||||
|
|
||||||||||||||||
| "github.com/sirupsen/logrus" | ||||||||||||||||
|
|
@@ -38,8 +39,17 @@ func TestStartRootfsCapture_EnabledFailsWithoutKubeConfig(t *testing.T) { | |||||||||||||||
| t.Setenv("KUBECONFIG", "/nonexistent/kubeconfig") | ||||||||||||||||
| t.Setenv("HOME", t.TempDir()) // hide any ~/.kube/config the test runner has | ||||||||||||||||
| a := &Agent{config: Config{}, log: logrus.New()} | ||||||||||||||||
| _, err := a.startRootfsCapture(context.Background(), RootfsCaptureConfig{Enabled: true}) | ||||||||||||||||
| // PodCacheDir is set so the whole-rootfs guard does not answer first. | ||||||||||||||||
| // Without it this test would still fail -- but on the guard, not on the | ||||||||||||||||
| // kube client it is named for, and the coverage would be gone silently. | ||||||||||||||||
| _, err := a.startRootfsCapture(context.Background(), RootfsCaptureConfig{ | ||||||||||||||||
| Enabled: true, | ||||||||||||||||
| PodCacheDir: "/opt/nvsnap", | ||||||||||||||||
| }) | ||||||||||||||||
| if err == nil { | ||||||||||||||||
| t.Fatal("expected kube client construction error when no config available") | ||||||||||||||||
| } | ||||||||||||||||
| if strings.Contains(err.Error(), "whole-rootfs") { | ||||||||||||||||
| t.Fatalf("guard fired instead of the kube client path; this test no longer covers what it claims: %v", err) | ||||||||||||||||
| } | ||||||||||||||||
|
Comment on lines
+52
to
+54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Assert the kube-client error path directly. The current assertion only rejects the whole-rootfs guard. A different early error could make this test pass without covering Proposed test assertion- if strings.Contains(err.Error(), "whole-rootfs") {
- t.Fatalf("guard fired instead of the kube client path; this test no longer covers what it claims: %v", err)
+ const want = "rootfsonly: build kube client:"
+ if !strings.Contains(err.Error(), want) {
+ t.Fatalf("expected kube client construction error containing %q; got %v", want, err)
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||
| } | ||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Preserve kube-client failure coverage.
Line 104 now intercepts
TestStartRootfsCapture_EnabledFailsWithoutKubeConfigbeforebuildKubeClient. Update that test to setPodCacheDirorAllowWholeRootfs: true, so it still verifies the kube-client configuration error described by its name and comments.As per path instructions, "Add or update tests for behavior changes."
🤖 Prompt for AI Agents
Source: Path instructions