diff --git a/os_repository_test.go b/os_repository_test.go new file mode 100644 index 0000000..92e09da --- /dev/null +++ b/os_repository_test.go @@ -0,0 +1,248 @@ +// Copyright © 2024 Dell Inc. or its subsidiaries. All Rights Reserved. +// +// 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 goscaleio + +import ( + "errors" + "fmt" + "math" + "net/http" + "net/http/httptest" + "testing" + + types "github.com/dell/goscaleio/types/v1" +) + +func TestGetAllOSRepositories(t *testing.T) { + type testCase struct { + server *httptest.Server + expectedErr error + } + + cases := []testCase{ + { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/v1/OSRepository": + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"bad request","httpStatusCode":400,"errorCode":0}`)) + })), + expectedErr: errors.New("bad request"), + }, + } + + for _, tc := range cases { + client, err := NewClientWithArgs(tc.server.URL, "", math.MaxInt64, true, false) + client.configConnect.Version = "3.6" + if err != nil { + t.Fatal(err) + } + + s := System{ + client: client, + } + + _, err = s.GetAllOSRepositories() + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestGetOSRepositoryByID(t *testing.T) { + type testCase struct { + id string + server *httptest.Server + expectedErr error + } + + validID := "12345678-1234-1234-1234-123456789012" + + cases := []testCase{ + { + id: validID, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case fmt.Sprintf("/api/v1/OSRepository/%s", validID): + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + { + id: "invalid-id", + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"invalid id passed","httpStatusCode":400,"errorCode":0}`)) + })), + expectedErr: errors.New("invalid id passed"), + }, + } + + for _, tc := range cases { + client, err := NewClientWithArgs(tc.server.URL, "", math.MaxInt64, true, false) + client.configConnect.Version = "3.6" + if err != nil { + t.Fatal(err) + } + + s := System{ + client: client, + } + + _, err = s.GetOSRepositoryByID(tc.id) + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestCreateOSRepository(t *testing.T) { + type testCase struct { + repoContent *types.OSRepository + server *httptest.Server + expectedErr error + } + + cases := []testCase{ + { + repoContent: &types.OSRepository{ + Name: "my-repo", + RepoType: "S3", + SourcePath: "source", + ImageType: "ISO", + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/v1/OSRepository": + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + { + repoContent: nil, + server: httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {})), + expectedErr: errors.New("createOSRepository cannot be nil"), + }, + { + repoContent: &types.OSRepository{ + Name: "my-repo", + RepoType: "S3", + SourcePath: "source", + ImageType: "ISO", + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"invalid create repo request","httpStatusCode":400,"errorCode":0}`)) + })), + expectedErr: errors.New("invalid create repo request"), + }, + } + + for _, tc := range cases { + client, err := NewClientWithArgs(tc.server.URL, "", math.MaxInt64, true, false) + client.configConnect.Version = "3.6" + if err != nil { + t.Fatal(err) + } + + s := System{ + client: client, + } + + _, err = s.CreateOSRepository(tc.repoContent) + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestRemoveOSRepository(t *testing.T) { + type testCase struct { + id string + server *httptest.Server + expectedErr error + } + + validID := "12345678-1234-1234-1234-123456789012" + + cases := []testCase{ + { + id: validID, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case fmt.Sprintf("/api/v1/OSRepository/%s", validID): + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + { + id: "invalid-id", + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"invalid id passed","httpStatusCode":400,"errorCode":0}`)) + })), + expectedErr: errors.New("invalid id passed"), + }, + } + + for _, tc := range cases { + client, err := NewClientWithArgs(tc.server.URL, "", math.MaxInt64, true, false) + client.configConnect.Version = "3.6" + if err != nil { + t.Fatal(err) + } + + s := System{ + client: client, + } + + err = s.RemoveOSRepository(tc.id) + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} diff --git a/protectiondomain_test.go b/protectiondomain_test.go new file mode 100644 index 0000000..e26b7c8 --- /dev/null +++ b/protectiondomain_test.go @@ -0,0 +1,588 @@ +// Copyright © 2024 Dell Inc. or its subsidiaries. All Rights Reserved. +// +// 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 goscaleio + +import ( + "encoding/json" + "errors" + "fmt" + "math" + "net/http" + "net/http/httptest" + "testing" + + types "github.com/dell/goscaleio/types/v1" +) + +func TestCreateProtectionDomain(t *testing.T) { + pdName := "myPD" + type testCase struct { + server *httptest.Server + expectedErr error + } + + cases := map[string]testCase{ + "succeed": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/types/ProtectionDomain/instances": + resp.WriteHeader(http.StatusOK) + response := types.ProtectionDomainResp{ + ID: "1", + } + + content, err := json.Marshal(response) + if err != nil { + t.Fatal(err) + } + + resp.Write(content) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + "bad request": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"bad request","httpStatusCode":400,"errorCode":0}`)) + })), + expectedErr: errors.New("bad request"), + }, + } + + for _, tc := range cases { + client, err := NewClientWithArgs(tc.server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + s := System{ + client: client, + } + + _, err = s.CreateProtectionDomain(pdName) + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestGetProtectionDomainEx(t *testing.T) { + pdID := "12345678-1234-1234-1234-123456789012" + type testCase struct { + server *httptest.Server + expectedErr error + } + + cases := map[string]testCase{ + "succeed": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case fmt.Sprintf("/api/instances/ProtectionDomain::%s", pdID): + resp.WriteHeader(http.StatusOK) + response := types.ProtectionDomain{ + ID: pdID, + Name: "domain1", + } + + content, err := json.Marshal(response) + if err != nil { + t.Fatal(err) + } + + resp.Write(content) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + "error: invalid http response": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"bad request","httpStatusCode":400,"errorCode":0}`)) + })), + expectedErr: errors.New("error getting protection domain by id: bad request"), + }, + } + + for title, tc := range cases { + fmt.Printf("running test case: %s\n", title) + client, err := NewClientWithArgs(tc.server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + s := System{ + client: client, + } + + _, err = s.GetProtectionDomainEx(pdID) + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestDeleteProtectionDomain(t *testing.T) { + pdName := "myDomain" + domainHost := "localhost" + pdID := "12345678-1234-1234-1234-123456789012" + type testCase struct { + server *httptest.Server + expectedErr error + } + + cases := map[string]testCase{ + "succeed": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/System/relationship/ProtectionDomain": + resp.WriteHeader(http.StatusOK) + response := []types.ProtectionDomain{ + { + ID: pdID, + Name: pdName, + Links: []*types.Link{ + {Rel: "self", HREF: domainHost}, + }, + }, + } + + content, err := json.Marshal(response) + if err != nil { + t.Fatal(err) + } + + resp.Write(content) + case fmt.Sprintf("/%s/action/removeProtectionDomain", domainHost): + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + "error: invalid relationship protection domain call": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/System/relationship/ProtectionDomain": + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"bad request","httpStatusCode":400,"errorCode":0}`)) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: errors.New("Error getting protection domains bad request"), + }, + "error: unable to find protection domain": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/System/relationship/ProtectionDomain": + resp.WriteHeader(http.StatusOK) + response := []types.ProtectionDomain{ + { + ID: "invalidID", + Name: "invalidName", + }, + } + + content, err := json.Marshal(response) + if err != nil { + t.Fatal(err) + } + + resp.Write(content) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: errors.New("Couldn't find protection domain"), + }, + "error: invalid domain links": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/System/relationship/ProtectionDomain": + resp.WriteHeader(http.StatusOK) + response := []types.ProtectionDomain{ + { + ID: pdID, + Name: pdName, + }, + } + + content, err := json.Marshal(response) + if err != nil { + t.Fatal(err) + } + + resp.Write(content) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: errors.New("Error: problem finding link"), + }, + "error: unable to remove protection domain": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/System/relationship/ProtectionDomain": + resp.WriteHeader(http.StatusOK) + response := []types.ProtectionDomain{ + { + ID: pdID, + Name: pdName, + Links: []*types.Link{ + {Rel: "self", HREF: domainHost}, + }, + }, + } + + content, err := json.Marshal(response) + if err != nil { + t.Fatal(err) + } + + resp.Write(content) + case fmt.Sprintf("/%s/action/removeProtectionDomain", domainHost): + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"unable to remove protection domain","httpStatusCode":400,"errorCode":0}`)) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: errors.New("unable to remove protection domain"), + }, + } + + for title, tc := range cases { + fmt.Printf("running test case: %s\n", title) + client, err := NewClientWithArgs(tc.server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + s := System{ + System: &types.System{ + Links: []*types.Link{{Rel: "/api/System/relationship/ProtectionDomain", HREF: "/api/System/relationship/ProtectionDomain"}, {Rel: "self", HREF: "localhost"}}, + }, + client: client, + } + + err = s.DeleteProtectionDomain(pdName) + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestProtectionDomainDelete(t *testing.T) { + domainHost := "localhost" + type testCase struct { + protectionDomain *types.ProtectionDomain + server *httptest.Server + expectedErr error + } + + cases := map[string]testCase{ + "succeed": { + protectionDomain: &types.ProtectionDomain{ + Links: []*types.Link{ + {Rel: "self", HREF: domainHost}, + }, + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case fmt.Sprintf("/%s/action/removeProtectionDomain", domainHost): + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + "error: invalid domain links": { + protectionDomain: &types.ProtectionDomain{}, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusNoContent) + })), + expectedErr: errors.New("Error: problem finding link"), + }, + "error: unable to remove protection domain": { + protectionDomain: &types.ProtectionDomain{ + Links: []*types.Link{ + {Rel: "self", HREF: domainHost}, + }, + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"unable to remove protection domain","httpStatusCode":400,"errorCode":0}`)) + })), + expectedErr: errors.New("unable to remove protection domain"), + }, + } + + for title, tc := range cases { + fmt.Printf("running test case: %s\n", title) + client, err := NewClientWithArgs(tc.server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + pdClient := ProtectionDomain{ + ProtectionDomain: tc.protectionDomain, + client: client, + } + + err = pdClient.Delete() + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestFindProtectionDomainByName(t *testing.T) { + domainName := "myDomain" + domainID := "12345678-1234-1234-1234-123456789012" + type testCase struct { + server *httptest.Server + expectedErr error + } + + cases := map[string]testCase{ + "succeed": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/types/ProtectionDomain/instances/action/queryIdByKey": + resp.WriteHeader(http.StatusOK) + content, err := json.Marshal(domainID) + if err != nil { + t.Fatal(err) + } + + resp.Write(content) + case fmt.Sprintf("/api/instances/ProtectionDomain::%s", domainID): + resp.WriteHeader(http.StatusOK) + response := types.ProtectionDomain{ + ID: domainID, + Name: domainName, + } + + content, err := json.Marshal(response) + if err != nil { + t.Fatal(err) + } + + resp.Write(content) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + "error: bad request": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/types/ProtectionDomain/instances/action/queryIdByKey": + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"bad request","httpStatusCode":400,"errorCode":0}`)) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: errors.New("error getting protection domain by name: bad request"), + }, + } + + for title, tc := range cases { + fmt.Printf("running test case: %s\n", title) + client, err := NewClientWithArgs(tc.server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + s := System{ + client: client, + } + + _, err = s.FindProtectionDomainByName(domainName) + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestProtectionDomainRefresh(t *testing.T) { + domainHost := "localhost" + domainID := "12345678-1234-1234-1234-123456789012" + type testCase struct { + protectionDomain *types.ProtectionDomain + server *httptest.Server + expectedErr error + } + + cases := map[string]testCase{ + "succeed": { + protectionDomain: &types.ProtectionDomain{ + ID: domainID, + Links: []*types.Link{ + {Rel: "self", HREF: domainHost}, + }, + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case fmt.Sprintf("/api/instances/ProtectionDomain::%s", domainID): + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + "error: bad request": { + protectionDomain: &types.ProtectionDomain{ + ID: domainID, + Links: []*types.Link{ + {Rel: "self", HREF: domainHost}, + }, + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case fmt.Sprintf("/api/instances/ProtectionDomain::%s", domainID): + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"bad request","httpStatusCode":400,"errorCode":0}`)) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: errors.New("bad request"), + }, + } + + for title, tc := range cases { + fmt.Printf("running test case: %s\n", title) + client, err := NewClientWithArgs(tc.server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + pdClient := ProtectionDomain{ + ProtectionDomain: tc.protectionDomain, + client: client, + } + + err = pdClient.Refresh() + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestProtectionDomainSetParamters(t *testing.T) { + domainHost := "localhost" + domainID := "12345678-1234-1234-1234-123456789012" + + server := httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case fmt.Sprintf("/api/instances/ProtectionDomain::%s/action/setProtectionDomainName", domainID): + fmt.Println("handling setProtectionDomainName") + resp.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/instances/ProtectionDomain::%s/action/setRfcacheParameters", domainID): + fmt.Println("handling setRfcacheParameters") + resp.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/instances/ProtectionDomain::%s/action/setSdsNetworkLimits", domainID): + fmt.Println("handling setSdsNetworkLimits") + resp.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/instances/ProtectionDomain::%s/action/activateProtectionDomain", domainID): + fmt.Println("handling activateProtectionDomain") + resp.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/instances/ProtectionDomain::%s/action/inactivateProtectionDomain", domainID): + fmt.Println("handling inactivateProtectionDomain") + resp.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/instances/ProtectionDomain::%s/action/enableSdsRfcache", domainID): + fmt.Println("handling enableSdsRfcache") + resp.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/instances/ProtectionDomain::%s/action/disableSdsRfcache", domainID): + fmt.Println("handling disableSdsRfcache") + resp.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/instances/ProtectionDomain::%s/action/disableFglMetadataCache", domainID): + fmt.Println("handling disableFglMetadataCache") + case fmt.Sprintf("/api/instances/ProtectionDomain::%s/action/enableFglMetadataCache", domainID): + fmt.Println("handling disableFglMetadataCache") + case fmt.Sprintf("/api/instances/ProtectionDomain::%s/action/setDefaultFglMetadataCacheSize", domainID): + fmt.Println("handling disableFglMetadataCache") + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusNoContent) + } + })) + + client, err := NewClientWithArgs(server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + pdClient := ProtectionDomain{ + ProtectionDomain: &types.ProtectionDomain{ + ID: domainID, + Links: []*types.Link{ + {Rel: "self", HREF: domainHost}, + }, + }, + client: client, + } + + intPtr := 1 + + _ = pdClient.SetName("myDomain") + _ = pdClient.SetRfcacheParams(types.PDRfCacheParams{ + RfCachePageSizeKb: 16, + RfCacheMaxIoSizeKb: 64, + }) + _ = pdClient.SetSdsNetworkLimits(types.SdsNetworkLimitParams{ + RebuildNetworkThrottlingInKbps: &intPtr, + }) + _ = pdClient.Activate(true) + _ = pdClient.InActivate(true) + _ = pdClient.EnableRfcache() + _ = pdClient.DisableRfcache() + _ = pdClient.DisableFGLMcache() + _ = pdClient.EnableFGLMcache() + _ = pdClient.SetDefaultFGLMcacheSize(128) +} diff --git a/replication_test.go b/replication_test.go new file mode 100644 index 0000000..acd4baa --- /dev/null +++ b/replication_test.go @@ -0,0 +1,796 @@ +// Copyright © 2024 Dell Inc. or its subsidiaries. All Rights Reserved. +// +// 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 goscaleio + +import ( + "encoding/json" + "errors" + "fmt" + "math" + "net/http" + "net/http/httptest" + "testing" + + types "github.com/dell/goscaleio/types/v1" + "github.com/google/uuid" +) + +func TestGetPeerMdm(t *testing.T) { + searchID := uuid.NewString() + peerMdms := []*types.PeerMDM{ + { + Name: "firstPeer", + ID: searchID, + }, + { + Name: "secondPeer", + ID: uuid.NewString(), + }, + } + + server := httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/types/PeerMdm/instances": + resp.WriteHeader(http.StatusOK) + content, err := json.Marshal(peerMdms) + if err != nil { + t.Fatal(err) + } + + resp.Write(content) + case fmt.Sprintf("/api/instances/PeerMdm::%s", searchID): + resp.WriteHeader(http.StatusOK) + var peerMdm types.PeerMDM + for _, val := range peerMdms { + if val.ID == searchID { + peerMdm = *val + } + } + + content, err := json.Marshal(peerMdm) + if err != nil { + t.Fatal(err) + } + + resp.Write(content) + default: + resp.WriteHeader(http.StatusNoContent) + } + })) + defer server.Close() + + client, err := NewClientWithArgs(server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + response, err := client.GetPeerMDMs() + if err != nil { + t.Fatal(err) + } + + if len(response) != 2 { + t.Errorf("expected %d, got %d", 2, len(response)) + } + + res, err := client.GetPeerMDM(searchID) + if err != nil || res == nil { + t.Fatal(err) + } +} + +func TestModifyPeerMdm(t *testing.T) { + searchID := uuid.NewString() + + server := httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case fmt.Sprintf("/api/instances/PeerMdm::%s/action/modifyPeerMdmIp", searchID): + fmt.Printf("modifyPeerMdmIp for %s\n", searchID) + resp.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/instances/PeerMdm::%s/action/modifyPeerMdmName", searchID): + fmt.Printf("modifyPeerMdmName for %s\n", searchID) + resp.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/instances/PeerMdm::%s/action/modifyPeerMdmPort", searchID): + fmt.Printf("modifyPeerMdmPort for %s\n", searchID) + resp.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/instances/PeerMdm::%s/action/setPeerMdmPerformanceParameters", searchID): + fmt.Printf("setPeerMdmPerformanceParameters for %s\n", searchID) + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusNoContent) + } + })) + defer server.Close() + + client, err := NewClientWithArgs(server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + ips := []string{"127.0.0.1", "127.0.0.2"} + err = client.ModifyPeerMdmIP(searchID, ips) + if err != nil { + t.Fatal(err) + } + + modifyName := types.ModifyPeerMDMNameParam{ + NewName: "newPeerName", + } + err = client.ModifyPeerMdmName(searchID, &modifyName) + if err != nil { + t.Fatal(err) + } + + modifyPort := types.ModifyPeerMDMPortParam{ + NewPort: "newPort", + } + err = client.ModifyPeerMdmPort(searchID, &modifyPort) + if err != nil { + t.Fatal(err) + } + + modifyPerf := types.ModifyPeerMdmPerformanceParametersParam{ + NewPreformanceProfile: "Compact", + } + err = client.ModifyPeerMdmPerformanceParameters(searchID, &modifyPerf) + if err != nil { + t.Fatal(err) + } +} + +func TestAddPeerMdm(t *testing.T) { + type testCase struct { + addPeerMdm *types.AddPeerMdm + server *httptest.Server + expectedErr error + } + + cases := map[string]testCase{ + "succeed": { + addPeerMdm: &types.AddPeerMdm{ + PeerSystemID: uuid.NewString(), + PeerSystemIps: []string{"127.0.0.1", "127.0.0.2"}, + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/types/PeerMdm/instances": + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + "error: no peer system ID": { + addPeerMdm: &types.AddPeerMdm{}, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusNoContent) + })), + expectedErr: errors.New("PeerSystemID and PeerSystemIps are required"), + }, + "error: bad request": { + addPeerMdm: &types.AddPeerMdm{ + PeerSystemID: uuid.NewString(), + PeerSystemIps: []string{"127.0.0.1", "127.0.0.2"}, + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"bad request","httpStatusCode":400,"errorCode":0}`)) + })), + expectedErr: errors.New("bad request"), + }, + } + + for _, tc := range cases { + client, err := NewClientWithArgs(tc.server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + _, err = client.AddPeerMdm(tc.addPeerMdm) + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestRemovePeerMdm(t *testing.T) { + peerID := uuid.NewString() + type testCase struct { + server *httptest.Server + expectedErr error + } + + cases := map[string]testCase{ + "succeed": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case fmt.Sprintf("/api/instances/PeerMdm::%s/action/removePeerMdm", peerID): + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + "error: bad request": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"bad request","httpStatusCode":400,"errorCode":0}`)) + })), + expectedErr: errors.New("bad request"), + }, + } + + for _, tc := range cases { + client, err := NewClientWithArgs(tc.server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + err = client.RemovePeerMdm(peerID) + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestGetReplicationConsistencyGroup(t *testing.T) { + searchID := uuid.NewString() + replicationGroups := []*types.ReplicationConsistencyGroup{ + { + Name: "firstReplicationGroup", + ID: searchID, + }, + { + Name: "secondReplicationGroup", + ID: uuid.NewString(), + }, + } + + server := httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/types/ReplicationConsistencyGroup/instances": + resp.WriteHeader(http.StatusOK) + content, err := json.Marshal(replicationGroups) + if err != nil { + t.Fatal(err) + } + + resp.Write(content) + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s", searchID): + resp.WriteHeader(http.StatusOK) + var group types.ReplicationConsistencyGroup + for _, val := range replicationGroups { + if val.ID == searchID { + group = *val + } + } + + content, err := json.Marshal(group) + if err != nil { + t.Fatal(err) + } + + resp.Write(content) + default: + resp.WriteHeader(http.StatusNoContent) + } + })) + defer server.Close() + + client, err := NewClientWithArgs(server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + groupsResponse, err := client.GetReplicationConsistencyGroups() + if err != nil { + t.Fatal(err) + } + + if len(groupsResponse) != 2 { + t.Errorf("expected %d, got %d", 2, len(groupsResponse)) + } + + res, err := client.GetReplicationConsistencyGroupByID(searchID) + if err != nil || res == nil { + t.Fatal(err) + } +} + +func TestCreateReplicationConsistencyGroup(t *testing.T) { + type testCase struct { + group *types.ReplicationConsistencyGroupCreatePayload + server *httptest.Server + expectedErr error + } + + cases := map[string]testCase{ + "succeed": { + group: &types.ReplicationConsistencyGroupCreatePayload{ + Name: "myReplicationGroup", + RpoInSeconds: "60", + ProtectionDomainID: uuid.NewString(), + RemoteProtectionDomainID: uuid.NewString(), + DestinationSystemID: uuid.NewString(), + PeerMdmID: uuid.NewString(), + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/types/ReplicationConsistencyGroup/instances": + resp.WriteHeader(http.StatusOK) + content, err := json.Marshal(&types.ReplicationConsistencyGroupResp{ + ID: uuid.NewString(), + }) + if err != nil { + t.Fatal(err) + } + resp.Write(content) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + "error: missing protection domain": { + group: &types.ReplicationConsistencyGroupCreatePayload{}, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusNoContent) + })), + expectedErr: errors.New("RpoInSeconds, ProtectionDomainId, and RemoteProtectionDomainId are required"), + }, + "error: missing destination system id": { + group: &types.ReplicationConsistencyGroupCreatePayload{ + Name: "myReplicationGroup", + RpoInSeconds: "60", + ProtectionDomainID: uuid.NewString(), + RemoteProtectionDomainID: uuid.NewString(), + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusNoContent) + })), + expectedErr: errors.New("either DestinationSystemId or PeerMdmId are required"), + }, + "error: bad request": { + group: &types.ReplicationConsistencyGroupCreatePayload{ + Name: "myReplicationGroup", + RpoInSeconds: "60", + ProtectionDomainID: uuid.NewString(), + RemoteProtectionDomainID: uuid.NewString(), + DestinationSystemID: uuid.NewString(), + PeerMdmID: uuid.NewString(), + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"bad request","httpStatusCode":400,"errorCode":0}`)) + })), + expectedErr: errors.New("bad request"), + }, + } + + for _, tc := range cases { + client, err := NewClientWithArgs(tc.server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + _, err = client.CreateReplicationConsistencyGroup(tc.group) + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestRemoveReplicationConsistencyGroup(t *testing.T) { + ref := "localhost" + type testCase struct { + group *types.ReplicationConsistencyGroup + server *httptest.Server + expectedErr error + } + + cases := map[string]testCase{ + "succeed": { + group: &types.ReplicationConsistencyGroup{ + Name: "myReplicationGroup", + Links: []*types.Link{ + {Rel: "self", HREF: ref}, + }, + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusNoContent) + })), + expectedErr: nil, + }, + "error: bad link": { + group: &types.ReplicationConsistencyGroup{ + Name: "myReplicationGroup", + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusNoContent) + })), + expectedErr: errors.New("Error: problem finding link"), + }, + } + + for _, tc := range cases { + client, err := NewClientWithArgs(tc.server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + rcg := NewReplicationConsistencyGroup(client) + rcg.ReplicationConsistencyGroup = tc.group + + err = rcg.RemoveReplicationConsistencyGroup(true) + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestCreateReplicationPair(t *testing.T) { + type testCase struct { + replicationPair *types.QueryReplicationPair + server *httptest.Server + expectedErr error + } + + cases := map[string]testCase{ + "succeed": { + replicationPair: &types.QueryReplicationPair{ + Name: "myReplicationPair", + SourceVolumeID: uuid.NewString(), + DestinationVolumeID: uuid.NewString(), + ReplicationConsistencyGroupID: uuid.NewString(), + CopyType: "Remote", + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case "/api/types/ReplicationPair/instances": + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + "error: missing params": { + replicationPair: &types.QueryReplicationPair{ + Name: "myReplicationPair", + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusBadRequest) + })), + expectedErr: errors.New("CopyType, SourceVolumeID, DestinationVolumeID, and ReplicationConsistencyGroupID are required"), + }, + "error: bad request": { + replicationPair: &types.QueryReplicationPair{ + Name: "myReplicationPair", + SourceVolumeID: uuid.NewString(), + DestinationVolumeID: uuid.NewString(), + ReplicationConsistencyGroupID: uuid.NewString(), + CopyType: "Remote", + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"bad request","httpStatusCode":400,"errorCode":0}`)) + })), + expectedErr: errors.New("bad request"), + }, + } + + for _, tc := range cases { + client, err := NewClientWithArgs(tc.server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + _, err = client.CreateReplicationPair(tc.replicationPair) + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestRemoveReplicationPair(t *testing.T) { + rpID := uuid.NewString() + type testCase struct { + replicationPair *types.ReplicationPair + server *httptest.Server + expectedErr error + } + + cases := map[string]testCase{ + "succeed": { + replicationPair: &types.ReplicationPair{ + Name: "myReplicationPair", + ID: rpID, + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case fmt.Sprintf("/api/instances/ReplicationPair::%s/action/removeReplicationPair", rpID): + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusNoContent) + } + })), + expectedErr: nil, + }, + "error: bad request": { + replicationPair: &types.ReplicationPair{ + Name: "myReplicationPair", + }, + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"bad request","httpStatusCode":400,"errorCode":0}`)) + })), + expectedErr: errors.New("bad request"), + }, + } + + for _, tc := range cases { + client, err := NewClientWithArgs(tc.server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + rp := NewReplicationPair(client) + rp.ReplicaitonPair = tc.replicationPair + + _, err = rp.RemoveReplicationPair(true) + if err != nil { + if tc.expectedErr.Error() != err.Error() { + t.Fatal(err) + } + } + + tc.server.Close() + } +} + +func TestReplicationPairActions(t *testing.T) { + rpID := uuid.NewString() + + replicationPair := &types.ReplicationPair{ + Name: "myReplicationPair", + ID: rpID, + } + + server := httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case fmt.Sprintf("/api/instances/ReplicationPair::%s/relationships/Statistics", rpID): + resp.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/instances/ReplicationPair::%s/action/pausePairInitialCopy", rpID): + resp.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/instances/ReplicationPair::%s/action/resumePairInitialCopy", rpID): + resp.WriteHeader(http.StatusOK) + case "/api/types/ReplicationPair/instances": + resp.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/instances/ReplicationPair::%s", rpID): + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusBadRequest) + } + })) + defer server.Close() + + client, err := NewClientWithArgs(server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + rp := NewReplicationPair(client) + rp.ReplicaitonPair = replicationPair + + _, err = rp.GetReplicationPairStatistics() + if err != nil { + t.Fatal(err) + } + + _, err = client.PausePairInitialCopy(rpID) + if err != nil { + t.Fatal(err) + } + + _, err = client.ResumePairInitialCopy(rpID) + if err != nil { + t.Fatal(err) + } + + _, err = client.GetAllReplicationPairs() + if err != nil { + t.Fatal(err) + } + + _, err = client.GetReplicationPair(rpID) + if err != nil { + t.Fatal(err) + } +} + +func TestReplicationConsistencyGroupAction(t *testing.T) { + groupID := uuid.NewString() + + server := httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/freezeApplyReplicationConsistencyGroup", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/relationships/ReplicationPair", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/unfreezeApplyReplicationConsistencyGroup", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/failoverReplicationConsistencyGroup", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/switchoverReplicationConsistencyGroup", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/restoreReplicationConsistencyGroup", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/reverseReplicationConsistencyGroup", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/pauseReplicationConsistencyGroup", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/resumeReplicationConsistencyGroup", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/syncNowReplicationConsistencyGroup", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/ModifyReplicationConsistencyGroupRpo", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/modifyReplicationConsistencyGroupTargetVolumeAccessMode", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/renameReplicationConsistencyGroup", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/setReplicationConsistencyGroupConsistent", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/setReplicationConsistencyGroupInconsistent", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/activateReplicationConsistencyGroup", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/terminateReplicationConsistencyGroup", groupID): + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/querySyncNowReplicationConsistencyGroup", groupID): + resp.WriteHeader(http.StatusOK) + case fmt.Sprintf("/api/instances/ReplicationConsistencyGroup::%s/action/createReplicationConsistencyGroupSnapshots", groupID): + fmt.Printf("createReplicationConsistencyGroupSnapshots for %s\n", groupID) + resp.WriteHeader(http.StatusOK) + content, err := json.Marshal(&types.CreateReplicationConsistencyGroupSnapshotResp{ + SnapshotGroupID: uuid.NewString(), + }) + if err != nil { + t.Fatal(err) + } + resp.Write(content) + default: + fmt.Println("Not handled. Add route.") + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"no route handled","httpStatusCode":400,"errorCode":0}`)) + } + })) + defer server.Close() + + client, err := NewClientWithArgs(server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + rcg := NewReplicationConsistencyGroup(client) + rcg.ReplicationConsistencyGroup = &types.ReplicationConsistencyGroup{ + Name: "myReplicationGroup", + ID: groupID, + } + + _, err = rcg.GetReplicationPairs() + if err != nil { + t.Fatal(err) + } + + err = rcg.FreezeReplicationConsistencyGroup(groupID) + if err != nil { + t.Fatal(err) + } + + err = rcg.UnfreezeReplicationConsistencyGroup() + if err != nil { + t.Fatal(err) + } + + _, err = rcg.CreateReplicationConsistencyGroupSnapshot() + if err != nil { + t.Fatal(err) + } + + err = rcg.ExecuteFailoverOnReplicationGroup() + if err != nil { + t.Fatal(err) + } + + err = rcg.ExecuteSwitchoverOnReplicationGroup(true) + if err != nil { + t.Fatal(err) + } + + err = rcg.ExecuteRestoreOnReplicationGroup() + if err != nil { + t.Fatal(err) + } + + err = rcg.ExecuteReverseOnReplicationGroup() + if err != nil { + t.Fatal(err) + } + + err = rcg.ExecutePauseOnReplicationGroup() + if err != nil { + t.Fatal(err) + } + + err = rcg.ExecuteResumeOnReplicationGroup() + if err != nil { + t.Fatal(err) + } + + _, err = rcg.ExecuteSyncOnReplicationGroup() + if err != nil { + t.Fatal(err) + } + + err = rcg.SetRPOOnReplicationGroup(types.SetRPOReplicationConsistencyGroup{ + RpoInSeconds: "90", + }) + if err != nil { + t.Fatal(err) + } + + err = rcg.SetTargetVolumeAccessModeOnReplicationGroup(types.SetTargetVolumeAccessModeOnReplicationGroup{ + TargetVolumeAccessMode: "ReadOnly", + }) + if err != nil { + t.Fatal(err) + } + + err = rcg.SetNewNameOnReplicationGroup(types.SetNewNameOnReplicationGroup{ + NewName: "newReplicationGroup", + }) + if err != nil { + t.Fatal(err) + } + + err = rcg.ExecuteConsistentOnReplicationGroup() + if err != nil { + t.Fatal(err) + } + + err = rcg.ExecuteInconsistentOnReplicationGroup() + if err != nil { + t.Fatal(err) + } + + err = rcg.ExecuteActivateOnReplicationGroup() + if err != nil { + t.Fatal(err) + } + + err = rcg.ExecuteTerminateOnReplicationGroup() + if err != nil { + t.Fatal(err) + } + + err = rcg.GetSyncStateOnReplicationGroup("syncKeyVal") + if err != nil { + t.Fatal(err) + } +} diff --git a/scsiinitiator_test.go b/scsiinitiator_test.go new file mode 100644 index 0000000..857819a --- /dev/null +++ b/scsiinitiator_test.go @@ -0,0 +1,73 @@ +// Copyright © 2024 Dell Inc. or its subsidiaries. All Rights Reserved. +// +// 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 goscaleio + +import ( + "errors" + "fmt" + "math" + "net/http" + "net/http/httptest" + "testing" + + types "github.com/dell/goscaleio/types/v1" + "github.com/google/uuid" +) + +func TestGetScsiInitiator(t *testing.T) { + systemID := uuid.NewString() + type testCase struct { + server *httptest.Server + expectedErr error + } + + cases := map[string]testCase{ + "succeed": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + switch req.RequestURI { + case fmt.Sprintf("/api/instances/System::%v/relationships/ScsiInitiator", systemID): + resp.WriteHeader(http.StatusOK) + default: + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"no route handled","httpStatusCode":400,"errorCode":0}`)) + } + })), + expectedErr: nil, + }, + "error: bad request": { + server: httptest.NewServer(http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusBadRequest) + resp.Write([]byte(`{"message":"bad request","httpStatusCode":400,"errorCode":0}`)) + })), + expectedErr: errors.New("bad request"), + }, + } + + for _, tc := range cases { + client, err := NewClientWithArgs(tc.server.URL, "3.6", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + system := System{ + System: &types.System{ + ID: systemID, + }, + client: client, + } + + system.GetScsiInitiator() + + tc.server.Close() + } +}