diff --git a/cns/restserver/persistent_state_test.go b/cns/restserver/persistent_state_test.go index 2b1953b939..d5bef86018 100644 --- a/cns/restserver/persistent_state_test.go +++ b/cns/restserver/persistent_state_test.go @@ -22,6 +22,11 @@ var ( errSnapshotProvider = errors.New("provider failure") ) +const ( + persistentStateTestNetwork = "network" + persistentStateTestNestedKey = "nested" +) + func TestPersistentStateHandlerConstructors(t *testing.T) { statusHandler, err := NewPersistentStateStatusHandler(nil) require.Error(t, err) @@ -109,7 +114,7 @@ func TestPersistentStateHandlersProviderErrors(t *testing.T) { status int body string }{ - {name: "canceled", err: context.Canceled, status: http.StatusRequestTimeout, body: "request canceled\n"}, + {name: delTestCanceled, err: context.Canceled, status: http.StatusRequestTimeout, body: "request canceled\n"}, {name: "deadline", err: context.DeadlineExceeded, status: http.StatusRequestTimeout, body: "request canceled\n"}, {name: "provider", err: errPersistentStateProvider, status: http.StatusServiceUnavailable, body: "persistent state unavailable\n"}, } @@ -192,8 +197,8 @@ func TestPersistentStateSnapshotHandlerErrors(t *testing.T) { t.Run("encoding", func(t *testing.T) { snapshot := state.NewSnapshot() - snapshot.Networks["network"] = state.NetworkRecord{ - NetworkName: "network", + snapshot.Networks[persistentStateTestNetwork] = state.NetworkRecord{ + NetworkName: persistentStateTestNetwork, Options: map[string]any{"unsupported": make(chan struct{})}, } handler, err := NewPersistentStateSnapshotHandler(func(context.Context) (state.Snapshot, error) { @@ -210,13 +215,17 @@ func TestPersistentStateSnapshotHandlerErrors(t *testing.T) { t.Run("recursive sanitizer", func(t *testing.T) { document := map[string]any{ "AuthorizationToken": "secret", - "nested": []any{ + persistentStateTestNestedKey: []any{ map[string]any{"authorizationtoken": "another"}, }, } removeAuthorizationTokens(document) assert.NotContains(t, document, "AuthorizationToken") - assert.NotContains(t, document["nested"].([]any)[0].(map[string]any), "authorizationtoken") + assert.NotContains( + t, + document[persistentStateTestNestedKey].([]any)[0].(map[string]any), + "authorizationtoken", + ) }) } diff --git a/cns/state/cni_import_test.go b/cns/state/cni_import_test.go index 1f0dc6c917..26531c5f8d 100644 --- a/cns/state/cni_import_test.go +++ b/cns/state/cni_import_test.go @@ -7,6 +7,7 @@ import ( "context" "encoding/json" "errors" + "math" "net" "sort" "sync" @@ -22,6 +23,11 @@ var errInjectedCNIImport = errors.New("injected commit failure") const cniImportTestSecondaryInterface = "net1" +func TestCNIImportCountsRejectOverflow(t *testing.T) { + _, err := cniImportCounts(NewSnapshot(), math.MaxInt) + require.ErrorIs(t, err, ErrInvalidInput) +} + func TestCNIEndpointImportPreflightAndAtomicImport(t *testing.T) { db, _ := openTestDB(t) seedCNIImportInventory(t, db) diff --git a/cns/state/coverage_test.go b/cns/state/coverage_test.go index 1d8c92d2cc..1a859ccc68 100644 --- a/cns/state/coverage_test.go +++ b/cns/state/coverage_test.go @@ -28,11 +28,31 @@ const ( hardeningContainerID2 = "container-2" hardeningMultipleValues = "multiple values" hardeningUnsupportedOption = "unsupported" + coverageEmptyPodName = "empty pod name" + coverageEmptyPodNamespace = "empty pod namespace" hardeningLocation = "eastus" hardeningStateNamespace = "state-machine" hardeningNet1 = "net1" ) +func TestBoundedInvariantClassification(t *testing.T) { + tests := []struct { + name string + err error + want InvariantName + }{ + {name: "schema", err: ErrSchemaMismatch, want: InvariantSchema}, + {name: "corrupt", err: ErrCorrupt, want: InvariantStructural}, + {name: "inconsistent", err: ErrInconsistentState, want: InvariantStructural}, + {name: "unclassified error", err: errAbort, want: InvariantStructural}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, boundedInvariant(tt.err)) + }) + } +} + func TestOwnershipNormalizationRejectsMalformedRecords(t *testing.T) { validPod := PodIdentity{ PodKey: hardeningContainerID, @@ -48,8 +68,8 @@ func TestOwnershipNormalizationRejectsMalformedRecords(t *testing.T) { {name: "empty infra container", mutate: func(pod *PodIdentity) { pod.InfraContainerID = "" }}, {name: "pod key differs without interface", mutate: func(pod *PodIdentity) { pod.PodKey = testMismatchValue }}, {name: "interface differs from pod key", mutate: func(pod *PodIdentity) { pod.InterfaceID = testMismatchValue }}, - {name: "empty pod name", mutate: func(pod *PodIdentity) { pod.PodName = "" }}, - {name: "empty pod namespace", mutate: func(pod *PodIdentity) { pod.PodNamespace = "" }}, + {name: coverageEmptyPodName, mutate: func(pod *PodIdentity) { pod.PodName = "" }}, + {name: coverageEmptyPodNamespace, mutate: func(pod *PodIdentity) { pod.PodNamespace = "" }}, } for _, tt := range podTests { t.Run("pod/"+tt.name, func(t *testing.T) { @@ -102,7 +122,7 @@ func TestOwnershipNormalizationRejectsMalformedRecords(t *testing.T) { }{ {name: "empty container", record: validEndpoint}, { - name: "empty pod name", + name: coverageEmptyPodName, containerID: hardeningContainerID, record: EndpointRecord{ PodNamespace: hardeningNamespace, @@ -110,7 +130,7 @@ func TestOwnershipNormalizationRejectsMalformedRecords(t *testing.T) { }, }, { - name: "empty pod namespace", + name: coverageEmptyPodNamespace, containerID: hardeningContainerID, record: EndpointRecord{ PodName: importOrchestratorContextKey, @@ -570,7 +590,7 @@ func TestReleaseIdentityRejectsConflictingOwnership(t *testing.T) { name: "retained endpoint pod mismatch", pod: PodIdentity{ PodKey: testIfacePrimary, - InfraContainerID: "container-1", + InfraContainerID: exportContainerID, InterfaceID: testIfacePrimary, PodName: testMismatchValue, PodNamespace: exportPodNamespace, @@ -582,23 +602,23 @@ func TestReleaseIdentityRejectsConflictingOwnership(t *testing.T) { PodKey: testIfacePrimary, InfraContainerID: hardeningOtherContainerID, InterfaceID: testIfacePrimary, - PodName: "pod-1", + PodName: exportPodName, PodNamespace: exportPodNamespace, }, }, { name: "container assignment pod mismatch", mutate: func(value *Snapshot) { - delete(value.Endpoints, "container-1") + delete(value.Endpoints, exportContainerID) record := value.Assignments[testIfacePrimary] record.Pod.PodName = testMismatchValue value.Assignments[testIfacePrimary] = record }, pod: PodIdentity{ PodKey: "unknown-interface", - InfraContainerID: "container-1", + InfraContainerID: exportContainerID, InterfaceID: "unknown-interface", - PodName: "pod-1", + PodName: exportPodName, PodNamespace: exportPodNamespace, }, }, diff --git a/cns/state/export_test.go b/cns/state/export_test.go index f1356c12f0..8799a18620 100644 --- a/cns/state/export_test.go +++ b/cns/state/export_test.go @@ -48,6 +48,7 @@ const ( exportPodName = "pod-1" exportPodNamespace = "ns-1" exportNetworkType = "azure" + testEndpointsKey = "Endpoints" ) type rollbackFailureStage string @@ -115,7 +116,7 @@ func TestExportLegacySuccess(t *testing.T) { assert.Contains(t, string(cnsData), `"`+key+`"`) } for _, key := range []string{ - "Endpoints", + testEndpointsKey, "DeleteIntents", "PodName", "IfnameToIPMap", @@ -168,10 +169,14 @@ func TestExportLegacySuccess(t *testing.T) { var endpointEnvelope map[string]json.RawMessage require.NoError(t, json.Unmarshal(endpointData, &endpointEnvelope)) var endpoints map[string]*rollbackEndpointInfo - require.NoError(t, json.Unmarshal(endpointEnvelope["Endpoints"], &endpoints)) + require.NoError(t, json.Unmarshal(endpointEnvelope[testEndpointsKey], &endpoints)) assert.Equal(t, exportPodName, endpoints[exportContainerID].PodName) assert.Equal(t, exportPodNamespace, endpoints[exportContainerID].PodNamespace) - assert.ElementsMatch(t, []string{exportIfnameEth0, "net1"}, sortedKeys(endpoints[exportContainerID].IfnameToIPMap)) + assert.ElementsMatch( + t, + []string{exportIfnameEth0, cniImportTestSecondaryInterface}, + sortedKeys(endpoints[exportContainerID].IfnameToIPMap), + ) info := endpoints[exportContainerID].IfnameToIPMap[exportIfnameEth0] require.Len(t, info.IPv4, 1) assert.Equal(t, net.ParseIP(exportIPv4Address), info.IPv4[0].IP) @@ -183,7 +188,7 @@ func TestExportLegacySuccess(t *testing.T) { assert.Equal(t, "00:11:22:33:44:55", info.MacAddress) assert.Equal(t, exportNC1, info.NetworkContainerID) assert.Equal(t, cns.InfraNIC, info.NICType) - delegated := endpoints[exportContainerID].IfnameToIPMap["net1"] + delegated := endpoints[exportContainerID].IfnameToIPMap[cniImportTestSecondaryInterface] require.Len(t, delegated.IPv4, 1) assert.Equal(t, net.ParseIP("10.1.0.4"), delegated.IPv4[0].IP) assert.Equal(t, exportNC2, delegated.NetworkContainerID) @@ -684,7 +689,7 @@ func openPopulatedExportDB(t *testing.T) (db *DB, path string) { endpoint := completeEndpointRecord() endpoint.IfnameToIPMap[exportIfnameEth0].NetworkContainerID = exportNC1 - endpoint.IfnameToIPMap["net1"].NetworkContainerID = exportNC2 + endpoint.IfnameToIPMap[cniImportTestSecondaryInterface].NetworkContainerID = exportNC2 changed, err = db.AssignEndpoint( context.Background(), AssignmentRecord{ diff --git a/cns/state/import_legacy_keys_test.go b/cns/state/import_legacy_keys_test.go index 2d5a161c70..4856fc41bd 100644 --- a/cns/state/import_legacy_keys_test.go +++ b/cns/state/import_legacy_keys_test.go @@ -115,7 +115,7 @@ func TestImportLegacyCapitalizedRestserverKeys(t *testing.T) { require.NoError(t, err) endpointData, err := json.Marshal(map[string]any{ - "Endpoints": map[string]*capitalizedEndpointFixture{ + testEndpointsKey: map[string]*capitalizedEndpointFixture{ "capitalized-container": { PodName: "pod-capitalized", PodNamespace: "ns-capitalized", diff --git a/cns/state/import_test.go b/cns/state/import_test.go index 8dc53e59b0..a334a17832 100644 --- a/cns/state/import_test.go +++ b/cns/state/import_test.go @@ -702,7 +702,7 @@ func completeLegacyImportData(t testing.TB) (cnsData, endpointData []byte) { NetworkContainerID: importNC1, NICType: cns.InfraNIC, }, - "net1": { + cniImportTestSecondaryInterface: { IPv4: []net.IPNet{mustIPNet(t, importNet1Address+"/24")}, HNSEndpointID: "hns-endpoint-2", HNSNetworkID: "hns-network-2", @@ -714,7 +714,7 @@ func completeLegacyImportData(t testing.TB) (cnsData, endpointData []byte) { }, } endpointData, err = json.Marshal(map[string]any{ - "Endpoints": map[string]*EndpointRecord{importContainerID: &endpoint}, + testEndpointsKey: map[string]*EndpointRecord{importContainerID: &endpoint}, "DeleteIntents": map[string]DeleteIntent{ "deleted-container": {CreatedAt: testNow.Add(-time.Minute)}, }, diff --git a/cns/state/observability_test.go b/cns/state/observability_test.go index 985230d993..78e9464aeb 100644 --- a/cns/state/observability_test.go +++ b/cns/state/observability_test.go @@ -30,6 +30,13 @@ const ( metricTestDeleteIntent = "delete intent" ) +func TestNilMetricsClock(t *testing.T) { + started := time.Now() + duration := metricDuration(nil, started) + assert.GreaterOrEqual(t, duration, time.Duration(0)) + assert.Less(t, duration, time.Second) +} + func TestNewMetricsRegistration(t *testing.T) { t.Run("descriptors", func(t *testing.T) { registry := prometheus.NewRegistry() diff --git a/cns/state/types_test.go b/cns/state/types_test.go index 04bb17eeac..6b2416b261 100644 --- a/cns/state/types_test.go +++ b/cns/state/types_test.go @@ -176,7 +176,7 @@ func completeEndpointRecord() EndpointRecord { NetworkContainerID: testNCID, NICType: cns.InfraNIC, }, - "net1": { + cniImportTestSecondaryInterface: { IPv4: []net.IPNet{{ IP: net.ParseIP("10.1.0.4"), Mask: net.CIDRMask(24, 32),