github.com/huaweicloud/golangsdk@v0.0.0-20210831081626-d823fe11ceba/testing/params_test.go (about)

     1  package testing
     2  
     3  import (
     4  	"net/url"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/huaweicloud/golangsdk"
    10  	th "github.com/huaweicloud/golangsdk/testhelper"
    11  )
    12  
    13  func TestMaybeString(t *testing.T) {
    14  	testString := ""
    15  	var expected *string
    16  	actual := golangsdk.MaybeString(testString)
    17  	th.CheckDeepEquals(t, expected, actual)
    18  
    19  	testString = "carol"
    20  	expected = &testString
    21  	actual = golangsdk.MaybeString(testString)
    22  	th.CheckDeepEquals(t, expected, actual)
    23  }
    24  
    25  func TestMaybeInt(t *testing.T) {
    26  	testInt := 0
    27  	var expected *int
    28  	actual := golangsdk.MaybeInt(testInt)
    29  	th.CheckDeepEquals(t, expected, actual)
    30  
    31  	testInt = 4
    32  	expected = &testInt
    33  	actual = golangsdk.MaybeInt(testInt)
    34  	th.CheckDeepEquals(t, expected, actual)
    35  }
    36  
    37  func TestBuildQueryString(t *testing.T) {
    38  	type testVar string
    39  	iFalse := false
    40  	opts := struct {
    41  		J  int               `q:"j"`
    42  		R  string            `q:"r" required:"true"`
    43  		C  bool              `q:"c"`
    44  		S  []string          `q:"s"`
    45  		TS []testVar         `q:"ts"`
    46  		TI []int             `q:"ti"`
    47  		F  *bool             `q:"f"`
    48  		M  map[string]string `q:"m"`
    49  	}{
    50  		J:  2,
    51  		R:  "red",
    52  		C:  true,
    53  		S:  []string{"one", "two", "three"},
    54  		TS: []testVar{"a", "b"},
    55  		TI: []int{1, 2},
    56  		F:  &iFalse,
    57  		M:  map[string]string{"k1": "success1"},
    58  	}
    59  	expected := &url.URL{RawQuery: "c=true&f=false&j=2&m=%7B%27k1%27%3A%27success1%27%7D&r=red&s=one&s=two&s=three&ti=1&ti=2&ts=a&ts=b"}
    60  	actual, err := golangsdk.BuildQueryString(&opts)
    61  	if err != nil {
    62  		t.Errorf("Error building query string: %v", err)
    63  	}
    64  	th.CheckDeepEquals(t, expected, actual)
    65  
    66  	opts = struct {
    67  		J  int               `q:"j"`
    68  		R  string            `q:"r" required:"true"`
    69  		C  bool              `q:"c"`
    70  		S  []string          `q:"s"`
    71  		TS []testVar         `q:"ts"`
    72  		TI []int             `q:"ti"`
    73  		F  *bool             `q:"f"`
    74  		M  map[string]string `q:"m"`
    75  	}{
    76  		J: 2,
    77  		C: true,
    78  	}
    79  	_, err = golangsdk.BuildQueryString(&opts)
    80  	if err == nil {
    81  		t.Errorf("Expected error: 'Required field not set'")
    82  	}
    83  	th.CheckDeepEquals(t, expected, actual)
    84  
    85  	_, err = golangsdk.BuildQueryString(map[string]interface{}{"Number": 4})
    86  	if err == nil {
    87  		t.Errorf("Expected error: 'Options type is not a struct'")
    88  	}
    89  }
    90  
    91  func TestBuildHeaders(t *testing.T) {
    92  	testStruct := struct {
    93  		Accept        string `h:"Accept"`
    94  		ContentLength int64  `h:"Content-Length"`
    95  		Num           int    `h:"Number" required:"true"`
    96  		Style         bool   `h:"Style"`
    97  	}{
    98  		Accept:        "application/json",
    99  		ContentLength: 256,
   100  		Num:           4,
   101  		Style:         true,
   102  	}
   103  	expected := map[string]string{"Accept": "application/json", "Number": "4", "Style": "true", "Content-Length": "256"}
   104  	actual, err := golangsdk.BuildHeaders(&testStruct)
   105  	th.CheckNoErr(t, err)
   106  	th.CheckDeepEquals(t, expected, actual)
   107  
   108  	testStruct.Num = 0
   109  	_, err = golangsdk.BuildHeaders(&testStruct)
   110  	if err == nil {
   111  		t.Errorf("Expected error: 'Required header not set'")
   112  	}
   113  
   114  	_, err = golangsdk.BuildHeaders(map[string]interface{}{"Number": 4})
   115  	if err == nil {
   116  		t.Errorf("Expected error: 'Options type is not a struct'")
   117  	}
   118  }
   119  
   120  func TestQueriesAreEscaped(t *testing.T) {
   121  	type foo struct {
   122  		Name  string `q:"something"`
   123  		Shape string `q:"else"`
   124  	}
   125  
   126  	expected := &url.URL{RawQuery: "else=Triangl+e&something=blah%2B%3F%21%21foo"}
   127  
   128  	actual, err := golangsdk.BuildQueryString(foo{Name: "blah+?!!foo", Shape: "Triangl e"})
   129  	th.AssertNoErr(t, err)
   130  
   131  	th.AssertDeepEquals(t, expected, actual)
   132  }
   133  
   134  func TestBuildRequestBody(t *testing.T) {
   135  	type PasswordCredentials struct {
   136  		Username string `json:"username" required:"true"`
   137  		Password string `json:"password" required:"true"`
   138  	}
   139  
   140  	type TokenCredentials struct {
   141  		ID string `json:"id,omitempty" required:"true"`
   142  	}
   143  
   144  	type orFields struct {
   145  		Filler int `json:"filler,omitempty"`
   146  		F1     int `json:"f1,omitempty" or:"F2"`
   147  		F2     int `json:"f2,omitempty" or:"F1"`
   148  	}
   149  
   150  	// AuthOptions wraps a golangsdk AuthOptions in order to adhere to the AuthOptionsBuilder
   151  	// interface.
   152  	type AuthOptions struct {
   153  		PasswordCredentials *PasswordCredentials `json:"passwordCredentials,omitempty" xor:"TokenCredentials"`
   154  
   155  		// The TenantID and TenantName fields are optional for the Identity V2 API.
   156  		// Some providers allow you to specify a TenantName instead of the TenantId.
   157  		// Some require both. Your provider's authentication policies will determine
   158  		// how these fields influence authentication.
   159  		TenantID   string `json:"tenantId,omitempty"`
   160  		TenantName string `json:"tenantName,omitempty"`
   161  
   162  		// TokenCredentials allows users to authenticate (possibly as another user) with an
   163  		// authentication token ID.
   164  		TokenCredentials *TokenCredentials `json:"token,omitempty" xor:"PasswordCredentials"`
   165  
   166  		OrFields *orFields `json:"or_fields,omitempty"`
   167  	}
   168  
   169  	var successCases = []struct {
   170  		opts     AuthOptions
   171  		expected map[string]interface{}
   172  	}{
   173  		{
   174  			AuthOptions{
   175  				PasswordCredentials: &PasswordCredentials{
   176  					Username: "me",
   177  					Password: "swordfish",
   178  				},
   179  			},
   180  			map[string]interface{}{
   181  				"auth": map[string]interface{}{
   182  					"passwordCredentials": map[string]interface{}{
   183  						"password": "swordfish",
   184  						"username": "me",
   185  					},
   186  				},
   187  			},
   188  		},
   189  		{
   190  			AuthOptions{
   191  				TokenCredentials: &TokenCredentials{
   192  					ID: "1234567",
   193  				},
   194  			},
   195  			map[string]interface{}{
   196  				"auth": map[string]interface{}{
   197  					"token": map[string]interface{}{
   198  						"id": "1234567",
   199  					},
   200  				},
   201  			},
   202  		},
   203  	}
   204  
   205  	for _, successCase := range successCases {
   206  		actual, err := golangsdk.BuildRequestBody(successCase.opts, "auth")
   207  		th.AssertNoErr(t, err)
   208  		th.AssertDeepEquals(t, successCase.expected, actual)
   209  	}
   210  
   211  	var failCases = []struct {
   212  		opts     AuthOptions
   213  		expected error
   214  	}{
   215  		{
   216  			AuthOptions{
   217  				TenantID:   "987654321",
   218  				TenantName: "me",
   219  			},
   220  			golangsdk.ErrMissingInput{},
   221  		},
   222  		{
   223  			AuthOptions{
   224  				TokenCredentials: &TokenCredentials{
   225  					ID: "1234567",
   226  				},
   227  				PasswordCredentials: &PasswordCredentials{
   228  					Username: "me",
   229  					Password: "swordfish",
   230  				},
   231  			},
   232  			golangsdk.ErrMissingInput{},
   233  		},
   234  		{
   235  			AuthOptions{
   236  				PasswordCredentials: &PasswordCredentials{
   237  					Password: "swordfish",
   238  				},
   239  			},
   240  			golangsdk.ErrMissingInput{},
   241  		},
   242  		{
   243  			AuthOptions{
   244  				PasswordCredentials: &PasswordCredentials{
   245  					Username: "me",
   246  					Password: "swordfish",
   247  				},
   248  				OrFields: &orFields{
   249  					Filler: 2,
   250  				},
   251  			},
   252  			golangsdk.ErrMissingInput{},
   253  		},
   254  	}
   255  
   256  	for _, failCase := range failCases {
   257  		_, err := golangsdk.BuildRequestBody(failCase.opts, "auth")
   258  		th.AssertDeepEquals(t, reflect.TypeOf(failCase.expected), reflect.TypeOf(err))
   259  	}
   260  
   261  	createdAt := time.Date(2018, 1, 4, 10, 00, 12, 0, time.UTC)
   262  	var complexFields = struct {
   263  		Username  string     `json:"username" required:"true"`
   264  		CreatedAt *time.Time `json:"-"`
   265  	}{
   266  		Username:  "jdoe",
   267  		CreatedAt: &createdAt,
   268  	}
   269  
   270  	expectedComplexFields := map[string]interface{}{
   271  		"username": "jdoe",
   272  	}
   273  
   274  	actual, err := golangsdk.BuildRequestBody(complexFields, "")
   275  	th.AssertNoErr(t, err)
   276  	th.AssertDeepEquals(t, expectedComplexFields, actual)
   277  
   278  }