diff --git a/go.mod b/go.mod index d90ddb84..6263c60a 100644 --- a/go.mod +++ b/go.mod @@ -15,12 +15,17 @@ require ( github.com/spf13/cobra v1.3.0 github.com/spf13/viper v1.10.1 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.26.0 - k8s.io/apimachinery v0.26.0 + k8s.io/api v0.27.3 + k8s.io/apimachinery v0.27.3 k8s.io/client-go v12.0.0+incompatible sigs.k8s.io/yaml v1.3.0 ) +require ( + github.com/pmezard/go-difflib v1.0.0 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect +) + require ( github.com/chzyer/readline v1.5.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -56,9 +61,10 @@ require ( github.com/spf13/cast v1.4.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/testify v1.8.4 github.com/subosito/gotenv v1.2.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect + golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect @@ -70,9 +76,9 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.66.3 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/klog/v2 v2.80.1 // indirect - k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf // indirect - k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect + k8s.io/klog/v2 v2.90.1 // indirect + k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect + k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect sigs.k8s.io/controller-runtime v0.11.1 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) diff --git a/go.sum b/go.sum index ce27072e..60b97b89 100644 --- a/go.sum +++ b/go.sum @@ -135,19 +135,12 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= -github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= +github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -423,7 +416,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= @@ -909,35 +903,26 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.21.2 h1:vz7DqmRsXTCSa6pNxXwQ1IYeAZgdIsua+DZU+o+SX3Y= -k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU= -k8s.io/apimachinery v0.21.2 h1:vezUc/BHqWlQDnZ+XkrpXSmnANSLbpnlpwo0Lhk0gpc= -k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM= -k8s.io/client-go v0.21.2 h1:Q1j4L/iMN4pTw6Y4DWppBoUxgKO8LbffEMVEV00MUp0= -k8s.io/client-go v0.21.2/go.mod h1:HdJ9iknWpbl3vMGtib6T2PyI/VYxiZfq936WNVHBRrA= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= -k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= -k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf h1:M9XBsiMslw2lb2ZzglC0TOkBPK5NQi0/noUrdnoFwUg= -k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= -k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs= -k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/api v0.27.3 h1:yR6oQXXnUEBWEWcvPWS0jQL575KoAboQPfJAuKNrw5Y= +k8s.io/api v0.27.3/go.mod h1:C4BNvZnQOF7JA/0Xed2S+aUyJSfTGkGFxLXz9MnpIpg= +k8s.io/apimachinery v0.27.3 h1:Ubye8oBufD04l9QnNtW05idcOe9Z3GQN8+7PqmuVcUM= +k8s.io/apimachinery v0.27.3/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= +k8s.io/client-go v0.27.3 h1:7dnEGHZEJld3lYwxvLl7WoehK6lAq7GvgjxpA3nv1E8= +k8s.io/client-go v0.27.3/go.mod h1:2MBEKuTo6V1lbKy3z1euEGnhPfGZLKTS9tiJ2xodM48= +k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= +k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= +k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= +k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/controller-runtime v0.11.1 h1:7YIHT2QnHJArj/dk9aUkYhfqfK5cIxPOX5gPECfdZLU= sigs.k8s.io/controller-runtime v0.11.1/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA= -sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/pkg/apis/auth.go b/pkg/apis/auth.go index 5b2c3b42..3fc20f1f 100644 --- a/pkg/apis/auth.go +++ b/pkg/apis/auth.go @@ -1,6 +1,5 @@ /* Copyright © 2021 The LitmusChaos Authors - 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 @@ -26,12 +25,33 @@ import ( "github.com/litmuschaos/litmusctl/pkg/types" ) +// HTTPClient interface +type HTTPClientInterface interface { + Do(req *http.Request) (*http.Response, error) +} + +var ( + Client HTTPClientInterface +) + +func init() { + Client = &httpClient{http.Client{}} +} + +type httpClient struct { + client http.Client +} + +func (c *httpClient) Do(req *http.Request) (*http.Response, error) { + return c.client.Do(req) +} + type Payload struct { Username string `json:"username"` Password string `json:"password"` } -func Auth(input types.AuthInput) (types.AuthResponse, error) { +func Auth(input types.AuthInput, httpClient HTTPClientInterface) (types.AuthResponse, error) { payloadBytes, err := json.Marshal(Payload{ Username: input.Username, Password: input.Password, @@ -41,8 +61,8 @@ func Auth(input types.AuthInput) (types.AuthResponse, error) { return types.AuthResponse{}, err } - // Sending token as empty because auth server doesn't need Authorization token to validate. - resp, err := SendRequest(SendRequestParams{input.Endpoint + utils.AuthAPIPath + "/login", ""}, payloadBytes, string(types.Post)) + resp, err := SendRequest(SendRequestParams{input.Endpoint + utils.AuthAPIPath + "/login", ""}, Client, payloadBytes, string(types.Post)) + if err != nil { return types.AuthResponse{}, err } diff --git a/pkg/apis/auth_test.go b/pkg/apis/auth_test.go new file mode 100644 index 00000000..af2f33ec --- /dev/null +++ b/pkg/apis/auth_test.go @@ -0,0 +1,87 @@ +package apis + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "testing" + + "github.com/litmuschaos/litmusctl/pkg/types" +) + +var originalClient = Client + +type MockHTTPClientAuth struct { + mockResponse types.AuthResponse + mockError error +} + +func (c *MockHTTPClientAuth) Do(req *http.Request) (*http.Response, error) { + if c.mockError != nil { + return nil, c.mockError + } + + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader([]byte(`{"AccessToken": "mocked_token"}`))), + }, nil +} + +func TestAuthSuccess(t *testing.T) { + // Store the original HTTP client and restore it after the test. + defer func() { + Client = originalClient + }() + + // Create an instance of the MockHTTPClient. + mockClient := &MockHTTPClientAuth{} + + // Replace the global HTTP client with the mock client for this test. + Client = mockClient + + input := types.AuthInput{ + Username: "testuser", + Password: "testpassword", + Endpoint: "https://example.com", + } + + // Call the Auth function with the test input. + authResponse, err := Auth(input, mockClient) + + if err != nil { + t.Fatalf("Expected no error, but got %v", err) + } + + if authResponse.AccessToken != "mocked_token" { + t.Fatalf("Expected token 'mocked_token', but got %s", authResponse.AccessToken) + } +} + +func TestAuthFailed(t *testing.T) { + + defer func() { + Client = originalClient + }() + mockClient := &MockHTTPClientAuth{ + mockError: fmt.Errorf("mocked error"), + } + + Client = mockClient + + input := types.AuthInput{ + Username: "testuser", + Password: "testpassword", + Endpoint: "https://example.com", + } + + _, err := Auth(input, mockClient) + // fmt.Println("Response:", res) + if err == nil { + t.Fatal("Expected an error, but got nil") + } + expectedErrorMessage := "mocked error" + if err.Error() != expectedErrorMessage { + t.Fatalf("Expected error message '%s', but got '%s'", expectedErrorMessage, err.Error()) + } +} diff --git a/pkg/apis/environment/environment.go b/pkg/apis/environment/environment.go index 4721324c..41564706 100644 --- a/pkg/apis/environment/environment.go +++ b/pkg/apis/environment/environment.go @@ -3,23 +3,25 @@ package environment import ( "encoding/json" "errors" + "io/ioutil" + "net/http" + models "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" "github.com/litmuschaos/litmusctl/pkg/apis" "github.com/litmuschaos/litmusctl/pkg/types" "github.com/litmuschaos/litmusctl/pkg/utils" - "io/ioutil" - "net/http" ) // CreateEnvironment connects the Infra with the given details -func CreateEnvironment(pid string, request models.CreateEnvironmentRequest, cred types.Credentials) (CreateEnvironmentResponse, error) { +func CreateEnvironment(pid string, request models.CreateEnvironmentRequest, cred types.Credentials, httpClient apis.HTTPClientInterface) (CreateEnvironmentResponse, error) { var gqlReq CreateEnvironmentGQLRequest gqlReq.Query = CreateEnvironmentQuery gqlReq.Variables.ProjectId = pid gqlReq.Variables.Request = request - query, err := json.Marshal(gqlReq) - resp, err := apis.SendRequest(apis.SendRequestParams{Endpoint: cred.ServerEndpoint + utils.GQLAPIPath, Token: cred.Token}, query, string(types.Post)) + query, _ := json.Marshal(gqlReq) + resp, err := apis.SendRequest(apis.SendRequestParams{Endpoint: cred.Endpoint + utils.GQLAPIPath, Token: cred.Token}, httpClient, query, string(types.Post)) + if err != nil { return CreateEnvironmentResponse{}, errors.New("Error in Creating Chaos Infrastructure: " + err.Error()) } @@ -31,6 +33,7 @@ func CreateEnvironment(pid string, request models.CreateEnvironmentRequest, cred } if resp.StatusCode == http.StatusOK { + var connectEnvironment CreateEnvironmentResponse err = json.Unmarshal(bodyBytes, &connectEnvironment) if err != nil { @@ -46,7 +49,7 @@ func CreateEnvironment(pid string, request models.CreateEnvironmentRequest, cred } } -func GetEnvironmentList(pid string, cred types.Credentials) (ListEnvironmentData, error) { +func GetEnvironmentList(pid string, cred types.Credentials, httpClient apis.HTTPClientInterface) (ListEnvironmentData, error) { var err error var gqlReq CreateEnvironmentListGQLRequest gqlReq.Query = ListEnvironmentQuery @@ -62,6 +65,7 @@ func GetEnvironmentList(pid string, cred types.Credentials) (ListEnvironmentData Endpoint: cred.ServerEndpoint + utils.GQLAPIPath, Token: cred.Token, }, + httpClient, query, string(types.Post), ) diff --git a/pkg/apis/environment/environment_test.go b/pkg/apis/environment/environment_test.go new file mode 100644 index 00000000..993e19b2 --- /dev/null +++ b/pkg/apis/environment/environment_test.go @@ -0,0 +1,331 @@ +package environment + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "testing" + + models "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" + "github.com/litmuschaos/litmusctl/pkg/types" + "github.com/stretchr/testify/assert" +) + +type MockHTTPClientCreate struct { + mockError error + mockResponse CreateEnvironmentResponse +} + +func (c *MockHTTPClientCreate) Do(req *http.Request) (*http.Response, error) { + if c.mockError != nil { + return nil, c.mockError + } + data, err := json.Marshal(c.mockResponse) + if err != nil { + return nil, err + } + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader(data)), + }, nil + +} + +type MockHTTPClientGet struct { + mockResponse ListEnvironmentData + mockError error +} + +func (c *MockHTTPClientGet) Do(req *http.Request) (*http.Response, error) { + if c.mockError != nil { + return nil, c.mockError + } + data, err := json.Marshal(c.mockResponse) + if err != nil { + return nil, err + } + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader(data)), + }, nil +} + +func TestCreateEnvironmentSuccess(t *testing.T) { + //define the mock request + mockRequest := models.CreateEnvironmentRequest{ + EnvironmentID: "env123", + Name: "Test Environment", + Type: "Development", + Description: nil, + } + //custom input + input := types.Credentials{ + Username: "testuser", + Token: "testtoken", + Endpoint: "https://example.com", + } + + //define the mock data response + + mockData := CreateEnvironmentResponse{ + Errors: []struct { + Message string `json:"message"` + Path []string `json:"path"` + }(nil), + Data: CreateEnvironmentData{ + EnvironmentDetails: models.Environment{ + ProjectID: "project123", + EnvironmentID: "env123", + Name: "Test Environment", + Description: nil, + Tags: []string{"tag1", "tag2"}, + Type: "Development", + CreatedAt: "2023-10-13", + CreatedBy: &models.UserDetails{ + UserID: "user123", + Username: "JohnDoe", + Email: "johndoe@example.com", + }, + UpdatedBy: &models.UserDetails{ + UserID: "user456", + Username: "JaneSmith", + Email: "janesmith@example.com", + }, + UpdatedAt: "2023-10-14", + IsRemoved: nil, + InfraIDs: []string{"infra1", "infra2"}, + }, + }, + } + + mockClient := &MockHTTPClientCreate{ + mockResponse: mockData, + mockError: nil, // Set this to nil if you don't want to return an error. + } + + result, err := CreateEnvironment("testpid", mockRequest, input, mockClient) + + if err != nil { + fmt.Println(err) + } + assert.Equal(t, mockData, result) +} + +func TestCreateEnvironmentFailed(t *testing.T) { + //define the mock request + mockRequest := models.CreateEnvironmentRequest{ + EnvironmentID: "env123", + Name: "Test Environment", + Type: "Development", + Description: nil, + } + //custom input + input := types.Credentials{ + Username: "testuser", + Token: "testtoken", + Endpoint: "https://example.com", + } + + //define the mock data response + + mockData := CreateEnvironmentResponse{ + Errors: []struct { + Message string `json:"message"` + Path []string `json:"path"` + }{ + { + Message: "Error message 1", + Path: []string{"path1", "path2"}, + }, + }, + Data: CreateEnvironmentData{ + EnvironmentDetails: models.Environment{ + ProjectID: "project123", + EnvironmentID: "env123", + Name: "Test Environment", + Description: nil, + Tags: []string{"tag1", "tag2"}, + Type: "Development", + CreatedAt: "2023-10-13", + CreatedBy: &models.UserDetails{ + UserID: "user123", + Username: "JohnDoe", + Email: "johndoe@example.com", + }, + UpdatedBy: &models.UserDetails{ + UserID: "user456", + Username: "JaneSmith", + Email: "janesmith@example.com", + }, + UpdatedAt: "2023-10-14", + IsRemoved: nil, + InfraIDs: []string{"infra1", "infra2"}, + }, + }, + } + + mockClient := &MockHTTPClientCreate{ + mockResponse: mockData, + mockError: nil, + } + + result, _ := CreateEnvironment("testpid", mockRequest, input, mockClient) + + assert.NotEqual(t, mockData, result) +} + +func TestGetEnvironmentListSuccess(t *testing.T) { + + mockData := ListEnvironmentData{ + Errors: []struct { + Message string `json:"message"` + Path []string `json:"path"` + }{ + //keeping the error empty for asserting + }, + Data: EnvironmentsList{ + ListEnvironmentDetails: models.ListEnvironmentResponse{ + TotalNoOfEnvironments: 2, + Environments: []*models.Environment{ + { + ProjectID: "project1", + EnvironmentID: "env1", + Name: "Environment 1", + Description: nil, + Tags: []string{"tag1", "tag2"}, + Type: "Development", + CreatedAt: "2023-10-13", + CreatedBy: &models.UserDetails{ + UserID: "user1", + Username: "JohnDoe", + }, + UpdatedBy: &models.UserDetails{ + UserID: "user2", + Username: "JaneSmith", + }, + UpdatedAt: "2023-10-14", + IsRemoved: nil, + InfraIDs: []string{"infra1", "infra2"}, + }, + { + ProjectID: "project2", + EnvironmentID: "env2", + Name: "Environment 2", + Description: nil, + Tags: []string{"tag3", "tag4"}, + Type: "Production", + CreatedAt: "2023-10-15", + CreatedBy: &models.UserDetails{ + UserID: "user3", + Username: "AliceJohnson", + }, + UpdatedBy: &models.UserDetails{ + UserID: "user4", + Username: "BobWilliams", + }, + UpdatedAt: "2023-10-16", + IsRemoved: nil, + InfraIDs: []string{"infra3", "infra4"}, + }, + }, + }, + }, + } + + mockClient := &MockHTTPClientGet{ + mockResponse: mockData, + mockError: nil, + } + + input := types.Credentials{ + Username: "testuser", + Token: "testtoken", + Endpoint: "https://example.com", + } + + result, err := GetEnvironmentList("testpid", input, mockClient) + + if err != nil { + fmt.Println(err) + } + assert.Equal(t, mockData, result) +} + +func TestGetEnvironmentListFailed(t *testing.T) { + + mockData := ListEnvironmentData{ + Errors: []struct { + Message string `json:"message"` + Path []string `json:"path"` + }{ + { + Message: "Error message 1", + Path: []string{"path1", "path2"}, + }, + }, + Data: EnvironmentsList{ + ListEnvironmentDetails: models.ListEnvironmentResponse{ + TotalNoOfEnvironments: 2, + Environments: []*models.Environment{ + { + ProjectID: "project1", + EnvironmentID: "env1", + Name: "Environment 1", + Description: nil, + Tags: []string{"tag1", "tag2"}, + Type: "Development", + CreatedAt: "2023-10-13", + CreatedBy: &models.UserDetails{ + UserID: "user1", + Username: "JohnDoe", + }, + UpdatedBy: &models.UserDetails{ + UserID: "user2", + Username: "JaneSmith", + }, + UpdatedAt: "2023-10-14", + IsRemoved: nil, + InfraIDs: []string{"infra1", "infra2"}, + }, + { + ProjectID: "project2", + EnvironmentID: "env2", + Name: "Environment 2", + Description: nil, + Tags: []string{"tag3", "tag4"}, + Type: "Production", + CreatedAt: "2023-10-15", + CreatedBy: &models.UserDetails{ + UserID: "user3", + Username: "AliceJohnson", + }, + UpdatedBy: &models.UserDetails{ + UserID: "user4", + Username: "BobWilliams", + }, + UpdatedAt: "2023-10-16", + IsRemoved: nil, + InfraIDs: []string{"infra3", "infra4"}, + }, + }, + }, + }, + } + + mockClient := &MockHTTPClientGet{ + mockResponse: mockData, + mockError: nil, + } + + input := types.Credentials{ + Username: "testuser", + Token: "testtoken", + Endpoint: "https://example.com", + } + + result, _ := GetEnvironmentList("testpid", input, mockClient) + + assert.NotEqual(t, mockData, result) +} diff --git a/pkg/apis/experiment/experiment.go b/pkg/apis/experiment/experiment.go index 7ec17dbc..e0e73910 100644 --- a/pkg/apis/experiment/experiment.go +++ b/pkg/apis/experiment/experiment.go @@ -1,6 +1,5 @@ /* Copyright © 2021 The LitmusChaos Authors - 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 @@ -28,9 +27,8 @@ import ( ) // CreateExperiment sends GraphQL API request for creating a Experiment -func CreateExperiment(pid string, requestData model.SaveChaosExperimentRequest, cred types.Credentials) (RunExperimentResponse, error) { +func CreateExperiment(pid string, requestData model.SaveChaosExperimentRequest, cred types.Credentials, httpClient apis.HTTPClientInterface) (RunExperimentResponse, error) { - // Query to Save the Experiment var gqlReq SaveChaosExperimentGraphQLRequest gqlReq.Query = SaveExperimentQuery @@ -47,6 +45,7 @@ func CreateExperiment(pid string, requestData model.SaveChaosExperimentRequest, Endpoint: cred.ServerEndpoint + utils.GQLAPIPath, Token: cred.Token, }, + httpClient, query, string(types.Post), ) @@ -81,7 +80,8 @@ func CreateExperiment(pid string, requestData model.SaveChaosExperimentRequest, // Query to Run the Chaos Experiment runQuery := `{"query":"mutation{ \n runChaosExperiment(experimentID: \"` + requestData.ID + `\", projectID: \"` + pid + `\"){\n notifyID \n}}"}` - resp, err = apis.SendRequest(apis.SendRequestParams{Endpoint: cred.ServerEndpoint + utils.GQLAPIPath, Token: cred.Token}, []byte(runQuery), string(types.Post)) + + resp, err = apis.SendRequest(apis.SendRequestParams{Endpoint: cred.Endpoint + utils.GQLAPIPath, Token: cred.Token}, httpClient, []byte(runQuery), string(types.Post)) if err != nil { return RunExperimentResponse{}, errors.New("Error in Running Chaos Experiment: " + err.Error()) @@ -109,7 +109,7 @@ func CreateExperiment(pid string, requestData model.SaveChaosExperimentRequest, } } -func SaveExperiment(pid string, requestData model.SaveChaosExperimentRequest, cred types.Credentials) (SaveExperimentData, error) { +func SaveExperiment(pid string, requestData model.SaveChaosExperimentRequest, cred types.Credentials, httpClient apis.HTTPClientInterface) (SaveExperimentData, error) { // Query to Save the Experiment var gqlReq SaveChaosExperimentGraphQLRequest @@ -128,6 +128,7 @@ func SaveExperiment(pid string, requestData model.SaveChaosExperimentRequest, cr Endpoint: cred.ServerEndpoint + utils.GQLAPIPath, Token: cred.Token, }, + httpClient, query, string(types.Post), ) @@ -163,11 +164,11 @@ func SaveExperiment(pid string, requestData model.SaveChaosExperimentRequest, cr } -func RunExperiment(pid string, eid string, cred types.Credentials) (RunExperimentResponse, error) { +func RunExperiment(pid string, eid string, cred types.Credentials, httpClient apis.HTTPClientInterface) (RunExperimentResponse, error) { var err error runQuery := `{"query":"mutation{ \n runChaosExperiment(experimentID: \"` + eid + `\", projectID: \"` + pid + `\"){\n notifyID \n}}"}` - resp, err := apis.SendRequest(apis.SendRequestParams{Endpoint: cred.ServerEndpoint + utils.GQLAPIPath, Token: cred.Token}, []byte(runQuery), string(types.Post)) + resp, err := apis.SendRequest(apis.SendRequestParams{Endpoint: cred.Endpoint + utils.GQLAPIPath, Token: cred.Token}, httpClient, []byte(runQuery), string(types.Post)) if err != nil { return RunExperimentResponse{}, errors.New("Error in Running Chaos Experiment: " + err.Error()) @@ -196,7 +197,7 @@ func RunExperiment(pid string, eid string, cred types.Credentials) (RunExperimen } // GetExperimentList sends GraphQL API request for fetching a list of experiments. -func GetExperimentList(pid string, in model.ListExperimentRequest, cred types.Credentials) (ExperimentListData, error) { +func GetExperimentList(pid string, in model.ListExperimentRequest, cred types.Credentials, httpClient apis.HTTPClientInterface) (ExperimentListData, error) { var gqlReq GetChaosExperimentsGraphQLRequest var err error @@ -214,7 +215,7 @@ func GetExperimentList(pid string, in model.ListExperimentRequest, cred types.Cr apis.SendRequestParams{ Endpoint: cred.ServerEndpoint + utils.GQLAPIPath, Token: cred.Token, - }, + }, httpClient, query, string(types.Post), ) @@ -246,7 +247,7 @@ func GetExperimentList(pid string, in model.ListExperimentRequest, cred types.Cr } // GetExperimentRunsList sends GraphQL API request for fetching a list of experiment runs. -func GetExperimentRunsList(pid string, in model.ListExperimentRunRequest, cred types.Credentials) (ExperimentRunListData, error) { +func GetExperimentRunsList(pid string, in model.ListExperimentRunRequest, cred types.Credentials, httpClient apis.HTTPClientInterface) (ExperimentRunListData, error) { var gqlReq GetChaosExperimentRunGraphQLRequest var err error @@ -264,7 +265,7 @@ func GetExperimentRunsList(pid string, in model.ListExperimentRunRequest, cred t apis.SendRequestParams{ Endpoint: cred.ServerEndpoint + utils.GQLAPIPath, Token: cred.Token, - }, + }, httpClient, query, string(types.Post), ) @@ -296,7 +297,7 @@ func GetExperimentRunsList(pid string, in model.ListExperimentRunRequest, cred t } // DeleteChaosExperiment sends GraphQL API request for deleting a given Chaos Experiment. -func DeleteChaosExperiment(projectID string, experimentID *string, cred types.Credentials) (DeleteChaosExperimentData, error) { +func DeleteChaosExperiment(projectID string, experimentID *string, cred types.Credentials, httpClient apis.HTTPClientInterface) (DeleteChaosExperimentData, error) { var gqlReq DeleteChaosExperimentGraphQLRequest var err error @@ -317,6 +318,7 @@ func DeleteChaosExperiment(projectID string, experimentID *string, cred types.Cr Endpoint: cred.ServerEndpoint + utils.GQLAPIPath, Token: cred.Token, }, + httpClient, query, string(types.Post), ) @@ -348,12 +350,12 @@ func DeleteChaosExperiment(projectID string, experimentID *string, cred types.Cr } // GetServerVersion fetches the GQL server version -func GetServerVersion(endpoint string) (ServerVersionResponse, error) { +func GetServerVersion(endpoint string, httpClient apis.HTTPClientInterface) (ServerVersionResponse, error) { query := `{"query":"query{\n getServerVersion{\n key value\n }\n}"}` resp, err := apis.SendRequest( apis.SendRequestParams{ Endpoint: endpoint + utils.GQLAPIPath, - }, + }, httpClient, []byte(query), string(types.Post), ) diff --git a/pkg/apis/experiment/experiment_test.go b/pkg/apis/experiment/experiment_test.go new file mode 100644 index 00000000..b53a1e52 --- /dev/null +++ b/pkg/apis/experiment/experiment_test.go @@ -0,0 +1,567 @@ +package experiment + +import ( + "bytes" + "encoding/json" + "errors" + "io/ioutil" + "net/http" + "testing" + + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" + "github.com/litmuschaos/litmusctl/pkg/types" + + "github.com/stretchr/testify/assert" +) + +type MockHTTPClientCreateExperiment struct { + mockResponse RunExperimentResponse + mockError error +} + +func (c *MockHTTPClientCreateExperiment) Do(req *http.Request) (*http.Response, error) { + if c.mockError != nil { + return nil, c.mockError + } + data, err := json.Marshal(c.mockResponse) + if err != nil { + return nil, err + } + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader(data)), + }, nil +} + +func TestCreateExperimentSuccess(t *testing.T) { + + pid := "testprojectid" + requestData := model.SaveChaosExperimentRequest{ + ID: "test-experiment-id", + Name: "Test Experiment", + Description: "A test experiment for unit testing", + Manifest: "apiVersion: v1\nkind: Pod\nmetadata:\n name: nginx\nspec:\n containers:\n - name: nginx\n image: nginx", + InfraID: "test-infras-id", + Tags: []string{"tag1", "tag2"}, + } + cred := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + // Create a mock HTTP client with a successful response + mockResponse := RunExperimentResponse{} + mockClient := &MockHTTPClientCreateExperiment{ + mockError: nil, + mockResponse: mockResponse, + } + + result, _ := CreateExperiment(pid, requestData, cred, mockClient) + + // Assertions + assert.Equal(t, result, mockResponse) // Ensure the result matches the expected response +} + +func TestCreateExperimentFailedRequest(t *testing.T) { + + pid := "testprojectid" + requestData := model.SaveChaosExperimentRequest{ + ID: "test-experiment-id", + Name: "Test Experiment", + Description: "A test experiment for unit testing", + Manifest: "apiVersion: v1\nkind: Pod\nmetadata:\n name: nginx\nspec:\n containers:\n - name: nginx\n image: nginx", + InfraID: "test-infras-id", + Tags: []string{"tag1", "tag2"}, + } + cred := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + mockClient := &MockHTTPClientCreateExperiment{ + mockError: errors.New("Some error occurred"), + mockResponse: RunExperimentResponse{}, + } + + result, err := CreateExperiment(pid, requestData, cred, mockClient) + + // Assertions + assert.Error(t, err) // Ensure an error occurred + assert.Equal(t, result, RunExperimentResponse{}) // Ensure the result is an empty response +} + +// TestGetExperimentSuccess tests the GetExperiment function with a successful response. +type MockHTTPClientSaveExperiment struct { + mockResponse SaveExperimentData + mockError error +} + +func (c *MockHTTPClientSaveExperiment) Do(req *http.Request) (*http.Response, error) { + if c.mockError != nil { + return nil, c.mockError + } + data, err := json.Marshal(c.mockResponse) + if err != nil { + return nil, err + } + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader(data)), + }, nil +} +func TestSaveExperimentSuccess(t *testing.T) { + + pid := "testprojectid" + requestData := model.SaveChaosExperimentRequest{ + ID: "test-experiment-id", + Name: "Test Experiment", + Description: "A test experiment for unit testing", + Manifest: "apiVersion: v1\nkind: Pod\nmetadata:\n name: nginx\nspec:\n containers:\n - name: nginx\n image: nginx", + InfraID: "test-infras-id", + Tags: []string{"tag1", "tag2"}, + } + cred := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + // Create a mock HTTP client with a successful response + mockResponse := SaveExperimentData{} + mockClient := &MockHTTPClientSaveExperiment{ + mockError: nil, + mockResponse: mockResponse, + } + + result, _ := SaveExperiment(pid, requestData, cred, mockClient) + + // Assertion + assert.Equal(t, result, mockResponse) +} + +func TestSaveExperimentFailedRequest(t *testing.T) { + + pid := "testprojectid" + requestData := model.SaveChaosExperimentRequest{ + ID: "test-experiment-id", + Name: "Test Experiment", + Description: "A test experiment for unit testing", + Manifest: "apiVersion: v1\nkind: Pod\nmetadata:\n name: nginx\nspec:\n containers:\n - name: nginx\n image: nginx", + InfraID: "test-infras-id", + Tags: []string{"tag1", "tag2"}, + } + cred := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + // Create a mock HTTP client with an error response + mockClient := &MockHTTPClientSaveExperiment{ + mockError: errors.New("Some error occurred"), + mockResponse: SaveExperimentData{}, + } + + _, err := SaveExperiment(pid, requestData, cred, mockClient) + + assert.Error(t, err) // Ensure an error occurred + +} + +type MockHTTPClientRunExperiment struct { + mockResponse RunExperimentResponse + mockError error +} + +func (c *MockHTTPClientRunExperiment) Do(req *http.Request) (*http.Response, error) { + if c.mockError != nil { + return nil, c.mockError + } + data, err := json.Marshal(c.mockResponse) + if err != nil { + return nil, err + } + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader(data)), + }, nil +} + +func TestRunExperimentSuccess(t *testing.T) { + + pid := "testprojectid" + eid := "testexperimentid" + cred := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + // Create a mock HTTP client with a successful response + mockResponse := RunExperimentResponse{} + mockClient := &MockHTTPClientRunExperiment{ + mockError: nil, + mockResponse: mockResponse, + } + + result, err := RunExperiment(pid, eid, cred, mockClient) + + // Assertions + assert.NoError(t, err) // Ensure no errors occurred + assert.Equal(t, result, mockResponse) // Ensure the result matches the expected response +} + +func TestRunExperimentFailedRequest(t *testing.T) { + pid := "testprojectid" + eid := "testexperimentid" + cred := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + mockClient := &MockHTTPClientRunExperiment{ + mockError: errors.New("Some error occurred"), + mockResponse: RunExperimentResponse{}, + } + + result, _ := RunExperiment(pid, eid, cred, mockClient) + + // Assertions + // assert.Error(t, err) // Ensure an error occurred + assert.Empty(t, result.Data.RunExperimentDetails.NotifyID) // Ensure NotifyID is empty +} + +type MockHTTPClientGetExperimentList struct { + mockResponse ExperimentListData + mockError error +} + +func (c *MockHTTPClientGetExperimentList) Do(req *http.Request) (*http.Response, error) { + if c.mockError != nil { + return nil, c.mockError + } + data, err := json.Marshal(c.mockResponse) + if err != nil { + return nil, err + } + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader(data)), + }, nil +} + +func TestGetExperimentListSuccess(t *testing.T) { + pid := "testprojectid" + requestData := model.ListExperimentRequest{ + ExperimentIDs: []*string{nil}, + Pagination: &model.Pagination{ + Page: 1, + Limit: 10, + }, + Sort: &model.ExperimentSortInput{ + Field: "name", + }, + Filter: &model.ExperimentFilterInput{}, + } + cred := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + mockData := ExperimentListData{ + Errors: []struct { + Message string `json:"message"` + Path []string `json:"path"` + }{}, + Data: ExperimentList{ + ListExperimentDetails: model.ListExperimentResponse{ + TotalNoOfExperiments: 1, + Experiments: []*model.Experiment{ + { + Name: "testexperiment", + }, + }, + }, + }, + } + + mockResponse := mockData + mockClient := &MockHTTPClientGetExperimentList{ + mockError: nil, + mockResponse: mockResponse, + } + + result, err := GetExperimentList(pid, requestData, cred, mockClient) + + // Assertions + assert.NoError(t, err) // Ensure no errors occurred + assert.Equal(t, result, mockResponse) // Ensure the result matches the expected response +} + +func TestGetExperimentListFailedRequest(t *testing.T) { + + pid := "testprojectid" + requestData := model.ListExperimentRequest{ + ExperimentIDs: []*string{nil}, + Pagination: &model.Pagination{ + Page: 1, + Limit: 10, + }, + Sort: &model.ExperimentSortInput{ + Field: "name", + }, + Filter: &model.ExperimentFilterInput{}, + } + cred := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + mockClient := &MockHTTPClientGetExperimentList{ + mockError: errors.New("Some error occurred"), + mockResponse: ExperimentListData{}, + } + + result, err := GetExperimentList(pid, requestData, cred, mockClient) + + // Assertions + assert.Error(t, err, "Expected an error") + assert.Equal(t, result, ExperimentListData{}, "Expected an empty response") +} + +type MockHTTPClientGetExperimentRunsList struct { + mockResponse ExperimentRunListData + mockError error +} + +func (c *MockHTTPClientGetExperimentRunsList) Do(req *http.Request) (*http.Response, error) { + if c.mockError != nil { + return nil, c.mockError + } + data, err := json.Marshal(c.mockResponse) + if err != nil { + return nil, err + } + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader(data)), + }, nil +} + +func TestGetExperimentRunsListSuccess(t *testing.T) { + + pid := "testprojectid" + requestData := model.ListExperimentRunRequest{ + ExperimentRunIDs: []*string{nil}, + Pagination: &model.Pagination{ + Page: 1, + Limit: 10, + }, + Sort: &model.ExperimentRunSortInput{ + Field: "name", + }, + Filter: &model.ExperimentRunFilterInput{}, + } + cred := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + mockData := ExperimentRunListData{ + Errors: []struct { + Message string `json:"message"` + Path []string `json:"path"` + }{}, + Data: ExperimentRunsList{}, + } + + mockResponse := mockData + mockClient := &MockHTTPClientGetExperimentRunsList{ + mockError: nil, + mockResponse: mockResponse, + } + + result, err := GetExperimentRunsList(pid, requestData, cred, mockClient) + + // Assertions + assert.NoError(t, err) // Ensure no errors occurred + assert.Equal(t, result, mockResponse) // Ensure the result matches the expected response +} + +type MockHTTPClientGetServerVersion struct { + mockResponse ServerVersionResponse + mockError error +} + +func (c *MockHTTPClientGetServerVersion) Do(req *http.Request) (*http.Response, error) { + + if c.mockError != nil { + return nil, c.mockError + } + data, err := json.Marshal(c.mockResponse) + if err != nil { + return nil, err + } + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader(data)), + }, nil +} + +func TestGetExperimentRunsListFailure(t *testing.T) { + + pid := "testprojectid" + requestData := model.ListExperimentRunRequest{ + ExperimentRunIDs: []*string{nil}, + Pagination: &model.Pagination{ + Page: 1, + Limit: 10, + }, + Sort: &model.ExperimentRunSortInput{ + Field: "name", + }, + Filter: &model.ExperimentRunFilterInput{}, + } + cred := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + mockClient := &MockHTTPClientGetExperimentRunsList{ + mockError: errors.New("Some error occurred"), + mockResponse: ExperimentRunListData{}, + } + + result, err := GetExperimentRunsList(pid, requestData, cred, mockClient) + + // Assertions + assert.Error(t, err, "Expected an error") + assert.Equal(t, result, ExperimentRunListData{}, "Expected an empty response") +} + +func TestGetServerVersionSuccess(t *testing.T) { + endpoint := "https://example.com" + mockResponse := ServerVersionResponse{ + Data: ServerVersionData{ + GetServerVersion: GetServerVersionData{ + Key: "version", + Value: "1.0", + }, + }, + Errors: nil, + } + + mockClient := &MockHTTPClientGetServerVersion{ + mockError: nil, + mockResponse: mockResponse, + } + + result, err := GetServerVersion(endpoint, mockClient) + + // Assertions + assert.NoError(t, err) + assert.Equal(t, result, mockResponse) +} + +// TestGetServerVersionFailedRequest tests the GetServerVersion function with a failed request. +func TestGetServerVersionFailedRequest(t *testing.T) { + + endpoint := "https://example.com" + + mockClient := &MockHTTPClientGetServerVersion{ + mockError: errors.New("Some error occurred"), + mockResponse: ServerVersionResponse{}, + } + + result, err := GetServerVersion(endpoint, mockClient) + + // Assertions + assert.Error(t, err) // Ensure an error occurred + assert.Equal(t, result, ServerVersionResponse{}) // Ensure the result is an empty response +} + +type MockHTTPClientDeleteExperiment struct { + mockResponse DeleteChaosExperimentData + mockError error +} + +func (c *MockHTTPClientDeleteExperiment) Do(req *http.Request) (*http.Response, error) { + if c.mockError != nil { + return nil, c.mockError + } + data, err := json.Marshal(c.mockResponse) + if err != nil { + return nil, err + } + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader(data)), + }, nil +} +func TestDeleteChaosExperimentSuccess(t *testing.T) { + + projectID := "testprojectid" + experimentID := "test-experiment-id" + cred := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + mockResponse := DeleteChaosExperimentData{ + Errors: nil, // No errors + Data: DeleteChaosExperimentDetails{ + IsDeleted: true, + }, + } + + mockClient := &MockHTTPClientDeleteExperiment{ + mockError: nil, + mockResponse: mockResponse, + } + + result, err := DeleteChaosExperiment(projectID, &experimentID, cred, mockClient) + + // Assertions + assert.NoError(t, err) // Ensure no errors occurred + assert.Equal(t, result, mockResponse) +} + +func TestDeleteChaosExperimentFailedRequest(t *testing.T) { + + projectID := "testprojectid" + experimentID := "test-experiment-id" + cred := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + mockResponse := DeleteChaosExperimentData{ + Errors: []struct { + Message string `json:"message"` + Path []string `json:"path"` + }{ + { + Message: "Some error occurred", + Path: []string{"path", "to", "error"}, + }, + }, + Data: DeleteChaosExperimentDetails{}, // Empty data + } + + mockClient := &MockHTTPClientDeleteExperiment{ + mockError: errors.New("Some error occurred"), + mockResponse: mockResponse, + } + + _, err := DeleteChaosExperiment(projectID, &experimentID, cred, mockClient) + + // Assertions + assert.Error(t, err) // Ensure an error occurred +} diff --git a/pkg/apis/infrastructure/infra.go b/pkg/apis/infrastructure/infra.go index 14c3e8df..cba77b0c 100644 --- a/pkg/apis/infrastructure/infra.go +++ b/pkg/apis/infrastructure/infra.go @@ -1,6 +1,5 @@ /* Copyright © 2021 The LitmusChaos Authors - 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 a1 copy of the License at @@ -30,7 +29,7 @@ import ( ) // GetInfraList lists the Chaos Infrastructure connected to the specified project -func GetInfraList(c types.Credentials, pid string, request models.ListInfraRequest) (InfraData, error) { +func GetInfraList(c types.Credentials, pid string, request models.ListInfraRequest, httpClient apis.HTTPClientInterface) (InfraData, error) { var gplReq ListInfraGraphQLRequest gplReq.Query = ListInfraQuery gplReq.Variables.ProjectID = pid @@ -40,7 +39,9 @@ func GetInfraList(c types.Credentials, pid string, request models.ListInfraReque if err != nil { return InfraData{}, err } - resp, err := apis.SendRequest(apis.SendRequestParams{Endpoint: c.ServerEndpoint + utils.GQLAPIPath, Token: c.Token}, query, string(types.Post)) + + resp, err := apis.SendRequest(apis.SendRequestParams{Endpoint: c.Endpoint + utils.GQLAPIPath, Token: c.Token}, httpClient, query, string(types.Post)) + if err != nil { return InfraData{}, err } @@ -70,7 +71,7 @@ func GetInfraList(c types.Credentials, pid string, request models.ListInfraReque } // ConnectInfra connects the Infra with the given details -func ConnectInfra(infra types.Infra, cred types.Credentials) (InfraConnectionData, error) { +func ConnectInfra(infra types.Infra, cred types.Credentials, httpClient apis.HTTPClientInterface) (InfraConnectionData, error) { var gqlReq RegisterInfraGqlRequest gqlReq.Query = RegisterInfraQuery gqlReq.Variables.ProjectId = infra.ProjectId @@ -97,7 +98,9 @@ func ConnectInfra(infra types.Infra, cred types.Credentials) (InfraConnectionDat } query, err := json.Marshal(gqlReq) - resp, err := apis.SendRequest(apis.SendRequestParams{Endpoint: cred.ServerEndpoint + utils.GQLAPIPath, Token: cred.Token}, query, string(types.Post)) + + resp, err := apis.SendRequest(apis.SendRequestParams{Endpoint: cred.Endpoint + utils.GQLAPIPath, Token: cred.Token}, httpClient, query, string(types.Post)) + if err != nil { return InfraConnectionData{}, errors.New("Error in registering Chaos Infrastructure: " + err.Error()) } @@ -141,7 +144,7 @@ func CreateRegisterInfraRequest(infra types.Infra) (request models.RegisterInfra } // DisconnectInfra sends GraphQL API request for disconnecting Chaos Infra(s). -func DisconnectInfra(projectID string, infraID string, cred types.Credentials) (DisconnectInfraData, error) { +func DisconnectInfra(projectID string, infraID string, cred types.Credentials, httpClient apis.HTTPClientInterface) (DisconnectInfraData, error) { var gqlReq DisconnectInfraGraphQLRequest var err error @@ -160,6 +163,7 @@ func DisconnectInfra(projectID string, infraID string, cred types.Credentials) ( Endpoint: cred.ServerEndpoint + utils.GQLAPIPath, Token: cred.Token, }, + httpClient, query, string(types.Post), ) diff --git a/pkg/apis/infrastructure/infra_test.go b/pkg/apis/infrastructure/infra_test.go new file mode 100644 index 00000000..a99f575f --- /dev/null +++ b/pkg/apis/infrastructure/infra_test.go @@ -0,0 +1,583 @@ +package infrastructure + +import ( + "bytes" + "encoding/json" + "testing" + + "io/ioutil" + "net/http" + + models "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" + "github.com/litmuschaos/litmusctl/pkg/types" + "github.com/stretchr/testify/assert" +) + +type MockHTTPClientInfraGet struct { + mockResponse InfraData + mockError error +} + +func (c *MockHTTPClientInfraGet) Do(req *http.Request) (*http.Response, error) { + if c.mockError != nil { + return nil, c.mockError + } + data, err := json.Marshal(c.mockResponse) + if err != nil { + return nil, err + } + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader(data)), + }, nil +} + +func TestGetInfraListSuccess(t *testing.T) { + mockData := InfraData{ + Data: InfraList{ + ListInfraDetails: models.ListInfraResponse{ + TotalNoOfInfras: 2, + Infras: []*models.Infra{ + { + ProjectID: "project1", + InfraID: "infra1", + Name: "Infrastructure 1", + Description: nil, + Tags: []string{"tag1", "tag2"}, + EnvironmentID: "env1", + PlatformName: "GKE", + IsActive: true, + IsInfraConfirmed: true, + IsRemoved: false, + UpdatedAt: "2023-10-13", + CreatedAt: "2023-10-12", + NoOfExperiments: nil, + NoOfExperimentRuns: nil, + Token: "token1", + InfraNamespace: nil, + ServiceAccount: nil, + InfraScope: "ns", + InfraNsExists: nil, + InfraSaExists: nil, + LastExperimentTimestamp: nil, + StartTime: "2023-10-11", + Version: "v1", + CreatedBy: &models.UserDetails{ + UserID: "user1", + Username: "JohnDoe", + Email: "johndoe@example.com", + }, + UpdatedBy: &models.UserDetails{ + UserID: "user2", + Username: "JaneSmith", + Email: "janesmith@example.com", + }, + InfraType: nil, + UpdateStatus: "In Progress", + }, + { + ProjectID: "project2", + InfraID: "infra2", + Name: "Infrastructure 2", + Description: nil, + Tags: []string{"tag3", "tag4"}, + EnvironmentID: "env2", + PlatformName: "AWS", + IsActive: false, + IsInfraConfirmed: true, + IsRemoved: true, + UpdatedAt: "2023-10-15", + CreatedAt: "2023-10-14", + NoOfExperiments: nil, + NoOfExperimentRuns: nil, + Token: "token2", + InfraNamespace: nil, + ServiceAccount: nil, + InfraScope: "cluster", + InfraNsExists: nil, + InfraSaExists: nil, + LastExperimentTimestamp: nil, + StartTime: "2023-10-16", + Version: "v2", + CreatedBy: &models.UserDetails{ + UserID: "user3", + Username: "AliceJohnson", + Email: "alicejohnson@example.com", + }, + UpdatedBy: &models.UserDetails{ + UserID: "user4", + Username: "BobWilliams", + Email: "bobwilliams@example.com", + }, + InfraType: nil, + UpdateStatus: "Completed", + }, + }, + }, + }, + Errors: nil, // We can add errors if needed + } + + input := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + mockClient := &MockHTTPClientInfraGet{ + mockError: nil, + mockResponse: mockData, + } + + tag1 := "tag1" + tag2 := "tag2" + + mockRequest := models.ListInfraRequest{ + InfraIDs: []string{"infra1", "infra2"}, + EnvironmentIDs: []string{"env1", "env2"}, + Pagination: &models.Pagination{ + Page: 1, + Limit: 10, + }, + Filter: &models.InfraFilterInput{ + Name: nil, + InfraID: nil, + Description: nil, + PlatformName: nil, + InfraScope: nil, + IsActive: nil, + Tags: []*string{&tag1, &tag2}, + }, + } + + result, _ := GetInfraList(input, "testpid", mockRequest, mockClient) + assert.Equal(t, result, mockData) + +} + +func TestGetInfraListFailed(t *testing.T) { + mockData := InfraData{ + Data: InfraList{ + ListInfraDetails: models.ListInfraResponse{ + TotalNoOfInfras: 2, + Infras: []*models.Infra{ + { + ProjectID: "project1", + InfraID: "infra1", + Name: "Infrastructure 1", + Description: nil, + Tags: []string{"tag1", "tag2"}, + EnvironmentID: "env1", + PlatformName: "GKE", + IsActive: true, + IsInfraConfirmed: true, + IsRemoved: false, + UpdatedAt: "2023-10-13", + CreatedAt: "2023-10-12", + NoOfExperiments: nil, + NoOfExperimentRuns: nil, + Token: "token1", + InfraNamespace: nil, + ServiceAccount: nil, + InfraScope: "ns", + InfraNsExists: nil, + InfraSaExists: nil, + LastExperimentTimestamp: nil, + StartTime: "2023-10-11", + Version: "v1", + CreatedBy: &models.UserDetails{ + UserID: "user1", + Username: "JohnDoe", + Email: "johndoe@example.com", + }, + UpdatedBy: &models.UserDetails{ + UserID: "user2", + Username: "JaneSmith", + Email: "janesmith@example.com", + }, + InfraType: nil, + UpdateStatus: "In Progress", + }, + { + ProjectID: "project2", + InfraID: "infra2", + Name: "Infrastructure 2", + Description: nil, + Tags: []string{"tag3", "tag4"}, + EnvironmentID: "env2", + PlatformName: "AWS", + IsActive: false, + IsInfraConfirmed: true, + IsRemoved: true, + UpdatedAt: "2023-10-15", + CreatedAt: "2023-10-14", + NoOfExperiments: nil, + NoOfExperimentRuns: nil, + Token: "token2", + InfraNamespace: nil, + ServiceAccount: nil, + InfraScope: "cluster", + InfraNsExists: nil, + InfraSaExists: nil, + LastExperimentTimestamp: nil, + StartTime: "2023-10-16", + Version: "v2", + CreatedBy: &models.UserDetails{ + UserID: "user3", + Username: "AliceJohnson", + Email: "alicejohnson@example.com", + }, + UpdatedBy: &models.UserDetails{ + UserID: "user4", + Username: "BobWilliams", + Email: "bobwilliams@example.com", + }, + InfraType: nil, + UpdateStatus: "Completed", + }, + }, + }, + }, + Errors: []struct { + Message string `json:"message"` + Path []string `json:"path"` + }{ + { + Message: "Error message 1", + Path: []string{"path1", "path2"}, + }, + }, + } + + input := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + mockClient := &MockHTTPClientInfraGet{ + mockError: nil, + mockResponse: mockData, + } + + tag1 := "tag1" + tag2 := "tag2" + + mockRequest := models.ListInfraRequest{ + InfraIDs: []string{"infra1", "infra2"}, + EnvironmentIDs: []string{"env1", "env2"}, + Pagination: &models.Pagination{ + Page: 1, + Limit: 10, + }, + Filter: &models.InfraFilterInput{ + Name: nil, + InfraID: nil, + Description: nil, + PlatformName: nil, + InfraScope: nil, + IsActive: nil, + Tags: []*string{&tag1, &tag2}, + }, + } + + result, _ := GetInfraList(input, "testpid", mockRequest, mockClient) + assert.NotEqual(t, result, mockData) +} + +type MockHTTPClientConnect struct { + mockResponse InfraConnectionData + mockError error +} + +func (c *MockHTTPClientConnect) Do(req *http.Request) (*http.Response, error) { + if c.mockError != nil { + return nil, c.mockError + } + data, err := json.Marshal(c.mockResponse) + if err != nil { + return nil, err + } + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader(data)), + }, nil +} + +func TestConnectInfraSuccess(t *testing.T) { + + mockRequest := types.Infra{ + InfraName: "Infraname", + Mode: "mode", + Description: "desc", + PlatformName: "platform", + EnvironmentID: "estid", + ProjectId: "projectid", + InfraType: "infratype", + NodeSelector: "nodeselector", + Tolerations: "", + Namespace: "namespace", + ServiceAccount: "serviceaccount", + NsExists: false, + SAExists: false, + SkipSSL: false, + } + input := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + mockData := InfraConnectionData{ + Data: RegisterInfra{ + RegisterInfraDetails: models.RegisterInfraResponse{ + Token: "dummyToken", + InfraID: "dummyInfraID", + Name: "DummyInfraName", + Manifest: "DummyInfraManifest", + }, + }, + Errors: []struct { + Message string `json:"message"` + Path []string `json:"path"` + }{}, + } + mockClient := &MockHTTPClientConnect{ + mockError: nil, + mockResponse: mockData, + } + result, _ := ConnectInfra(mockRequest, input, mockClient) + assert.Equal(t, result, mockData) +} + +func TestConnectInfraFail(t *testing.T) { + + mockRequest := types.Infra{ + InfraName: "Infraname", + Mode: "mode", + Description: "desc", + PlatformName: "platform", + EnvironmentID: "estid", + ProjectId: "projectid", + InfraType: "infratype", + NodeSelector: "nodeselector", + Tolerations: "", + Namespace: "namespace", + ServiceAccount: "serviceaccount", + NsExists: false, + SAExists: false, + SkipSSL: false, + } + input := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + mockData := InfraConnectionData{ + Data: RegisterInfra{ + RegisterInfraDetails: models.RegisterInfraResponse{ + Token: "dummyToken", + InfraID: "dummyInfraID", + Name: "DummyInfraName", + Manifest: "DummyInfraManifest", + }, + }, + Errors: []struct { + Message string `json:"message"` + Path []string `json:"path"` + }{ + { + Message: "Error message 1", + Path: []string{"path1", "path2"}, + }, + }, + } + mockClient := &MockHTTPClientConnect{ + mockError: nil, + mockResponse: mockData, + } + result, _ := ConnectInfra(mockRequest, input, mockClient) + assert.NotEqual(t, result, mockData) +} +func TestCreateRegisterInfraRequestSuccess(t *testing.T) { + + mockRequest := types.Infra{ + InfraName: "Infraname", + Mode: "mode", + Description: "desc", + PlatformName: "platform", + EnvironmentID: "estid", + ProjectId: "projectid", + InfraType: "infratype", + NodeSelector: "nodeselector", + Tolerations: "", + Namespace: "namespace", + ServiceAccount: "serviceaccount", + NsExists: false, + SAExists: false, + SkipSSL: false, + } + + mockData := models.RegisterInfraRequest{ + Name: "Infraname", + EnvironmentID: "estid", + InfrastructureType: "INTERNAL", + Description: stringPointer("desc"), + PlatformName: "platform", + InfraNamespace: stringPointer("namespace"), + ServiceAccount: stringPointer("serviceaccount"), + InfraScope: "mode", + InfraNsExists: boolPointer(false), + InfraSaExists: boolPointer(false), + SkipSsl: boolPointer(false), + NodeSelector: nil, + Tolerations: []*models.Toleration(nil), + Tags: []string(nil), + } + + result := CreateRegisterInfraRequest(mockRequest) + assert.Equal(t, result, mockData) +} + +func TestCreateRegisterInfraRequestFail(t *testing.T) { + + mockRequest := types.Infra{ + InfraName: "Infraname", + Mode: "mode", + Description: "desc", + PlatformName: "platform", + EnvironmentID: "estid", + ProjectId: "projectid", + InfraType: "infratype", + NodeSelector: "nodeselector", + Tolerations: "", + Namespace: "namespace", + ServiceAccount: "serviceaccount", + NsExists: false, + SAExists: false, + SkipSSL: false, + } + + mockData := models.RegisterInfraRequest{ + Name: "Infraname", + EnvironmentID: "estid", + InfrastructureType: "INTERNAL", + Description: stringPointer("desc"), + PlatformName: "platform", + InfraNamespace: stringPointer("namespace"), + ServiceAccount: stringPointer("serviceaccount"), + InfraScope: "mode", + InfraNsExists: boolPointer(false), + InfraSaExists: boolPointer(false), + SkipSsl: boolPointer(false), + NodeSelector: nil, + Tolerations: []*models.Toleration(nil), + Tags: []string{"tag1", "tag2"}, + } + + result := CreateRegisterInfraRequest(mockRequest) + assert.NotEqual(t, result, mockData) +} +func stringPointer(s string) *string { + return &s +} + +func boolPointer(b bool) *bool { + return &b +} + +type MockHTTPClientDisconnect struct { + mockResponse DisconnectInfraData + mockError error +} + +func (c *MockHTTPClientDisconnect) Do(req *http.Request) (*http.Response, error) { + if c.mockError != nil { + return nil, c.mockError + } + data, err := json.Marshal(c.mockResponse) + if err != nil { + return nil, err + } + return &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewReader(data)), + }, nil +} + +func TestDisconnectInfraSuccess(t *testing.T) { + + projectID := "testprojectid" + infraID := "infratestid" + + input := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + mockData := DisconnectInfraData{ + Errors: []struct { + Message string `json:"message"` + Path []string `json:"path"` + }{ + // { + // Message: "Error message 1", + // Path: []string{"path", "to", "error1"}, + // }, + // { + // Message: "Error message 2", + // Path: []string{"path", "to", "error2"}, + // }, + }, + Data: DisconnectInfraDetails{ + Message: "Infra deleted successfully", + }, + } + + mockClient := &MockHTTPClientDisconnect{ + mockError: nil, + mockResponse: mockData, + } + result, _ := DisconnectInfra(projectID, infraID, input, mockClient) + assert.Equal(t, result, mockData) +} + +func TestDisconnectInfraFail(t *testing.T) { + + projectID := "testprojectid" + infraID := "infratestid" + + input := types.Credentials{ + Username: "testusername", + Token: "testtoken", + Endpoint: "https://example.com", + } + + mockData := DisconnectInfraData{ + Errors: []struct { + Message string `json:"message"` + Path []string `json:"path"` + }{ + { + Message: "Error message 1", + Path: []string{"path", "to", "error1"}, + }, + { + Message: "Error message 2", + Path: []string{"path", "to", "error2"}, + }, + }, + Data: DisconnectInfraDetails{ + Message: "Infra deleted successfully", + }, + } + + mockClient := &MockHTTPClientDisconnect{ + mockError: nil, + mockResponse: mockData, + } + result, _ := DisconnectInfra(projectID, infraID, input, mockClient) + assert.NotEqual(t, result, mockData) +} diff --git a/pkg/apis/project.go b/pkg/apis/project.go index ba0fb996..2f10dd55 100644 --- a/pkg/apis/project.go +++ b/pkg/apis/project.go @@ -1,6 +1,5 @@ /* Copyright © 2021 The LitmusChaos Authors - 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 @@ -51,7 +50,7 @@ func CreateProjectRequest(projectName string, cred types.Credentials) (CreatePro if err != nil { return CreateProjectResponse{}, err } - resp, err := SendRequest(SendRequestParams{cred.Endpoint + utils.AuthAPIPath + "/create_project", "Bearer " + cred.Token}, payloadBytes, string(types.Post)) + resp, err := SendRequest(SendRequestParams{cred.Endpoint + utils.AuthAPIPath + "/create_project", "Bearer " + cred.Token}, Client, payloadBytes, string(types.Post)) if err != nil { return CreateProjectResponse{}, err } @@ -95,7 +94,7 @@ type listProjectResponse struct { func ListProject(cred types.Credentials) (listProjectResponse, error) { - resp, err := SendRequest(SendRequestParams{Endpoint: cred.Endpoint + utils.AuthAPIPath + "/list_projects", Token: "Bearer " + cred.Token}, []byte{}, string(types.Get)) + resp, err := SendRequest(SendRequestParams{Endpoint: cred.Endpoint + utils.AuthAPIPath + "/list_projects", Token: "Bearer " + cred.Token}, Client, []byte{}, string(types.Get)) if err != nil { return listProjectResponse{}, err } @@ -157,7 +156,7 @@ func GetProjectDetails(c types.Credentials) (ProjectDetails, error) { return ProjectDetails{}, nil } Username, _ := token.Claims.(jwt.MapClaims)["username"].(string) - resp, err := SendRequest(SendRequestParams{Endpoint: c.Endpoint + utils.AuthAPIPath + "/get_user_with_project/" + Username, Token: "Bearer " + c.Token}, []byte{}, string(types.Get)) + resp, err := SendRequest(SendRequestParams{Endpoint: "http://localhost:3000" + utils.AuthAPIPath + "/get_user_with_project/" + Username, Token: "Bearer " + c.Token}, Client, []byte{}, string(types.Get)) if err != nil { return ProjectDetails{}, err } diff --git a/pkg/apis/request.go b/pkg/apis/request.go index fc94806b..018564b2 100644 --- a/pkg/apis/request.go +++ b/pkg/apis/request.go @@ -1,6 +1,5 @@ /* Copyright © 2021 The LitmusChaos Authors - 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 @@ -25,7 +24,7 @@ type SendRequestParams struct { Token string } -func SendRequest(params SendRequestParams, payload []byte, method string) (*http.Response, error) { +func SendRequest(params SendRequestParams, httpClient HTTPClientInterface, payload []byte, method string) (*http.Response, error) { req, err := http.NewRequest(method, params.Endpoint, bytes.NewBuffer(payload)) if err != nil { return &http.Response{}, err @@ -33,7 +32,7 @@ func SendRequest(params SendRequestParams, payload []byte, method string) (*http req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", params.Token) - resp, err := http.DefaultClient.Do(req) + resp, err := httpClient.Do(req) if err != nil { return &http.Response{}, err } diff --git a/pkg/apis/upgrade.go b/pkg/apis/upgrade.go index 2a1e4bc8..4d39a623 100644 --- a/pkg/apis/upgrade.go +++ b/pkg/apis/upgrade.go @@ -49,7 +49,7 @@ func UpgradeInfra(c context.Context, cred types.Credentials, projectID string, i // Query to fetch Infra details from server query := `{"query":"query {\n getInfraDetails(infraID : \"` + infraID + `\", \n projectID : \"` + projectID + `\"){\n infraNamespace infraID \n}}"}` - resp, err := SendRequest(SendRequestParams{Endpoint: cred.Endpoint + utils.GQLAPIPath, Token: cred.Token}, []byte(query), string(types.Post)) + resp, err := SendRequest(SendRequestParams{Endpoint: cred.Endpoint + utils.GQLAPIPath, Token: cred.Token}, Client, []byte(query), string(types.Post)) if err != nil { return "", err } @@ -76,7 +76,7 @@ func UpgradeInfra(c context.Context, cred types.Credentials, projectID string, i // Query to fetch upgraded manifest from the server query = `{"query":"query {\n getInfraManifest(projectID : \"` + projectID + `\",\n infraID : \"` + infra.Data.GetInfraDetails.InfraID + `\", \n upgrade: true)}"}` - resp, err = SendRequest(SendRequestParams{Endpoint: cred.Endpoint + utils.GQLAPIPath, Token: cred.Token}, []byte(query), string(types.Post)) + resp, err = SendRequest(SendRequestParams{Endpoint: cred.Endpoint + utils.GQLAPIPath, Token: cred.Token}, Client, []byte(query), string(types.Post)) if err != nil { return "", err } diff --git a/pkg/cmd/config/setAccount.go b/pkg/cmd/config/setAccount.go index 49dddced..7778cde6 100644 --- a/pkg/cmd/config/setAccount.go +++ b/pkg/cmd/config/setAccount.go @@ -26,6 +26,7 @@ import ( "github.com/golang-jwt/jwt" "github.com/litmuschaos/litmusctl/pkg/apis" + "github.com/litmuschaos/litmusctl/pkg/config" "github.com/litmuschaos/litmusctl/pkg/types" "github.com/litmuschaos/litmusctl/pkg/utils" @@ -116,7 +117,7 @@ var setAccountCmd = &cobra.Command{ utils.PrintError(err) } - resp, err := apis.Auth(authInput) + resp, err := apis.Auth(authInput, apis.Client) utils.PrintError(err) // Decoding token token, _ := jwt.Parse(resp.AccessToken, nil) @@ -177,7 +178,7 @@ var setAccountCmd = &cobra.Command{ utils.Red.Println("\nError: some flags are missing. Run 'litmusctl config set-account --help' for usage. ") } - serverResp, err := experiment.GetServerVersion(authInput.Endpoint) + serverResp, err := experiment.GetServerVersion(authInput.Endpoint, apis.Client) var isCompatible bool if err != nil { utils.Red.Println("\nError: ", err) diff --git a/pkg/cmd/connect/infra.go b/pkg/cmd/connect/infra.go index 32750352..15168763 100644 --- a/pkg/cmd/connect/infra.go +++ b/pkg/cmd/connect/infra.go @@ -177,7 +177,7 @@ var infraCmd = &cobra.Command{ infra_ops.PrintExistingInfra(infraList) os.Exit(1) } - envIDs, err := environment.GetEnvironmentList(newInfra.ProjectId, credentials) + envIDs, err := environment.GetEnvironmentList(newInfra.ProjectId, credentials, apis.Client) utils.PrintError(err) // Check if Environment exists @@ -223,7 +223,7 @@ var infraCmd = &cobra.Command{ infra_ops.ConfirmInstallation() } - infra, err := infrastructure.ConnectInfra(newInfra, credentials) + infra, err := infrastructure.ConnectInfra(newInfra, credentials, apis.Client) if err != nil { utils.Red.Println("\n❌ Chaos Infra connection failed: " + err.Error() + "\n") os.Exit(1) diff --git a/pkg/cmd/create/environment.go b/pkg/cmd/create/environment.go index 29c7f34e..a3a59691 100644 --- a/pkg/cmd/create/environment.go +++ b/pkg/cmd/create/environment.go @@ -94,10 +94,8 @@ var environmentCmd = &cobra.Command{ } newEnvironment.Type = models.EnvironmentType(envType) - envs, err := environment.GetEnvironmentList(pid, credentials) - if err != nil { - utils.PrintError(err) - } + envs, err := environment.GetEnvironmentList(pid, credentials, apis.Client) + utils.PrintError(err) // Generate EnvironmentID from Environment Name envID := utils.GenerateNameID(newEnvironment.Name) @@ -140,7 +138,7 @@ var environmentCmd = &cobra.Command{ os.Exit(1) } - newEnv, err := environment.CreateEnvironment(pid, newEnvironment, credentials) + newEnv, err := environment.CreateEnvironment(pid, newEnvironment, credentials, apis.Client) if err != nil { utils.Red.Println("\n❌ Chaos Environment connection failed: " + err.Error() + "\n") os.Exit(1) diff --git a/pkg/cmd/create/experiment.go b/pkg/cmd/create/experiment.go index ae77b0d4..2e3fa112 100644 --- a/pkg/cmd/create/experiment.go +++ b/pkg/cmd/create/experiment.go @@ -113,7 +113,7 @@ var experimentCmd = &cobra.Command{ // Generate ExperimentID from ExperimentName chaosExperimentRequest.ID = utils.GenerateNameID(chaosExperimentRequest.Name) // Make API call - createExperiment, err := experiment.CreateExperiment(pid, chaosExperimentRequest, credentials) + createExperiment, err := experiment.CreateExperiment(pid, chaosExperimentRequest, credentials, apis.Client) if err != nil { if (createExperiment.Data == experiment.RunExperimentData{}) { if strings.Contains(err.Error(), "multiple write errors") { diff --git a/pkg/cmd/delete/experiment.go b/pkg/cmd/delete/experiment.go index 77368a63..6b00bd22 100644 --- a/pkg/cmd/delete/experiment.go +++ b/pkg/cmd/delete/experiment.go @@ -120,7 +120,7 @@ var experimentCmd = &cobra.Command{ } // Make API call - deleteExperiment, err := experiment.DeleteChaosExperiment(projectID, &experimentID, credentials) + deleteExperiment, err := experiment.DeleteChaosExperiment(projectID, &experimentID, credentials, apis.Client) if err != nil { utils.Red.Println("\n❌ Error in deleting Chaos Experiment: ", err.Error()) os.Exit(1) diff --git a/pkg/cmd/describe/experiment.go b/pkg/cmd/describe/experiment.go index 61973b90..1727855a 100644 --- a/pkg/cmd/describe/experiment.go +++ b/pkg/cmd/describe/experiment.go @@ -23,8 +23,10 @@ import ( "os" "strings" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" + "github.com/litmuschaos/litmusctl/pkg/apis" "github.com/litmuschaos/litmusctl/pkg/apis/experiment" + + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" "github.com/litmuschaos/litmusctl/pkg/utils" "github.com/manifoldco/promptui" "github.com/spf13/cobra" @@ -80,7 +82,7 @@ var experimentCmd = &cobra.Command{ describeExperimentRequest.ExperimentIDs = append(describeExperimentRequest.ExperimentIDs, &experimentID) - experiment, err := experiment.GetExperimentList(pid, describeExperimentRequest, credentials) + experiment, err := experiment.GetExperimentList(pid, describeExperimentRequest, credentials, apis.Client) if err != nil { if strings.Contains(err.Error(), "permission_denied") { utils.Red.Println("❌ The specified Project ID doesn't exist.") diff --git a/pkg/cmd/disconnect/infra.go b/pkg/cmd/disconnect/infra.go index e6ee9eba..3d7b76b2 100644 --- a/pkg/cmd/disconnect/infra.go +++ b/pkg/cmd/disconnect/infra.go @@ -17,10 +17,11 @@ package disconnect import ( "fmt" - "github.com/litmuschaos/litmusctl/pkg/apis/infrastructure" "os" "strings" + "github.com/litmuschaos/litmusctl/pkg/apis/infrastructure" + "github.com/litmuschaos/litmusctl/pkg/apis" "github.com/litmuschaos/litmusctl/pkg/utils" @@ -91,7 +92,7 @@ var infraCmd = &cobra.Command{ } // Make API call - disconnectedInfra, err := infrastructure.DisconnectInfra(projectID, infraID, credentials) + disconnectedInfra, err := infrastructure.DisconnectInfra(projectID, infraID, credentials, apis.Client) if err != nil { if strings.Contains(err.Error(), "no documents in result") { utils.Red.Println("❌ The specified Project ID or Chaos Infrastructure ID doesn't exist.") diff --git a/pkg/cmd/get/environment.go b/pkg/cmd/get/environment.go index f20278d4..2ea04f3b 100644 --- a/pkg/cmd/get/environment.go +++ b/pkg/cmd/get/environment.go @@ -18,14 +18,16 @@ package get import ( "fmt" - "github.com/litmuschaos/litmusctl/pkg/apis/environment" - "github.com/litmuschaos/litmusctl/pkg/utils" - "github.com/spf13/cobra" "os" "strconv" "strings" "text/tabwriter" "time" + + "github.com/litmuschaos/litmusctl/pkg/apis" + "github.com/litmuschaos/litmusctl/pkg/apis/environment" + "github.com/litmuschaos/litmusctl/pkg/utils" + "github.com/spf13/cobra" ) var ChaosEnvironmentCmd = &cobra.Command{ @@ -62,7 +64,7 @@ var ChaosEnvironmentCmd = &cobra.Command{ } } - environmentList, err := environment.GetEnvironmentList(projectID, credentials) + environmentList, err := environment.GetEnvironmentList(projectID, credentials, apis.Client) if err != nil { if strings.Contains(err.Error(), "permission_denied") { utils.Red.Println("❌ You don't have enough permissions to access this resource.") diff --git a/pkg/cmd/get/experimentruns.go b/pkg/cmd/get/experimentruns.go index 39b5d7b1..a188af60 100644 --- a/pkg/cmd/get/experimentruns.go +++ b/pkg/cmd/get/experimentruns.go @@ -23,6 +23,7 @@ import ( "text/tabwriter" "time" + "github.com/litmuschaos/litmusctl/pkg/apis" "github.com/litmuschaos/litmusctl/pkg/apis/experiment" "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" @@ -77,7 +78,7 @@ var experimentRunsCmd = &cobra.Command{ listExperimentRunsRequest.Pagination.Limit, _ = cmd.Flags().GetInt("count") } - experimentRuns, err := experiment.GetExperimentRunsList(projectID, listExperimentRunsRequest, credentials) + experimentRuns, err := experiment.GetExperimentRunsList(projectID, listExperimentRunsRequest, credentials, apis.Client) if err != nil { if strings.Contains(err.Error(), "permission_denied") { utils.Red.Println("❌ The specified Project ID doesn't exist.") diff --git a/pkg/cmd/get/experiments.go b/pkg/cmd/get/experiments.go index b44061f1..36ae2377 100644 --- a/pkg/cmd/get/experiments.go +++ b/pkg/cmd/get/experiments.go @@ -22,6 +22,7 @@ import ( "text/tabwriter" "time" + "github.com/litmuschaos/litmusctl/pkg/apis" "github.com/litmuschaos/litmusctl/pkg/apis/experiment" "github.com/gorhill/cronexpr" @@ -66,7 +67,7 @@ var experimentsCmd = &cobra.Command{ utils.PrintError(err) listExperimentRequest.Filter.InfraName = &infraName - experiments, err := experiment.GetExperimentList(pid, listExperimentRequest, credentials) + experiments, err := experiment.GetExperimentList(pid, listExperimentRequest, credentials, apis.Client) if err != nil { if strings.Contains(err.Error(), "permission_denied") { utils.Red.Println("❌ The specified Project ID doesn't exist.") diff --git a/pkg/cmd/get/infra.go b/pkg/cmd/get/infra.go index f29992d7..6b519339 100644 --- a/pkg/cmd/get/infra.go +++ b/pkg/cmd/get/infra.go @@ -22,6 +22,8 @@ import ( "text/tabwriter" models "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" + + "github.com/litmuschaos/litmusctl/pkg/apis" "github.com/litmuschaos/litmusctl/pkg/apis/infrastructure" "github.com/litmuschaos/litmusctl/pkg/utils" @@ -50,7 +52,7 @@ var InfraCmd = &cobra.Command{ } } - infras, err := infrastructure.GetInfraList(credentials, projectID, models.ListInfraRequest{}) + infras, err := infrastructure.GetInfraList(credentials, projectID, models.ListInfraRequest{}, apis.Client) if err != nil { if strings.Contains(err.Error(), "permission_denied") { utils.Red.Println("❌ you don't have enough permissions to access this project") diff --git a/pkg/cmd/list/environment.go b/pkg/cmd/list/environment.go index 0daec8fa..429ae3f1 100644 --- a/pkg/cmd/list/environment.go +++ b/pkg/cmd/list/environment.go @@ -18,15 +18,17 @@ package list import ( "fmt" - "github.com/litmuschaos/litmusctl/pkg/apis/environment" - "github.com/litmuschaos/litmusctl/pkg/utils" - "github.com/manifoldco/promptui" - "github.com/spf13/cobra" "os" "strconv" "strings" "text/tabwriter" "time" + + "github.com/litmuschaos/litmusctl/pkg/apis" + "github.com/litmuschaos/litmusctl/pkg/apis/environment" + "github.com/litmuschaos/litmusctl/pkg/utils" + "github.com/manifoldco/promptui" + "github.com/spf13/cobra" ) var ListChaosEnvironmentCmd = &cobra.Command{ @@ -50,7 +52,7 @@ var ListChaosEnvironmentCmd = &cobra.Command{ } } - environmentList, err := environment.GetEnvironmentList(projectID, credentials) + environmentList, err := environment.GetEnvironmentList(projectID, credentials, apis.Client) if err != nil { if strings.Contains(err.Error(), "permission_denied") { utils.Red.Println("❌ You don't have enough permissions to access this resource.") diff --git a/pkg/cmd/run/experiment.go b/pkg/cmd/run/experiment.go index 179e5d8e..8516c844 100644 --- a/pkg/cmd/run/experiment.go +++ b/pkg/cmd/run/experiment.go @@ -17,12 +17,13 @@ package run import ( "fmt" + "os" + "strings" + "github.com/litmuschaos/litmusctl/pkg/apis" "github.com/litmuschaos/litmusctl/pkg/apis/experiment" "github.com/litmuschaos/litmusctl/pkg/utils" "github.com/spf13/cobra" - "os" - "strings" ) // experimentCmd represents the project command @@ -90,7 +91,7 @@ var experimentCmd = &cobra.Command{ } // Make API call - runExperiment, err := experiment.RunExperiment(pid, eid, credentials) + runExperiment, err := experiment.RunExperiment(pid, eid, credentials, apis.Client) if err != nil { if (runExperiment.Data == experiment.RunExperimentData{}) { if strings.Contains(err.Error(), "multiple run errors") { diff --git a/pkg/cmd/save/experiment.go b/pkg/cmd/save/experiment.go index 8ce9e248..8c63b11e 100644 --- a/pkg/cmd/save/experiment.go +++ b/pkg/cmd/save/experiment.go @@ -17,10 +17,12 @@ package save import ( "fmt" - models "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" - "github.com/litmuschaos/litmusctl/pkg/apis/experiment" "os" "strings" + + models "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" + "github.com/litmuschaos/litmusctl/pkg/apis/experiment" + //"time" //"github.com/gorhill/cronexpr" @@ -116,7 +118,7 @@ var experimentCmd = &cobra.Command{ // Generate ExperimentID from the ExperimentName chaosExperimentRequest.ID = utils.GenerateNameID(chaosExperimentRequest.Name) // Make API call - saveExperiment, err := experiment.SaveExperiment(pid, chaosExperimentRequest, credentials) + saveExperiment, err := experiment.SaveExperiment(pid, chaosExperimentRequest, credentials, apis.Client) if err != nil { if (saveExperiment.Data == experiment.SavedExperimentDetails{}) { diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go new file mode 100644 index 00000000..c850aaea --- /dev/null +++ b/pkg/config/config_test.go @@ -0,0 +1,328 @@ +package config + +import ( + "io/ioutil" + "os" + + "testing" + + "github.com/litmuschaos/litmusctl/pkg/types" + "github.com/stretchr/testify/assert" + yaml "gopkg.in/yaml.v2" +) + +func TestCreateNewLitmusCtlConfig(t *testing.T) { + testFilename := "test-config.yaml" + testConfig := types.LitmuCtlConfig{ + APIVersion: "v1", + Kind: "Config", + } + + // unit test + err := CreateNewLitmusCtlConfig(testFilename, testConfig) + assert.NoError(t, err) + + assert.True(t, FileExists(testFilename)) + + // Check if the file length is greater than 0 + length, err := GetFileLength(testFilename) + assert.NoError(t, err) + assert.Greater(t, length, 0) + + os.Remove(testFilename) +} + +func TestFileExists(t *testing.T) { + + testFilename := "test-file-exists.txt" + _, err := os.Create(testFilename) + assert.NoError(t, err) + + exists := FileExists(testFilename) + assert.True(t, exists) + + os.Remove(testFilename) +} + +func TestGetFileLength(t *testing.T) { + + testFilename := "test-file-length.txt" + file, err := os.Create(testFilename) + assert.NoError(t, err) + _, err = file.WriteString("This is a test.") + assert.NoError(t, err) + file.Close() + + length, err := GetFileLength(testFilename) + assert.NoError(t, err) + + // Calculate the expected length based on the text content, accounting for line endings + expectedLength := len("This is a test.") + assert.Equal(t, expectedLength, length) + + err = os.Remove(testFilename) + assert.NoError(t, err) +} + +func TestYamltoObject(t *testing.T) { + + testConfig := types.LitmuCtlConfig{ + APIVersion: "v1", + Kind: "Config", + Accounts: []types.Account{}, + CurrentAccount: "test-account", + CurrentUser: "test-user", + } + + // Serialize the test config to YAML and write it to a temporary test file + data, err := yaml.Marshal(testConfig) + assert.NoError(t, err) + testFilename := "test-config.yaml" + err = ioutil.WriteFile(testFilename, data, 0644) + assert.NoError(t, err) + + //unit test + obj, err := YamltoObject(testFilename) + assert.NoError(t, err) + assert.Equal(t, testConfig, obj) + + os.Remove(testFilename) +} + +func TestConfigSyntaxCheck(t *testing.T) { + + testFilename := "test-config.yaml" + testConfig := types.LitmuCtlConfig{ + APIVersion: "v1", + Kind: "Config", + Accounts: []types.Account{}, + CurrentAccount: "", + CurrentUser: "", + } + + // Serialize the LitmusCtlConfig to a YAML file + err := CreateNewLitmusCtlConfig(testFilename, testConfig) + assert.NoError(t, err) + + //unit test + err = ConfigSyntaxCheck(testFilename) + assert.NoError(t, err) + + os.Remove(testFilename) + + invalidTestFilename := "invalid-test-config.yaml" + invalidTestConfig := types.LitmuCtlConfig{ + APIVersion: "v1", + Kind: "InvalidKind", // This is an invalid Kind value + Accounts: []types.Account{}, + CurrentAccount: "", + CurrentUser: "", + } + + err = CreateNewLitmusCtlConfig(invalidTestFilename, invalidTestConfig) + assert.NoError(t, err) + + // unit test + err = ConfigSyntaxCheck(invalidTestFilename) + assert.Error(t, err) + + os.Remove(invalidTestFilename) +} + +func TestUpdateLitmusCtlConfig(t *testing.T) { + + testFilename := "test-update-config.yaml" + initialConfig := types.LitmuCtlConfig{ + APIVersion: "v1", + Kind: "Config", + Accounts: []types.Account{ + { + Endpoint: "https://cluster1", + Users: []types.User{ + { + Username: "user1", + Token: "token1", + ExpiresIn: "3600s", + }, + }, + }, + { + Endpoint: "https://cluster2", + Users: []types.User{ + { + Username: "user2", + Token: "token2", + ExpiresIn: "7200s", + }, + }, + }, + }, + CurrentAccount: "cluster1", + CurrentUser: "user1", + } + + // Serialize the initial LitmusCtlConfig to a YAML file + err := CreateNewLitmusCtlConfig(testFilename, initialConfig) + assert.NoError(t, err) + + // Define an update configuration + updateConfig := types.UpdateLitmusCtlConfig{ + Account: types.Account{ + Endpoint: "https://cluster2", + Users: []types.User{ + { + Username: "user2", // Existing username + Token: "newtoken", // Updated token + ExpiresIn: "5400s", // Updated ExpiresIn + }, + }, + }, + CurrentAccount: "cluster2", // Updated current account + CurrentUser: "user2", // Updated current user + } + + // unit test to update the configuration + err = UpdateLitmusCtlConfig(updateConfig, testFilename) + assert.NoError(t, err) + + // Read the updated configuration from the file + updatedConfig, err := YamltoObject(testFilename) + assert.NoError(t, err) + + // Check if the user's token and ExpiresIn have been updated + assert.Equal(t, "newtoken", updatedConfig.Accounts[1].Users[0].Token) + assert.Equal(t, "5400s", updatedConfig.Accounts[1].Users[0].ExpiresIn) + // Check if the current account and user have been updated + assert.Equal(t, "cluster2", updatedConfig.CurrentAccount) + assert.Equal(t, "user2", updatedConfig.CurrentUser) + + os.Remove(testFilename) +} + +func TestUpdateCurrent(t *testing.T) { + + testFilename := "test-update-current.yaml" + defer os.Remove(testFilename) + + initialConfig := types.LitmuCtlConfig{ + APIVersion: "v1", + Kind: "Config", + CurrentUser: "user1", + CurrentAccount: "account1", + Accounts: []types.Account{ + { + Endpoint: "example.com", + Users: []types.User{ + { + Username: "user1", + Token: "token1", + ExpiresIn: "3600s", + }, + }, + }, + }, + } + + err := CreateNewLitmusCtlConfig(testFilename, initialConfig) + assert.NoError(t, err) + + // updated current user and account + updatedCurrent := types.Current{ + CurrentUser: "user2", + CurrentAccount: "account2", + } + + // Update the current user and account + err = UpdateCurrent(updatedCurrent, testFilename) + assert.NoError(t, err) + + updatedConfig, err := YamltoObject(testFilename) + assert.NoError(t, err) + + // Check that the current user and account have been updated as expected + assert.Equal(t, "user2", updatedConfig.CurrentUser) + assert.Equal(t, "account2", updatedConfig.CurrentAccount) +} + +func TestWriteObjToFile(t *testing.T) { + + testFilename := "test-write-obj.yaml" + testConfig := types.LitmuCtlConfig{ + APIVersion: "v1", + Kind: "Config", + CurrentUser: "user1", + CurrentAccount: "account1", + Accounts: []types.Account{ + { + Endpoint: "https://cluster1", + Users: []types.User{ + { + Username: "user1", + Token: "token1", + ExpiresIn: "3600s", + }, + }, + }, + }, + } + + err := WriteObjToFile(testConfig, testFilename) + assert.NoError(t, err) + + loadedConfig, err := YamltoObject(testFilename) + assert.NoError(t, err) + + // Verify that the loaded configuration matches the original test configuration + assert.Equal(t, testConfig, loadedConfig) + + os.Remove(testFilename) +} + +func TestIsAccountExists(t *testing.T) { + + testConfig := types.LitmuCtlConfig{ + Accounts: []types.Account{ + { + Endpoint: "example.com", + Users: []types.User{ + { + Username: "user1", + Token: "token1", + ExpiresIn: "3600s", + }, + { + Username: "user2", + Token: "token2", + ExpiresIn: "7200s", + }, + }, + }, + { + Endpoint: "another.com", + Users: []types.User{ + { + Username: "user3", + Token: "token3", + ExpiresIn: "5400s", + }, + }, + }, + }, + APIVersion: "v1", + Kind: "Config", + CurrentAccount: "example.com", + CurrentUser: "user1", + } + + // Check if a known username and endpoint exist + exists := IsAccountExists(testConfig, "user1", "example.com") + assert.True(t, exists) + + // Check if a username that doesn't exist returns false + exists = IsAccountExists(testConfig, "nonexistentuser", "example.com") + assert.False(t, exists) + + // Check if an endpoint that doesn't exist returns false + exists = IsAccountExists(testConfig, "user1", "nonexistent.com") + assert.False(t, exists) +} diff --git a/pkg/config/ops.go b/pkg/config/ops.go index b1a97674..adcb80f8 100644 --- a/pkg/config/ops.go +++ b/pkg/config/ops.go @@ -130,7 +130,7 @@ func UpdateLitmusCtlConfig(litmusconfig types.UpdateLitmusCtlConfig, filename st obj.CurrentAccount = litmusconfig.CurrentAccount obj.CurrentUser = litmusconfig.CurrentUser - err = writeObjToFile(obj, filename) + err = WriteObjToFile(obj, filename) if err != nil { return err } @@ -147,7 +147,7 @@ func UpdateCurrent(current types.Current, filename string) error { obj.CurrentUser = current.CurrentUser obj.CurrentAccount = current.CurrentAccount - err = writeObjToFile(obj, filename) + err = WriteObjToFile(obj, filename) if err != nil { return err } @@ -155,7 +155,7 @@ func UpdateCurrent(current types.Current, filename string) error { return nil } -func writeObjToFile(obj types.LitmuCtlConfig, filename string) error { +func WriteObjToFile(obj types.LitmuCtlConfig, filename string) error { _, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0644) if err != nil { return err diff --git a/pkg/infra_ops/ops.go b/pkg/infra_ops/ops.go index 6e15f5c1..41473c07 100644 --- a/pkg/infra_ops/ops.go +++ b/pkg/infra_ops/ops.go @@ -17,13 +17,14 @@ package infra_ops import ( "fmt" - "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" - "github.com/litmuschaos/litmusctl/pkg/apis/environment" - "github.com/litmuschaos/litmusctl/pkg/apis/infrastructure" "os" "strconv" "strings" + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model" + "github.com/litmuschaos/litmusctl/pkg/apis/environment" + "github.com/litmuschaos/litmusctl/pkg/apis/infrastructure" + "github.com/litmuschaos/litmusctl/pkg/apis" "github.com/litmuschaos/litmusctl/pkg/k8s" "github.com/litmuschaos/litmusctl/pkg/types" @@ -137,7 +138,7 @@ ENVIRONMENT: } // Check if Chaos Environment with the given name exists - Env, err := environment.GetEnvironmentList(pid, c) + Env, err := environment.GetEnvironmentList(pid, c, apis.Client) if err != nil { return types.Infra{}, err } @@ -284,7 +285,7 @@ func ValidateSAPermissions(namespace string, mode string, kubeconfig *string) { // ValidateInfraNameExists checks if an infrastructure already exists func ValidateInfraNameExists(infraName string, pid string, c types.Credentials) (bool, error, infrastructure.InfraData) { - infra, err := infrastructure.GetInfraList(c, pid, model.ListInfraRequest{}) + infra, err := infrastructure.GetInfraList(c, pid, model.ListInfraRequest{}, apis.Client) if err != nil { return false, err, infrastructure.InfraData{} }