@@ -843,67 +843,139 @@ func publishNCViaCNS(
843843 return fmt .Errorf ("decoding response: %w" , err )
844844 }
845845
846+ expStatus := http .StatusOK
847+ gotStatus := resp .PublishStatusCode
848+ if gotStatus != expStatus {
849+ // nolint:goerr113 // this is okay in a test:
850+ return fmt .Errorf ("unsuccessful request. exp: %d, got: %d" , expStatus , gotStatus )
851+ }
852+
853+ // ensure that there is an NMA body for legacy purposes
854+ nmaResp := make (map [string ]any )
855+ err = json .Unmarshal (resp .PublishResponseBody , & nmaResp )
856+ if err != nil {
857+ return fmt .Errorf ("decoding response body from nmagent: %w" , err )
858+ }
859+
860+ if statusStr , ok := nmaResp ["httpStatusCode" ]; ok {
861+ bodyStatus , err := strconv .Atoi (statusStr .(string ))
862+ if err != nil {
863+ return fmt .Errorf ("parsing http status string from nmagent: %w" , err )
864+ }
865+
866+ if bodyStatus != expStatus {
867+ // nolint:goerr113 // this is okay in a test:
868+ return fmt .Errorf ("unexpected status in body. exp: %d, got %d" , expStatus , bodyStatus )
869+ }
870+ }
871+
846872 fmt .Printf ("PublishNetworkContainer succeded with response %+v, raw:%+v\n " , resp , w .Body )
847873 return nil
848874}
849875
850876func TestUnpublishNCViaCNS (t * testing.T ) {
877+ // Publishing and Unpublishing via CNS effectively uses CNS as a proxy to
878+ // NMAgent. This test asserts that the correct methods are invoked on the
879+ // NMAgent client in the correct order based on a sequence of creating and
880+ // destroying an example NC.
881+
882+ // create a mock NMAgent that allows assertions on the methods called. There
883+ // should be a certain sequence of invocations based on the high-level
884+ // actions that are taken here.
885+ const (
886+ joinNetwork = "JoinNetwork"
887+ deleteNetworkContainer = "DeleteNetworkContainer"
888+ putNetworkContainer = "PutNetworkContainer"
889+ )
890+
891+ got := []string {}
851892 mnma := & fakes.NMAgentClientFake {
852893 JoinNetworkF : func (_ context.Context , _ nmagent.JoinNetworkRequest ) error {
894+ got = append (got , joinNetwork )
853895 return nil
854896 },
855897 DeleteNetworkContainerF : func (_ context.Context , _ nmagent.DeleteContainerRequest ) error {
898+ got = append (got , deleteNetworkContainer )
856899 return nil
857900 },
858901 PutNetworkContainerF : func (_ context.Context , _ * nmagent.PutNetworkContainerRequest ) error {
902+ got = append (got , putNetworkContainer )
859903 return nil
860904 },
861905 }
862906
863907 cleanup := setMockNMAgent (svc , mnma )
864908 defer cleanup ()
865909
866- deleteNetworkContainerURL := "http://" + nmagentEndpoint +
867- "/machine/plugins/?comp=nmagent&type=NetworkManagement/interfaces/dummyIntf/networkContainers/dummyNCURL/authenticationToken/dummyT/api-version/1/method/DELETE"
868- err := publishNCViaCNS ("vnet1" , "ethWebApp" , deleteNetworkContainerURL )
910+ // create a network container as the subject of this test.
911+ createNetworkContainerURL := "http://" + nmagentEndpoint +
912+ "/machine/plugins/?comp=nmagent&type=NetworkManagement/interfaces/dummyIntf/networkContainers/dummyNCURL/authenticationToken/dummyT/api-version/1"
913+ err := publishNCViaCNS ("vnet1" , "ethWebApp" , createNetworkContainerURL )
869914 if err != nil {
870- t .Fatal (err )
915+ t .Fatal (fmt . Errorf ( "publish container failed %w " , err ) )
871916 }
872917
873- deleteNetworkContainerURL = "http://" + nmagentEndpoint +
918+ // prior to the actual deletion, attempt to delete using an invalid URL (by
919+ // omitting a letter from "authenticationToken"). This should fail:
920+ deleteNetworkContainerURL := "http://" + nmagentEndpoint +
874921 "/machine/plugins/?comp=nmagent&type=NetworkManagement/interfaces/dummyIntf/networkContainers/dummyNCURL/authenticationToke/" +
875922 "8636c99d-7861-401f-b0d3-7e5b7dc8183c" +
876923 "/api-version/1/method/DELETE"
877-
878- err = publishNCViaCNS ("vnet1" , "ethWebApp" , deleteNetworkContainerURL )
924+ err = unpublishNCViaCNS ("vnet1" , "ethWebApp" , deleteNetworkContainerURL )
879925 if err == nil {
880926 t .Fatal ("Expected a bad request error due to delete network url being incorrect" )
881927 }
882928
929+ // also ensure that deleting a network container with an invalid
930+ // authentication token (one that is too long) also fails:
883931 deleteNetworkContainerURL = "http://" + nmagentEndpoint +
884932 "/machine/plugins/?comp=nmagent&NetworkManagement/interfaces/dummyIntf/networkContainers/dummyNCURL/authenticationToken/" +
885933 "8636c99d-7861-401f-b0d3-7e5b7dc8183c8636c99d-7861-401f-b0d3-7e5b7dc8183c" +
886934 "/api-version/1/method/DELETE"
887-
888- err = testUnpublishNCViaCNS (t , "vnet1" , "ethWebApp" , deleteNetworkContainerURL , true )
935+ err = unpublishNCViaCNS ("vnet1" , "ethWebApp" , deleteNetworkContainerURL )
889936 if err == nil {
890937 t .Fatal ("Expected a bad request error due to create network url having more characters than permitted in auth token" )
891938 }
892- }
893939
894- func testUnpublishNCViaCNS (t * testing.T ,
895- networkID ,
896- networkContainerID ,
897- deleteNetworkContainerURL string ,
898- expectError bool ,
899- ) error {
900- var (
901- body bytes.Buffer
902- resp cns.UnpublishNetworkContainerResponse
903- )
940+ // now actually perform the deletion:
941+ deleteNetworkContainerURL = "http://" + nmagentEndpoint +
942+ "/machine/plugins/?comp=nmagent&type=NetworkManagement/interfaces/dummyIntf/networkContainers/dummyNCURL/authenticationToken/dummyT/api-version/1/method/DELETE"
943+ err = unpublishNCViaCNS ("vnet1" , "ethWebApp" , deleteNetworkContainerURL )
944+ if err != nil {
945+ t .Fatal (err )
946+ }
904947
905- fmt .Println ("Test: unpublishNetworkContainer" )
948+ // Assert the correct sequence of invocations on the NMAgent client. Creating
949+ // a network container involves first joining the network and then creating a
950+ // network container. Deleting the network container only involved the Delete
951+ // call. Even though there were two other invalid Delete calls, we do not
952+ // expect them to generate invocations of methods on the NMAgent
953+ // client--these should be captured by CNS.
954+ exp := []string {
955+ // These two methods in the sequence are from the NC creation:
956+ joinNetwork ,
957+ putNetworkContainer ,
906958
959+ // This one is from the delete. There is technically one code path where a
960+ // "JoinNetwork" can appear here, but we don't expect it because
961+ // "JoinNetwork" appeared as part of the NC creation.
962+ deleteNetworkContainer ,
963+ }
964+
965+ // with the expectation set, match up expectations with the method calls
966+ // received:
967+ if len (exp ) != len (got ) {
968+ t .Fatal ("unexpected sequence of methods invoked on NMAgent client: exp:" , exp , "got:" , got )
969+ }
970+
971+ for idx := range exp {
972+ if got [idx ] != exp [idx ] {
973+ t .Error ("unexpected sequence of methods invoked on NMAgent client: exp:" , exp , "got:" , got )
974+ }
975+ }
976+ }
977+
978+ func unpublishNCViaCNS (networkID , networkContainerID , deleteNetworkContainerURL string ) error {
907979 joinNetworkURL := "http://" + nmagentEndpoint + "/dummyVnetURL"
908980
909981 unpublishNCRequest := & cns.UnpublishNetworkContainerRequest {
@@ -913,36 +985,50 @@ func testUnpublishNCViaCNS(t *testing.T,
913985 DeleteNetworkContainerURL : deleteNetworkContainerURL ,
914986 }
915987
988+ var body bytes.Buffer
916989 json .NewEncoder (& body ).Encode (unpublishNCRequest )
917990 req , err := http .NewRequest (http .MethodPost , cns .UnpublishNetworkContainer , & body )
918991 if err != nil {
919992 return fmt .Errorf ("Failed to create unpublish request %w" , err )
920993 }
921994
922- mnma := & fakes.NMAgentClientFake {
923- DeleteNetworkContainerF : func (_ context.Context , _ nmagent.DeleteContainerRequest ) error {
924- return nil
925- },
926- JoinNetworkF : func (_ context.Context , _ nmagent.JoinNetworkRequest ) error {
927- return nil
928- },
929- }
930-
931- cleanup := setMockNMAgent (svc , mnma )
932- defer cleanup ()
933-
934995 w := httptest .NewRecorder ()
935996 mux .ServeHTTP (w , req )
936997
998+ var resp cns.UnpublishNetworkContainerResponse
937999 err = decodeResponse (w , & resp )
938- if err != nil || resp .Response .ReturnCode != 0 {
939- if ! expectError {
940- t .Errorf ("UnpublishNetworkContainer failed with response %+v Err:%+v" , resp , err )
941- }
942- return err
1000+ if err != nil {
1001+ return fmt .Errorf ("error decoding json: err: %w" , err )
1002+ }
1003+
1004+ if resp .Response .ReturnCode != 0 {
1005+ // nolint:goerr113 // this is okay in a test:
1006+ return fmt .Errorf ("UnpublishNetworkContainer failed with response %+v: err: %w" , resp , err )
1007+ }
1008+
1009+ code := resp .UnpublishStatusCode
1010+ if code != http .StatusOK {
1011+ // nolint:goerr113 // this is okay in a test:
1012+ return fmt .Errorf ("unsuccessful NMAgent response: status code %d" , code )
9431013 }
9441014
945- fmt .Printf ("UnpublishNetworkContainer succeded with response %+v, raw:%+v\n " , resp , w .Body )
1015+ nmaBody := struct {
1016+ StatusCode string `json:"httpStatusCode"`
1017+ }{}
1018+ err = json .Unmarshal (resp .UnpublishResponseBody , & nmaBody )
1019+ if err != nil {
1020+ return fmt .Errorf ("unmarshaling NMAgent response body: %w" , err )
1021+ }
1022+
1023+ bodyCode , err := strconv .Atoi (nmaBody .StatusCode )
1024+ if err != nil {
1025+ return fmt .Errorf ("parsing NMAgent body status code as an integer: %w" , err )
1026+ }
1027+
1028+ if bodyCode != code {
1029+ // nolint:goerr113 // this is okay in a test:
1030+ return fmt .Errorf ("mismatch between NMAgent status code (%d) and NMAgent body status code (%d)" , code , bodyCode )
1031+ }
9461032
9471033 return nil
9481034}
@@ -1367,14 +1453,16 @@ func setEnv(t *testing.T) *httptest.ResponseRecorder {
13671453}
13681454
13691455func startService () error {
1370- var err error
13711456 // Create the service.
13721457 config := common.ServiceConfig {}
1373- // Create the key value store.
1374- if config .Store , err = store .NewJsonFileStore (cnsJsonFileName , processlock .NewMockFileLock (false )); err != nil {
1458+
1459+ // Create the key value fileStore.
1460+ fileStore , err := store .NewJsonFileStore (cnsJsonFileName , processlock .NewMockFileLock (false ))
1461+ if err != nil {
13751462 logger .Errorf ("Failed to create store file: %s, due to error %v\n " , cnsJsonFileName , err )
13761463 return err
13771464 }
1465+ config .Store = fileStore
13781466
13791467 nmagentClient := & fakes.NMAgentClientFake {}
13801468 service , err = NewHTTPRestService (& config , & fakes.WireserverClientFake {}, nmagentClient , nil , nil , nil )
@@ -1383,10 +1471,6 @@ func startService() error {
13831471 }
13841472 svc = service .(* HTTPRestService )
13851473 svc .Name = "cns-test-server"
1386- if err != nil {
1387- logger .Errorf ("Failed to create CNS object, err:%v.\n " , err )
1388- return err
1389- }
13901474
13911475 svc .IPAMPoolMonitor = & fakes.MonitorFake {}
13921476 nmagentClient .GetNCVersionListF = func (context.Context ) (nmagent.NCVersionList , error ) {
0 commit comments