...

Text file src/edge-infra.dev/pkg/edge/edgecli/commands/README.md

Documentation: edge-infra.dev/pkg/edge/edgecli/commands

     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