1**This file is to show instruction on how to write tests for any CLI**
2
3# Getting started:
4- 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.
5- If you want more examples, you can go through `networkservice` or `clustersecret` to see more examples.
6- Typically, most CLIs will require `store-name` and `banner-name`, so tests for these will show up frequently.
7- You will need to setup your testConfig. Here's an example:
8 ```
9 var (
10 testBanner = edgecli.BannerContext{
11 BannerEdgeID: "test-banner-edge-id-0",
12 BannerName: "test-banner-0",
13 TenantOrg: "test-org-0",
14 Username: "test-user-0",
15 Token: "test-token-0",
16 }
17 testCurrrentBanner = "test-current-banner"
18 testConfig = edgecli.Config{
19 CurrentBannerContext: testCurrrentBanner,
20 BannerContexts: map[string]*edgecli.BannerContext{
21 testCurrrentBanner: &testBanner,
22 },
23 }
24 edgeAPIMockSvr *httptest.Server
25 edgeAPIMockURL string
26 )
27 ```
28
29- Then setup `TestMain` to make sure your mock API server is working correctly
30-
31```
32func TestMain(m *testing.M) {
33 edgeAPIMockSvr = fake.GetMockAPIServer()
34 edgeAPIMockURL = edgeAPIMockSvr.URL + "/api/v2"
35 run := m.Run()
36 edgeAPIMockSvr.Close()
37 os.Exit(run)
38}
39```
40
41- 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:
42
43```
44func apiRequestsCallback(w http.ResponseWriter, r *http.Request) {
45 body, err := io.ReadAll(r.Body)
46 if err != nil {
47 utils.WriteBadResponse(w, nil)
48 return
49 }
50
51 switch {
52 ...
53 case strings.Contains(string(body), "randomFunction(requiredParam: $ParamValue)"):
54 data, err := wrapAsGraphqlResponse(&randomFunctionResponses{StructVal: TestStructVal})
55 if err != nil {
56 utils.WriteBadResponse(w, nil)
57 return
58 }
59 utils.WriteOkResponse(w, data)
60 ...
61}
62```
63
64- In the same folder, add respond struct in `fake_types.go`
65
66```
67type randomFunctionResponse struct {
68 StructVal string `json:"randomFunction"`
69}
70```
71
72- Make sure the `json:...` part the same name with the graphql function you trying to call
73- Once finished with initial setting up, you can begin writing your test
74
75## Writing tests:
76
77- 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.
78- 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.
79- Secondly, you need to setup your mock api server and declare
80
81```
82testConfig.BannerContexts[testCurrrentBanner].Endpoint = edgeAPIMockURL
83```
84
85- Thirdly, declare `cmd`
86
87```
88cmd := NewCmd(&testConfig)
89```
90
91- Now you set up check for required flags. Here's an example of expecting not to return any error:
92
93```
94require.Error(t, cmd.Command().Exec(context.Background(), []string{}), "Flag 'store' is required")
95require.NoError(t, flagutil.SetFlag(cmd.Rags, flagutil.StoreFlag, "test-cluster-0"))
96require.NoError(t, flagutil.SetFlag(cmd.Rags, flagutil.BannerFlag, "test-banner-0"))
97require.NoError(t, cmd.Command().Exec(context.Background(), []string{}))
98
99```
100
101- Now, putting them all together:
102
103```
104func TestABCFunction(t *testing.T) {
105 testConfig.BannerContexts[testCurrrentBanner].Endpoint = edgeAPIMockURL
106 cmd := NewCmd(&testConfig)
107
108 require.Error(t, cmd.Command().Exec(context.Background(), []string{}), "Flag 'store' is required")
109 require.NoError(t, flagutil.SetFlag(cmd.Rags, flagutil.StoreFlag, "test-cluster-0"))
110 require.NoError(t, flagutil.SetFlag(cmd.Rags, flagutil.BannerFlag, "test-banner-0"))
111 require.NoError(t, cmd.Command().Exec(context.Background(), []string{}))
112}
113```
114
115- Once you finished with working test case, let's go to ones that will return error
116
117### Writing tests to expect errors:
118- You pretty much can reuse your working test case function, and change up the conditions to trigger the error.
119- Name the function with the test case you expecting to fail.
120- 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
121
122```
123require.NoError(t, flagutil.SetFlag(cmd.Rags, flagutil.StoreFlag, "cluster-not-exist"))
124```
125
126- 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`.
127
128**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**
129
130- Because I am expecting an error to come back, I will the last function to expect an error
131
132```
133require.ErrorContains(t, cmd.Command().Exec(context.Background(), []string{}), "cluster does not exist: cluster-not-exist")
134```
135
136- Your function should look like this after updating those 2 lines
137
138```
139func TestABCFunctionWithBadStore(t *testing.T) {
140 testConfig.BannerContexts[testCurrrentBanner].Endpoint = edgeAPIMockURL
141 cmd := NewCmd(&testConfig)
142
143 require.Error(t, cmd.Command().Exec(context.Background(), []string{}), "Flag 'store' is required")
144 require.NoError(t, flagutil.SetFlag(cmd.Rags, flagutil.StoreFlag, "cluster-not-exist"))
145 require.NoError(t, flagutil.SetFlag(cmd.Rags, flagutil.BannerFlag, "test-banner-0"))
146 require.ErrorContains(t, cmd.Command().Exec(context.Background(), []string{}), "cluster does not exist: cluster-not-exist")
147}
148```
149
150- From there, you can repeat the same for any other test with expecting errors
151
152
153
154**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 :)**
View as plain text