1// 2// Copyright (c) 2018, Joyent, Inc. All rights reserved. 3// 4// This Source Code Form is subject to the terms of the Mozilla Public 5// License, v. 2.0. If a copy of the MPL was not distributed with this 6// file, You can obtain one at http://mozilla.org/MPL/2.0/. 7// 8 9package identity_test 10 11import ( 12 "context" 13 "errors" 14 "fmt" 15 "io/ioutil" 16 "net/http" 17 "strings" 18 "testing" 19 20 "github.com/joyent/triton-go/identity" 21 "github.com/joyent/triton-go/testutils" 22) 23 24var ( 25 fakePolicyId = "95ca7b25-5c8f-4c1b-92da-4276f23805ds" 26 aDifferentFakePolicyId = "95ca7b25-5c8f-4c1b-92da-4276f23807f3" 27 listPoliciesErrorType = errors.New("unable to list policies") 28 getPolicyErrorType = errors.New("unable to get policy") 29 deletePolicyErrorType = errors.New("unable to delete policy") 30 updatePolicyErrorType = errors.New("unable to update policy") 31 createPolicyErrorType = errors.New("unable to create policy") 32) 33 34func TestListPolicies(t *testing.T) { 35 identityClient := MockIdentityClient() 36 37 do := func(ctx context.Context, ic *identity.IdentityClient) ([]*identity.Policy, error) { 38 defer testutils.DeactivateClient() 39 40 policies, err := ic.Policies().List(ctx, &identity.ListPoliciesInput{}) 41 if err != nil { 42 return nil, err 43 } 44 45 return policies, nil 46 } 47 48 t.Run("successful", func(t *testing.T) { 49 testutils.RegisterResponder("GET", fmt.Sprintf("/%s/policies", accountUrl), listPoliciesSuccess) 50 51 resp, err := do(context.Background(), identityClient) 52 if err != nil { 53 t.Fatal(err) 54 } 55 56 if resp == nil { 57 t.Fatalf("Expected an output but got nil") 58 } 59 }) 60 61 t.Run("eof", func(t *testing.T) { 62 testutils.RegisterResponder("GET", fmt.Sprintf("/%s/policies", accountUrl), listPoliciesEmpty) 63 64 _, err := do(context.Background(), identityClient) 65 if err == nil { 66 t.Fatal(err) 67 } 68 69 if !strings.Contains(err.Error(), "EOF") { 70 t.Errorf("expected error to contain EOF: found %s", err) 71 } 72 }) 73 74 t.Run("bad_decode", func(t *testing.T) { 75 testutils.RegisterResponder("GET", fmt.Sprintf("/%s/policies", accountUrl), listPoliciesBadeDecode) 76 77 _, err := do(context.Background(), identityClient) 78 if err == nil { 79 t.Fatal(err) 80 } 81 82 if !strings.Contains(err.Error(), "invalid character") { 83 t.Errorf("expected decode to fail: found %s", err) 84 } 85 }) 86 87 t.Run("error", func(t *testing.T) { 88 testutils.RegisterResponder("GET", fmt.Sprintf("/%s/policies", accountUrl), listPoliciesError) 89 90 resp, err := do(context.Background(), identityClient) 91 if err == nil { 92 t.Fatal(err) 93 } 94 if resp != nil { 95 t.Error("expected resp to be nil") 96 } 97 98 if !strings.Contains(err.Error(), "unable to list policies") { 99 t.Errorf("expected error to equal testError: found %s", err) 100 } 101 }) 102} 103 104func TestGetPolicy(t *testing.T) { 105 identityClient := MockIdentityClient() 106 107 do := func(ctx context.Context, ic *identity.IdentityClient) (*identity.Policy, error) { 108 defer testutils.DeactivateClient() 109 110 user, err := ic.Policies().Get(ctx, &identity.GetPolicyInput{ 111 PolicyID: fakePolicyId, 112 }) 113 if err != nil { 114 return nil, err 115 } 116 117 return user, nil 118 } 119 120 t.Run("successful", func(t *testing.T) { 121 testutils.RegisterResponder("GET", fmt.Sprintf("/%s/policies/%s", accountUrl, fakePolicyId), getPolicySuccess) 122 123 resp, err := do(context.Background(), identityClient) 124 if err != nil { 125 t.Fatal(err) 126 } 127 128 if resp == nil { 129 t.Fatalf("Expected an output but got nil") 130 } 131 }) 132 133 t.Run("eof", func(t *testing.T) { 134 testutils.RegisterResponder("GET", fmt.Sprintf("/%s/policies/%s", accountUrl, fakePolicyId), getPolicyEmpty) 135 136 _, err := do(context.Background(), identityClient) 137 if err == nil { 138 t.Fatal(err) 139 } 140 141 if !strings.Contains(err.Error(), "EOF") { 142 t.Errorf("expected error to contain EOF: found %s", err) 143 } 144 }) 145 146 t.Run("bad_decode", func(t *testing.T) { 147 testutils.RegisterResponder("GET", fmt.Sprintf("/%s/policies/%s", accountUrl, fakePolicyId), getPolicyBadeDecode) 148 149 _, err := do(context.Background(), identityClient) 150 if err == nil { 151 t.Fatal(err) 152 } 153 154 if !strings.Contains(err.Error(), "invalid character") { 155 t.Errorf("expected decode to fail: found %s", err) 156 } 157 }) 158 159 t.Run("error", func(t *testing.T) { 160 testutils.RegisterResponder("GET", fmt.Sprintf("/%s/policies", accountUrl), getPolicyError) 161 162 resp, err := do(context.Background(), identityClient) 163 if err == nil { 164 t.Fatal(err) 165 } 166 if resp != nil { 167 t.Error("expected resp to be nil") 168 } 169 170 if !strings.Contains(err.Error(), "unable to get policy") { 171 t.Errorf("expected error to equal testError: found %s", err) 172 } 173 }) 174} 175 176func TestDeletePolicy(t *testing.T) { 177 identityClient := MockIdentityClient() 178 179 do := func(ctx context.Context, ic *identity.IdentityClient) error { 180 defer testutils.DeactivateClient() 181 182 return ic.Policies().Delete(ctx, &identity.DeletePolicyInput{ 183 PolicyID: fakePolicyId, 184 }) 185 } 186 187 t.Run("successful", func(t *testing.T) { 188 testutils.RegisterResponder("DELETE", fmt.Sprintf("/%s/policies/%s", accountUrl, fakePolicyId), deletePolicySuccess) 189 190 err := do(context.Background(), identityClient) 191 if err != nil { 192 t.Fatal(err) 193 } 194 }) 195 196 t.Run("error", func(t *testing.T) { 197 testutils.RegisterResponder("DELETE", fmt.Sprintf("/%s/policies", accountUrl), deletePolicyError) 198 199 err := do(context.Background(), identityClient) 200 if err == nil { 201 t.Fatal(err) 202 } 203 204 if !strings.Contains(err.Error(), "unable to delete policy") { 205 t.Errorf("expected error to equal testError: found %s", err) 206 } 207 }) 208} 209 210func TestUpdatePolicy(t *testing.T) { 211 identityClient := MockIdentityClient() 212 213 do := func(ctx context.Context, ic *identity.IdentityClient) (*identity.Policy, error) { 214 defer testutils.DeactivateClient() 215 216 policy, err := ic.Policies().Update(ctx, &identity.UpdatePolicyInput{ 217 PolicyID: fakePolicyId, 218 Description: "Updated Description", 219 Name: "Updated Name", 220 }) 221 if err != nil { 222 return nil, err 223 } 224 225 return policy, nil 226 } 227 228 t.Run("successful", func(t *testing.T) { 229 testutils.RegisterResponder("POST", fmt.Sprintf("/%s/policies/%s", accountUrl, fakePolicyId), updatePolicySuccess) 230 231 _, err := do(context.Background(), identityClient) 232 if err != nil { 233 t.Fatal(err) 234 } 235 }) 236 237 t.Run("error", func(t *testing.T) { 238 testutils.RegisterResponder("POST", fmt.Sprintf("/%s/policies/%s", accountUrl, aDifferentFakePolicyId), updatePolicyError) 239 240 _, err := do(context.Background(), identityClient) 241 if err == nil { 242 t.Fatal(err) 243 } 244 245 if !strings.Contains(err.Error(), "unable to update policy") { 246 t.Errorf("expected error to equal testError: found %s", err) 247 } 248 }) 249} 250 251func TestCreatePolicy(t *testing.T) { 252 identityClient := MockIdentityClient() 253 254 do := func(ctx context.Context, ic *identity.IdentityClient) (*identity.Policy, error) { 255 defer testutils.DeactivateClient() 256 257 policy, err := ic.Policies().Create(ctx, &identity.CreatePolicyInput{ 258 Name: "Test Policy", 259 Description: "Test Description", 260 Rules: []string{"CAN rebootmachine"}, 261 }) 262 263 if err != nil { 264 return nil, err 265 } 266 267 return policy, nil 268 } 269 270 t.Run("successful", func(t *testing.T) { 271 testutils.RegisterResponder("POST", fmt.Sprintf("/%s/policies", accountUrl), createPolicySuccess) 272 273 _, err := do(context.Background(), identityClient) 274 if err != nil { 275 t.Fatal(err) 276 } 277 }) 278 279 t.Run("error", func(t *testing.T) { 280 testutils.RegisterResponder("POST", fmt.Sprintf("/%s/policies", accountUrl), createPolicyError) 281 282 _, err := do(context.Background(), identityClient) 283 if err == nil { 284 t.Fatal(err) 285 } 286 287 if !strings.Contains(err.Error(), "unable to create policy") { 288 t.Errorf("expected error to equal testError: found %s", err) 289 } 290 }) 291} 292 293func listPoliciesEmpty(req *http.Request) (*http.Response, error) { 294 header := http.Header{} 295 header.Add("Content-Type", "application/json") 296 297 return &http.Response{ 298 StatusCode: 200, 299 Header: header, 300 Body: ioutil.NopCloser(strings.NewReader("")), 301 }, nil 302} 303 304func listPoliciesSuccess(req *http.Request) (*http.Response, error) { 305 header := http.Header{} 306 header.Add("Content-Type", "application/json") 307 308 body := strings.NewReader(`[ 309 { 310 "name": "readinstance", 311 "id": "95ca7b25-5c8f-4c1b-92da-4276f23807f3", 312 "rules": [ 313 "can listmachine and getmachine" 314 ] 315 }, 316 { 317 "name": "createinstance", 318 "id": "95ca7b25-5c8f-4c1b-92da-4276f23805ds", 319 "rules": [ 320 "can createinstance" 321 ] 322 } 323]`) 324 325 return &http.Response{ 326 StatusCode: 200, 327 Header: header, 328 Body: ioutil.NopCloser(body), 329 }, nil 330} 331 332func listPoliciesBadeDecode(req *http.Request) (*http.Response, error) { 333 header := http.Header{} 334 header.Add("Content-Type", "application/json") 335 336 body := strings.NewReader(`{[ 337 { 338 "name": "createinstance", 339 "id": "95ca7b25-5c8f-4c1b-92da-4276f23805ds", 340 "rules": [ 341 "can createinstance" 342 ] 343 } 344]}`) 345 346 return &http.Response{ 347 StatusCode: 200, 348 Header: header, 349 Body: ioutil.NopCloser(body), 350 }, nil 351} 352 353func listPoliciesError(req *http.Request) (*http.Response, error) { 354 return nil, listPoliciesErrorType 355} 356 357func getPolicySuccess(req *http.Request) (*http.Response, error) { 358 header := http.Header{} 359 header.Add("Content-Type", "application/json") 360 361 body := strings.NewReader(`{ 362 "name": "readinstance", 363 "id": "95ca7b25-5c8f-4c1b-92da-4276f23807f3", 364 "rules": [ 365 "can listmachine and getmachine" 366 ] 367 } 368`) 369 370 return &http.Response{ 371 StatusCode: 200, 372 Header: header, 373 Body: ioutil.NopCloser(body), 374 }, nil 375} 376 377func getPolicyError(req *http.Request) (*http.Response, error) { 378 return nil, getPolicyErrorType 379} 380 381func getPolicyBadeDecode(req *http.Request) (*http.Response, error) { 382 header := http.Header{} 383 header.Add("Content-Type", "application/json") 384 385 body := strings.NewReader(`{ 386 "name": "readinstance", 387 "id": "95ca7b25-5c8f-4c1b-92da-4276f23807f3", 388 "rules": [ 389 "can listmachine and getmachine" 390 ], 391 }`) 392 393 return &http.Response{ 394 StatusCode: 200, 395 Header: header, 396 Body: ioutil.NopCloser(body), 397 }, nil 398} 399 400func getPolicyEmpty(req *http.Request) (*http.Response, error) { 401 header := http.Header{} 402 header.Add("Content-Type", "application/json") 403 404 return &http.Response{ 405 StatusCode: 200, 406 Header: header, 407 Body: ioutil.NopCloser(strings.NewReader("")), 408 }, nil 409} 410 411func deletePolicySuccess(req *http.Request) (*http.Response, error) { 412 header := http.Header{} 413 header.Add("Content-Type", "application/json") 414 415 return &http.Response{ 416 StatusCode: 204, 417 Header: header, 418 }, nil 419} 420 421func deletePolicyError(req *http.Request) (*http.Response, error) { 422 return nil, deletePolicyErrorType 423} 424 425func updatePolicySuccess(req *http.Request) (*http.Response, error) { 426 header := http.Header{} 427 header.Add("Content-Type", "application/json") 428 429 body := strings.NewReader(`{ 430 "name": "Updated Name", 431 "id": "95ca7b25-5c8f-4c1b-92da-4276f23807f3", 432 "rules": [ 433 "can rebootMachine" 434 ], 435 "description": "Updated Description" 436} 437`) 438 439 return &http.Response{ 440 StatusCode: 200, 441 Header: header, 442 Body: ioutil.NopCloser(body), 443 }, nil 444} 445 446func updatePolicyError(req *http.Request) (*http.Response, error) { 447 return nil, updatePolicyErrorType 448} 449 450func createPolicySuccess(req *http.Request) (*http.Response, error) { 451 header := http.Header{} 452 header.Add("Content-Type", "application/json") 453 454 body := strings.NewReader(`{ 455 "name": "Test Policy", 456 "id": "95ca7b25-5c8f-4c1b-92da-4276f23807f3", 457 "rules": [ 458 "CAN rebootmachine" 459 ], 460 "description": "Test Description" 461} 462`) 463 464 return &http.Response{ 465 StatusCode: 201, 466 Header: header, 467 Body: ioutil.NopCloser(body), 468 }, nil 469} 470 471func createPolicyError(req *http.Request) (*http.Response, error) { 472 return nil, createPolicyErrorType 473} 474