**This file is to show instruction on how to write tests for any CLI** # Getting started: - Before writing any test, you need to check on all the required flags of the CLI. From there, it will be easier to figure out what you need to test. - If you want more examples, you can go through `networkservice` or `clustersecret` to see more examples. - Typically, most CLIs will require `store-name` and `banner-name`, so tests for these will show up frequently. - You will need to setup your testConfig. Here's an example: ``` var ( testBanner = edgecli.BannerContext{ BannerEdgeID: "test-banner-edge-id-0", BannerName: "test-banner-0", TenantOrg: "test-org-0", Username: "test-user-0", Token: "test-token-0", } testCurrrentBanner = "test-current-banner" testConfig = edgecli.Config{ CurrentBannerContext: testCurrrentBanner, BannerContexts: map[string]*edgecli.BannerContext{ testCurrrentBanner: &testBanner, }, } edgeAPIMockSvr *httptest.Server edgeAPIMockURL string ) ``` - Then setup `TestMain` to make sure your mock API server is working correctly - ``` func TestMain(m *testing.M) { edgeAPIMockSvr = fake.GetMockAPIServer() edgeAPIMockURL = edgeAPIMockSvr.URL + "/api/v2" run := m.Run() edgeAPIMockSvr.Close() os.Exit(run) } ``` - Go to `pkg/edge/api/fake/fake_server.go` to add your mock API calls inside `apiRequestCallBack` function to make sure it catches your API calls and return the expected test data: ``` func apiRequestsCallback(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) if err != nil { utils.WriteBadResponse(w, nil) return } switch { ... case strings.Contains(string(body), "randomFunction(requiredParam: $ParamValue)"): data, err := wrapAsGraphqlResponse(&randomFunctionResponses{StructVal: TestStructVal}) if err != nil { utils.WriteBadResponse(w, nil) return } utils.WriteOkResponse(w, data) ... } ``` - In the same folder, add respond struct in `fake_types.go` ``` type randomFunctionResponse struct { StructVal string `json:"randomFunction"` } ``` - Make sure the `json:...` part the same name with the graphql function you trying to call - Once finished with initial setting up, you can begin writing your test ## Writing tests: - You can write all the tests in one function, but I recommend separating your test cases out to be its own function, so you can keep track easier and for debugging purposes. - First, you will set up a test with all working conditions, let's call it `TestABCFunction` and it has `store` and `banner` as only required flags. - Secondly, you need to setup your mock api server and declare ``` testConfig.BannerContexts[testCurrrentBanner].Endpoint = edgeAPIMockURL ``` - Thirdly, declare `cmd` ``` cmd := NewCmd(&testConfig) ``` - Now you set up check for required flags. Here's an example of expecting not to return any error: ``` require.Error(t, cmd.Command().Exec(context.Background(), []string{}), "Flag 'store' is required") require.NoError(t, flagutil.SetFlag(cmd.Rags, flagutil.StoreFlag, "test-cluster-0")) require.NoError(t, flagutil.SetFlag(cmd.Rags, flagutil.BannerFlag, "test-banner-0")) require.NoError(t, cmd.Command().Exec(context.Background(), []string{})) ``` - Now, putting them all together: ``` func TestABCFunction(t *testing.T) { testConfig.BannerContexts[testCurrrentBanner].Endpoint = edgeAPIMockURL cmd := NewCmd(&testConfig) require.Error(t, cmd.Command().Exec(context.Background(), []string{}), "Flag 'store' is required") require.NoError(t, flagutil.SetFlag(cmd.Rags, flagutil.StoreFlag, "test-cluster-0")) require.NoError(t, flagutil.SetFlag(cmd.Rags, flagutil.BannerFlag, "test-banner-0")) require.NoError(t, cmd.Command().Exec(context.Background(), []string{})) } ``` - Once you finished with working test case, let's go to ones that will return error ### Writing tests to expect errors: - You pretty much can reuse your working test case function, and change up the conditions to trigger the error. - Name the function with the test case you expecting to fail. - Let's say I want to test the function `GetCluster` to see if it works, I will feed a wrong `cluster name` inside the parameter ``` require.NoError(t, flagutil.SetFlag(cmd.Rags, flagutil.StoreFlag, "cluster-not-exist")) ``` - This should trigger error since there is no `cluster-not-exist` in the mock server, it should returns you with this error message `cluster does not exist: cluster-not-exist`. **Note: because I put `cluster-not-exist` in the parameter as its cluster name, that's why I'm getting back the name of it here in the error message, so if you put any other name on the parameter, it will show up on the error. This is important because the following step, you will check if the error contains that exact message** - Because I am expecting an error to come back, I will the last function to expect an error ``` require.ErrorContains(t, cmd.Command().Exec(context.Background(), []string{}), "cluster does not exist: cluster-not-exist") ``` - Your function should look like this after updating those 2 lines ``` func TestABCFunctionWithBadStore(t *testing.T) { testConfig.BannerContexts[testCurrrentBanner].Endpoint = edgeAPIMockURL cmd := NewCmd(&testConfig) require.Error(t, cmd.Command().Exec(context.Background(), []string{}), "Flag 'store' is required") require.NoError(t, flagutil.SetFlag(cmd.Rags, flagutil.StoreFlag, "cluster-not-exist")) require.NoError(t, flagutil.SetFlag(cmd.Rags, flagutil.BannerFlag, "test-banner-0")) require.ErrorContains(t, cmd.Command().Exec(context.Background(), []string{}), "cluster does not exist: cluster-not-exist") } ``` - From there, you can repeat the same for any other test with expecting errors **If you have any question, please feel free to reach out to the API team and we will help you with any confusion. Thank you :)**