@@ -11,6 +11,7 @@ import (
1111 "os"
1212 "reflect"
1313 "strconv"
14+ "strings"
1415 "sync"
1516 "testing"
1617 "time"
@@ -44,7 +45,6 @@ const (
4445 initPoolSize = 10
4546 ncID = "6a07155a-32d7-49af-872f-1e70ee366dc0"
4647 imdsNCID = "6a07155a-32d7-49af-872f-1e70ee36imds"
47- macAddress = "00:11:22:33:44:55"
4848)
4949
5050var dnsservers = []string {"8.8.8.8" , "8.8.4.4" }
@@ -337,6 +337,212 @@ func TestPendingIPsGotUpdatedWhenSyncHostNCVersion(t *testing.T) {
337337 }
338338}
339339
340+ func TestSyncHostNCVersionErrorMissingNC (t * testing.T ) {
341+ req := createNCReqeustForSyncHostNCVersion (t )
342+
343+ svc .Lock ()
344+ ncStatus := svc .state .ContainerStatus [req .NetworkContainerid ]
345+ ncStatus .CreateNetworkContainerRequest .Version = "2"
346+ ncStatus .HostVersion = "0"
347+ svc .state .ContainerStatus [req .NetworkContainerid ] = ncStatus
348+ svc .Unlock ()
349+
350+ // Setup IMDS mock with different interface IDs (not matching the outdated NC)
351+ cleanupIMDS := setupIMDSMockAPIsWithCustomIDs (svc , []string {"different-nc-id-1" , "different-nc-id-2" })
352+ defer cleanupIMDS ()
353+
354+ // NMAgent returns empty
355+ mnma := & fakes.NMAgentClientFake {
356+ GetNCVersionListF : func (_ context.Context ) (nma.NCVersionList , error ) {
357+ return nma.NCVersionList {
358+ Containers : []nma.NCVersion {},
359+ }, nil
360+ },
361+ }
362+ cleanup := setMockNMAgent (svc , mnma )
363+ defer cleanup ()
364+
365+ _ , err := svc .syncHostNCVersion (context .Background (), cns .KubernetesCRD )
366+ if err == nil {
367+ t .Errorf ("Expected error when NC is missing from both NMAgent and IMDS, but got nil" )
368+ }
369+
370+ // Check that the error message contains the expected text
371+ expectedErrorText := "unable to update some NCs"
372+ if ! strings .Contains (err .Error (), expectedErrorText ) {
373+ t .Errorf ("Expected error to contain '%s', but got: %v" , expectedErrorText , err )
374+ }
375+
376+ // Verify that the NC HostVersion was not updated, should still be 0
377+ containerStatus := svc .state .ContainerStatus [req .NetworkContainerid ]
378+ if containerStatus .HostVersion != "0" {
379+ t .Errorf ("Expected HostVersion to remain 0, but got %s" , containerStatus .HostVersion )
380+ }
381+ }
382+
383+ func TestSyncHostNCVersionLocalVersionHigher (t * testing.T ) {
384+ // Test scenario where local NC version is higher than consolidated NC version from IMDS
385+ // This should trigger the "NC version from consolidated sources is decreasing" error
386+ req := createNCReqeustForSyncHostNCVersion (t )
387+
388+ svc .Lock ()
389+ ncStatus := svc .state .ContainerStatus [req .NetworkContainerid ]
390+ ncStatus .CreateNetworkContainerRequest .Version = "1" // DNC version is 1
391+ ncStatus .HostVersion = "3" // But local host version is 3
392+ svc .state .ContainerStatus [req .NetworkContainerid ] = ncStatus
393+ svc .Unlock ()
394+
395+ // Create IMDS mock that returns lower version(1) than local host version(3)
396+ // Setup IMDS mock with version support
397+ cleanupIMDS := setupIMDSMockAPIsWithCustomIDs (svc , []string {imdsNCID , "nc2" })
398+ defer cleanupIMDS ()
399+
400+ mnma := & fakes.NMAgentClientFake {
401+ GetNCVersionListF : func (_ context.Context ) (nma.NCVersionList , error ) {
402+ return nma.NCVersionList {
403+ Containers : []nma.NCVersion {},
404+ }, nil
405+ },
406+ }
407+ cleanup := setMockNMAgent (svc , mnma )
408+ defer cleanup ()
409+
410+ _ , err := svc .syncHostNCVersion (context .Background (), cns .KubernetesCRD )
411+ if err != nil {
412+ t .Errorf ("Expected sync to succeed, but got error: %v" , err )
413+ }
414+
415+ // Verify that the NC HostVersion was NOT updated (should remain "3")
416+ containerStatus := svc .state .ContainerStatus [req .NetworkContainerid ]
417+ if containerStatus .HostVersion != "3" {
418+ t .Errorf ("Expected HostVersion to remain 3 (unchanged due to decreasing version), got %s" , containerStatus .HostVersion )
419+ }
420+
421+ t .Logf ("Successfully handled decreasing version scenario: local=%s, consolidated=%s" ,
422+ containerStatus .HostVersion , "2" )
423+ }
424+
425+ func TestSyncHostNCVersionLocalHigherThanDNC (t * testing.T ) {
426+ // Test scenario where localNCVersion > dncNCVersion
427+ // This should trigger an error log: "NC version from NMAgent is larger than DNC"
428+ req := createNCReqeustForSyncHostNCVersion (t )
429+
430+ // Set up the NC state where HostVersion (localNCVersion) > DNC NC Version
431+ svc .Lock ()
432+ ncStatus := svc .state .ContainerStatus [req .NetworkContainerid ]
433+ ncStatus .CreateNetworkContainerRequest .Version = "1"
434+ ncStatus .HostVersion = "3"
435+ svc .state .ContainerStatus [req .NetworkContainerid ] = ncStatus
436+ svc .Unlock ()
437+
438+ cleanupIMDS := setupIMDSMockAPIsWithCustomIDs (svc , []string {imdsNCID , "nc2" })
439+ defer cleanupIMDS ()
440+
441+ mnma := & fakes.NMAgentClientFake {
442+ GetNCVersionListF : func (_ context.Context ) (nma.NCVersionList , error ) {
443+ return nma.NCVersionList {
444+ Containers : []nma.NCVersion {}, // Empty
445+ }, nil
446+ },
447+ }
448+ cleanup := setMockNMAgent (svc , mnma )
449+ defer cleanup ()
450+
451+ // This should detect that localNCVersion (3) > dncNCVersion (1) and log error
452+ // but since there are no outdated NCs, it should return successfully
453+ _ , err := svc .syncHostNCVersion (context .Background (), cns .KubernetesCRD )
454+ if err != nil {
455+ t .Errorf ("Expected no error when localNCVersion > dncNCVersion (no outdated NCs), but got: %v" , err )
456+ }
457+
458+ containerStatus := svc .state .ContainerStatus [req .NetworkContainerid ]
459+ if containerStatus .HostVersion != "3" {
460+ t .Errorf ("Expected HostVersion to remain 3 (unchanged), got %s" , containerStatus .HostVersion )
461+ }
462+
463+ // Verify that the DNC version remains unchanged, should still be 1
464+ if containerStatus .CreateNetworkContainerRequest .Version != "1" {
465+ t .Errorf ("Expected DNC version to remain 1 (unchanged), got %s" , containerStatus .CreateNetworkContainerRequest .Version )
466+ }
467+
468+ t .Logf ("Successfully handled localNCVersion > dncNCVersion scenario: local=%s, dnc=%s" ,
469+ containerStatus .HostVersion , containerStatus .CreateNetworkContainerRequest .Version )
470+ }
471+
472+ func TestSyncHostNCVersionIMDSAPIVersionNotSupported (t * testing.T ) {
473+ orchestratorTypes := []string {cns .Kubernetes , cns .KubernetesCRD }
474+ for _ , orchestratorType := range orchestratorTypes {
475+ t .Run (orchestratorType , func (t * testing.T ) {
476+ req := createNCReqeustForSyncHostNCVersion (t )
477+
478+ // Make the NMA NC up-to-date so it doesn't interfere with the test
479+ svc .Lock ()
480+ nmaNCStatus := svc .state .ContainerStatus [req .NetworkContainerid ]
481+ nmaNCStatus .HostVersion = "0" // Same as Version "0", so not outdated
482+ svc .state .ContainerStatus [req .NetworkContainerid ] = nmaNCStatus
483+ svc .Unlock ()
484+
485+ // NMAgent mock - not important for this test, just needs to not interfere
486+ mnma := & fakes.NMAgentClientFake {
487+ GetNCVersionListF : func (_ context.Context ) (nma.NCVersionList , error ) {
488+ return nma.NCVersionList {Containers : []nma.NCVersion {}}, nil
489+ },
490+ }
491+ cleanup := setMockNMAgent (svc , mnma )
492+ defer cleanup ()
493+
494+ // Add IMDS NC that is outdated - this is the focus of the test
495+ svc .state .ContainerStatus [imdsNCID ] = containerstatus {
496+ ID : imdsNCID ,
497+ VMVersion : "0" ,
498+ HostVersion : "-1" , // Outdated
499+ CreateNetworkContainerRequest : cns.CreateNetworkContainerRequest {
500+ NetworkContainerid : imdsNCID ,
501+ Version : "1" , // Higher than HostVersion
502+ },
503+ }
504+
505+ // Setup IMDS mock that returns API versions WITHOUT the expected version "2025-07-24"
506+ mockIMDS := & struct {
507+ networkInterfaces func (_ context.Context ) ([]imds.NetworkInterface , error )
508+ imdsVersions func (_ context.Context ) (* imds.APIVersionsResponse , error )
509+ }{
510+ networkInterfaces : func (_ context.Context ) ([]imds.NetworkInterface , error ) {
511+ return []imds.NetworkInterface {
512+ {InterfaceCompartmentID : imdsNCID },
513+ }, nil
514+ },
515+ imdsVersions : func (_ context.Context ) (* imds.APIVersionsResponse , error ) {
516+ return & imds.APIVersionsResponse {
517+ APIVersions : []string {"2017-03-01" , "2021-01-01" }, // Missing "2025-07-24"
518+ }, nil
519+ },
520+ }
521+ originalIMDS := svc .imdsClient
522+ svc .imdsClient = & mockIMDSAdapter {mockIMDS }
523+ defer func () { svc .imdsClient = originalIMDS }()
524+
525+ // Test should fail because of outdated IMDS NC that can't be updated
526+ _ , err := svc .syncHostNCVersion (context .Background (), orchestratorType )
527+ if err == nil {
528+ t .Errorf ("Expected error when there are outdated IMDS NCs but API version is not supported, but got nil" )
529+ }
530+
531+ // Verify the error is about being unable to update NCs
532+ expectedErrorText := "unable to update some NCs"
533+ if ! strings .Contains (err .Error (), expectedErrorText ) {
534+ t .Errorf ("Expected error to contain '%s', but got: %v" , expectedErrorText , err )
535+ }
536+
537+ // Only verify IMDS NC state - this is the focus of the test
538+ imdsContainerStatus := svc .state .ContainerStatus [imdsNCID ]
539+ if imdsContainerStatus .HostVersion != "-1" {
540+ t .Errorf ("Expected IMDS NC HostVersion to remain -1, got %s" , imdsContainerStatus .HostVersion )
541+ }
542+ })
543+ }
544+ }
545+
340546func createNCReqeustForSyncHostNCVersion (t * testing.T ) cns.CreateNetworkContainerRequest {
341547 restartService ()
342548 setEnv (t )
0 commit comments