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 }