github.com/vnpaycloud-console/gophercloud/v2@v2.0.5/openstack/identity/v3/tokens/testing/requests_test.go (about)

     1  package testing
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/vnpaycloud-console/gophercloud/v2"
    11  	"github.com/vnpaycloud-console/gophercloud/v2/openstack/identity/v3/tokens"
    12  	th "github.com/vnpaycloud-console/gophercloud/v2/testhelper"
    13  	"github.com/vnpaycloud-console/gophercloud/v2/testhelper/client"
    14  )
    15  
    16  // authTokenPost verifies that providing certain AuthOptions and Scope results in an expected JSON structure.
    17  func authTokenPost(t *testing.T, options tokens.AuthOptions, scope *tokens.Scope, requestJSON string) {
    18  	th.SetupHTTP()
    19  	defer th.TeardownHTTP()
    20  
    21  	client := gophercloud.ServiceClient{
    22  		ProviderClient: &gophercloud.ProviderClient{},
    23  		Endpoint:       th.Endpoint(),
    24  	}
    25  
    26  	th.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
    27  		th.TestMethod(t, r, "POST")
    28  		th.TestHeader(t, r, "Content-Type", "application/json")
    29  		th.TestHeader(t, r, "Accept", "application/json")
    30  		th.TestJSONRequest(t, r, requestJSON)
    31  
    32  		w.WriteHeader(http.StatusCreated)
    33  		fmt.Fprint(w, `{
    34  			"token": {
    35  				"expires_at": "2014-10-02T13:45:00.000000Z"
    36  			}
    37  		}`)
    38  	})
    39  
    40  	if scope != nil {
    41  		options.Scope = *scope
    42  	}
    43  
    44  	expected := &tokens.Token{
    45  		ExpiresAt: time.Date(2014, 10, 2, 13, 45, 0, 0, time.UTC),
    46  	}
    47  	actual, err := tokens.Create(context.TODO(), &client, &options).Extract()
    48  	th.AssertNoErr(t, err)
    49  	th.CheckDeepEquals(t, expected, actual)
    50  }
    51  
    52  func authTokenPostErr(t *testing.T, options tokens.AuthOptions, scope *tokens.Scope, includeToken bool, expectedErr error) {
    53  	th.SetupHTTP()
    54  	defer th.TeardownHTTP()
    55  
    56  	client := gophercloud.ServiceClient{
    57  		ProviderClient: &gophercloud.ProviderClient{},
    58  		Endpoint:       th.Endpoint(),
    59  	}
    60  	if includeToken {
    61  		client.TokenID = "abcdef123456"
    62  	}
    63  
    64  	if scope != nil {
    65  		options.Scope = *scope
    66  	}
    67  
    68  	_, err := tokens.Create(context.TODO(), &client, &options).Extract()
    69  	if err == nil {
    70  		t.Errorf("Create did NOT return an error")
    71  	}
    72  	if err != expectedErr {
    73  		t.Errorf("Create returned an unexpected error: wanted %v, got %v", expectedErr, err)
    74  	}
    75  }
    76  
    77  func TestCreateUserIDAndPassword(t *testing.T) {
    78  	authTokenPost(t, tokens.AuthOptions{UserID: "me", Password: "squirrel!"}, nil, `
    79  		{
    80  			"auth": {
    81  				"identity": {
    82  					"methods": ["password"],
    83  					"password": {
    84  						"user": { "id": "me", "password": "squirrel!" }
    85  					}
    86  				}
    87  			}
    88  		}
    89  	`)
    90  }
    91  
    92  func TestCreateUsernameDomainIDPassword(t *testing.T) {
    93  	authTokenPost(t, tokens.AuthOptions{Username: "fakey", Password: "notpassword", DomainID: "abc123"}, nil, `
    94  		{
    95  			"auth": {
    96  				"identity": {
    97  					"methods": ["password"],
    98  					"password": {
    99  						"user": {
   100  							"domain": {
   101  								"id": "abc123"
   102  							},
   103  							"name": "fakey",
   104  							"password": "notpassword"
   105  						}
   106  					}
   107  				}
   108  			}
   109  		}
   110  	`)
   111  }
   112  
   113  func TestCreateUsernameDomainNamePassword(t *testing.T) {
   114  	authTokenPost(t, tokens.AuthOptions{Username: "frank", Password: "swordfish", DomainName: "spork.net"}, nil, `
   115  		{
   116  			"auth": {
   117  				"identity": {
   118  					"methods": ["password"],
   119  					"password": {
   120  						"user": {
   121  							"domain": {
   122  								"name": "spork.net"
   123  							},
   124  							"name": "frank",
   125  							"password": "swordfish"
   126  						}
   127  					}
   128  				}
   129  			}
   130  		}
   131  	`)
   132  }
   133  
   134  func TestCreateTokenID(t *testing.T) {
   135  	authTokenPost(t, tokens.AuthOptions{TokenID: "12345abcdef"}, nil, `
   136  		{
   137  			"auth": {
   138  				"identity": {
   139  					"methods": ["token"],
   140  					"token": {
   141  						"id": "12345abcdef"
   142  					}
   143  				}
   144  			}
   145  		}
   146  	`)
   147  }
   148  
   149  func TestCreateProjectIDScope(t *testing.T) {
   150  	options := tokens.AuthOptions{UserID: "someuser", Password: "somepassword"}
   151  	scope := &tokens.Scope{ProjectID: "123456"}
   152  	authTokenPost(t, options, scope, `
   153  		{
   154  			"auth": {
   155  				"identity": {
   156  					"methods": ["password"],
   157  					"password": {
   158  						"user": {
   159  							"id": "someuser",
   160  							"password": "somepassword"
   161  						}
   162  					}
   163  				},
   164  				"scope": {
   165  					"project": {
   166  						"id": "123456"
   167  					}
   168  				}
   169  			}
   170  		}
   171  	`)
   172  }
   173  
   174  func TestCreateDomainIDScope(t *testing.T) {
   175  	options := tokens.AuthOptions{UserID: "someuser", Password: "somepassword"}
   176  	scope := &tokens.Scope{DomainID: "1000"}
   177  	authTokenPost(t, options, scope, `
   178  		{
   179  			"auth": {
   180  				"identity": {
   181  					"methods": ["password"],
   182  					"password": {
   183  						"user": {
   184  							"id": "someuser",
   185  							"password": "somepassword"
   186  						}
   187  					}
   188  				},
   189  				"scope": {
   190  					"domain": {
   191  						"id": "1000"
   192  					}
   193  				}
   194  			}
   195  		}
   196  	`)
   197  }
   198  
   199  func TestCreateDomainNameScope(t *testing.T) {
   200  	options := tokens.AuthOptions{UserID: "someuser", Password: "somepassword"}
   201  	scope := &tokens.Scope{DomainName: "evil-plans"}
   202  	authTokenPost(t, options, scope, `
   203  		{
   204  			"auth": {
   205  				"identity": {
   206  					"methods": ["password"],
   207  					"password": {
   208  						"user": {
   209  							"id": "someuser",
   210  							"password": "somepassword"
   211  						}
   212  					}
   213  				},
   214  				"scope": {
   215  					"domain": {
   216  						"name": "evil-plans"
   217  					}
   218  				}
   219  			}
   220  		}
   221  	`)
   222  }
   223  
   224  func TestCreateProjectNameAndDomainIDScope(t *testing.T) {
   225  	options := tokens.AuthOptions{UserID: "someuser", Password: "somepassword"}
   226  	scope := &tokens.Scope{ProjectName: "world-domination", DomainID: "1000"}
   227  	authTokenPost(t, options, scope, `
   228  		{
   229  			"auth": {
   230  				"identity": {
   231  					"methods": ["password"],
   232  					"password": {
   233  						"user": {
   234  							"id": "someuser",
   235  							"password": "somepassword"
   236  						}
   237  					}
   238  				},
   239  				"scope": {
   240  					"project": {
   241  						"domain": {
   242  							"id": "1000"
   243  						},
   244  						"name": "world-domination"
   245  					}
   246  				}
   247  			}
   248  		}
   249  	`)
   250  }
   251  
   252  func TestCreateProjectNameAndDomainNameScope(t *testing.T) {
   253  	options := tokens.AuthOptions{UserID: "someuser", Password: "somepassword"}
   254  	scope := &tokens.Scope{ProjectName: "world-domination", DomainName: "evil-plans"}
   255  	authTokenPost(t, options, scope, `
   256  		{
   257  			"auth": {
   258  				"identity": {
   259  					"methods": ["password"],
   260  					"password": {
   261  						"user": {
   262  							"id": "someuser",
   263  							"password": "somepassword"
   264  						}
   265  					}
   266  				},
   267  				"scope": {
   268  					"project": {
   269  						"domain": {
   270  							"name": "evil-plans"
   271  						},
   272  						"name": "world-domination"
   273  					}
   274  				}
   275  			}
   276  		}
   277  	`)
   278  }
   279  
   280  func TestCreateSystemScope(t *testing.T) {
   281  	options := tokens.AuthOptions{UserID: "someuser", Password: "somepassword"}
   282  	scope := &tokens.Scope{System: true}
   283  	authTokenPost(t, options, scope, `
   284  		{
   285  			"auth": {
   286  				"identity": {
   287  					"methods": ["password"],
   288  					"password": {
   289  						"user": {
   290  							"id": "someuser",
   291  							"password": "somepassword"
   292  						}
   293  					}
   294  				},
   295  				"scope": {
   296  					"system": {
   297  						"all": true
   298  					}
   299  				}
   300  			}
   301  		}
   302  	`)
   303  }
   304  
   305  func TestCreateUserIDPasswordTrustID(t *testing.T) {
   306  	th.SetupHTTP()
   307  	defer th.TeardownHTTP()
   308  
   309  	requestJSON := `{
   310  		"auth": {
   311  			"identity": {
   312  				"methods": ["password"],
   313  				"password": {
   314  					"user": { "id": "demo", "password": "squirrel!" }
   315  				}
   316  			},
   317  			"scope": {
   318  				"OS-TRUST:trust": {
   319  					"id": "95946f9eef864fdc993079d8fe3e5747"
   320  				}
   321  			}
   322  		}
   323  	}`
   324  	responseJSON := `{
   325  		"token": {
   326  			"OS-TRUST:trust": {
   327  				"id": "95946f9eef864fdc993079d8fe3e5747",
   328  				"impersonation": false,
   329  				"trustee_user": {
   330  					"id": "64f9caa2872b442c98d42a986ee3b37a"
   331  				},
   332  				"trustor_user": {
   333  					"id": "c88693b7c81c408e9084ac1e51082bfb"
   334  				}
   335  			},
   336  			"audit_ids": [
   337  				"wwcoUZGPR6mCIIl-COn8Kg"
   338  			],
   339  			"catalog": [],
   340  			"expires_at": "2024-02-28T12:10:39.000000Z",
   341  			"issued_at": "2024-02-28T11:10:39.000000Z",
   342  			"methods": [
   343  				"password"
   344  			],
   345  			"project": {
   346  				"domain": {
   347  					"id": "default",
   348  					"name": "Default"
   349  				},
   350  				"id": "1fd93a4455c74d2ea94b929fc5f0e488",
   351  				"name": "admin"
   352  			},
   353  			"roles": [],
   354  			"user": {
   355  				"domain": {
   356  					"id": "default",
   357  					"name": "Default"
   358  				},
   359  				"id": "64f9caa2872b442c98d42a986ee3b37a",
   360  				"name": "demo",
   361  				"password_expires_at": null
   362  			}
   363  		}
   364  	}`
   365  	th.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
   366  		th.TestMethod(t, r, "POST")
   367  		th.TestHeader(t, r, "Content-Type", "application/json")
   368  		th.TestHeader(t, r, "Accept", "application/json")
   369  		th.TestJSONRequest(t, r, requestJSON)
   370  
   371  		w.WriteHeader(http.StatusCreated)
   372  		fmt.Fprint(w, responseJSON)
   373  	})
   374  
   375  	ao := gophercloud.AuthOptions{
   376  		UserID:   "demo",
   377  		Password: "squirrel!",
   378  		Scope: &gophercloud.AuthScope{
   379  			TrustID: "95946f9eef864fdc993079d8fe3e5747",
   380  		},
   381  	}
   382  
   383  	rsp := tokens.Create(context.TODO(), client.ServiceClient(), &ao)
   384  
   385  	token, err := rsp.Extract()
   386  	if err != nil {
   387  		t.Errorf("Create returned an error: %v", err)
   388  	}
   389  	expectedToken := &tokens.Token{
   390  		ExpiresAt: time.Date(2024, 02, 28, 12, 10, 39, 0, time.UTC),
   391  	}
   392  	th.AssertDeepEquals(t, expectedToken, token)
   393  
   394  	trust, err := rsp.ExtractTrust()
   395  	if err != nil {
   396  		t.Errorf("ExtractTrust returned an error: %v", err)
   397  	}
   398  	expectedTrust := &tokens.Trust{
   399  		ID:            "95946f9eef864fdc993079d8fe3e5747",
   400  		Impersonation: false,
   401  		TrusteeUserID: tokens.TrustUser{
   402  			ID: "64f9caa2872b442c98d42a986ee3b37a",
   403  		},
   404  		TrustorUserID: tokens.TrustUser{
   405  			ID: "c88693b7c81c408e9084ac1e51082bfb",
   406  		},
   407  	}
   408  	th.AssertDeepEquals(t, expectedTrust, trust)
   409  }
   410  
   411  func TestCreateApplicationCredentialIDAndSecret(t *testing.T) {
   412  	authTokenPost(t, tokens.AuthOptions{ApplicationCredentialID: "12345abcdef", ApplicationCredentialSecret: "mysecret"}, nil, `
   413  		{
   414  			"auth": {
   415  				"identity": {
   416  					"application_credential": {
   417  						"id": "12345abcdef",
   418  						"secret": "mysecret"
   419  					},
   420  					"methods": [
   421  						"application_credential"
   422  					]
   423  				}
   424  			}
   425  		}
   426  	`)
   427  }
   428  
   429  func TestCreateApplicationCredentialNameAndSecret(t *testing.T) {
   430  	authTokenPost(t, tokens.AuthOptions{ApplicationCredentialName: "myappcred", ApplicationCredentialSecret: "mysecret", Username: "someuser", DomainName: "evil-plans"}, nil, `
   431  		{
   432  			"auth": {
   433  				"identity": {
   434  					"application_credential": {
   435  						"name": "myappcred",
   436  						"secret": "mysecret",
   437  						"user": {
   438  							"name": "someuser",
   439  							"domain": {
   440  								"name": "evil-plans"
   441  							}
   442  						}
   443  					},
   444  					"methods": [
   445  						"application_credential"
   446  					]
   447  				}
   448  			}
   449  		}
   450  	`)
   451  }
   452  
   453  func TestCreateTOTPProjectNameAndDomainNameScope(t *testing.T) {
   454  	options := tokens.AuthOptions{UserID: "someuser", Passcode: "12345678"}
   455  	scope := &tokens.Scope{ProjectName: "world-domination", DomainName: "evil-plans"}
   456  	authTokenPost(t, options, scope, `
   457  		{
   458  			"auth": {
   459  				"identity": {
   460  					"methods": ["totp"],
   461  					"totp": {
   462  						"user": {
   463  							"id": "someuser",
   464  							"passcode": "12345678"
   465  						}
   466  					}
   467  				},
   468  				"scope": {
   469  					"project": {
   470  						"domain": {
   471  							"name": "evil-plans"
   472  						},
   473  						"name": "world-domination"
   474  					}
   475  				}
   476  			}
   477  		}
   478  	`)
   479  }
   480  
   481  func TestCreatePasswordTOTPProjectNameAndDomainNameScope(t *testing.T) {
   482  	options := tokens.AuthOptions{UserID: "someuser", Password: "somepassword", Passcode: "12345678"}
   483  	scope := &tokens.Scope{ProjectName: "world-domination", DomainName: "evil-plans"}
   484  	authTokenPost(t, options, scope, `
   485  		{
   486  			"auth": {
   487  				"identity": {
   488  					"methods": ["password","totp"],
   489  					"password": {
   490  						"user": {
   491  							"id": "someuser",
   492  							"password": "somepassword"
   493  						}
   494  					},
   495  					"totp": {
   496  						"user": {
   497  							"id": "someuser",
   498  							"passcode": "12345678"
   499  						}
   500  					}
   501  				},
   502  				"scope": {
   503  					"project": {
   504  						"domain": {
   505  							"name": "evil-plans"
   506  						},
   507  						"name": "world-domination"
   508  					}
   509  				}
   510  			}
   511  		}
   512  	`)
   513  }
   514  
   515  func TestCreateExtractsTokenFromResponse(t *testing.T) {
   516  	th.SetupHTTP()
   517  	defer th.TeardownHTTP()
   518  
   519  	client := gophercloud.ServiceClient{
   520  		ProviderClient: &gophercloud.ProviderClient{},
   521  		Endpoint:       th.Endpoint(),
   522  	}
   523  
   524  	th.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
   525  		w.Header().Add("X-Subject-Token", "aaa111")
   526  
   527  		w.WriteHeader(http.StatusCreated)
   528  		fmt.Fprint(w, `{
   529  			"token": {
   530  				"expires_at": "2014-10-02T13:45:00.000000Z"
   531  			}
   532  		}`)
   533  	})
   534  
   535  	options := tokens.AuthOptions{UserID: "me", Password: "shhh"}
   536  	token, err := tokens.Create(context.TODO(), &client, &options).Extract()
   537  	if err != nil {
   538  		t.Fatalf("Create returned an error: %v", err)
   539  	}
   540  
   541  	if token.ID != "aaa111" {
   542  		t.Errorf("Expected token to be aaa111, but was %s", token.ID)
   543  	}
   544  }
   545  
   546  func TestCreateFailureEmptyAuth(t *testing.T) {
   547  	authTokenPostErr(t, tokens.AuthOptions{}, nil, false, gophercloud.ErrMissingPassword{})
   548  }
   549  
   550  func TestCreateFailureTokenIDUsername(t *testing.T) {
   551  	authTokenPostErr(t, tokens.AuthOptions{Username: "something", TokenID: "12345"}, nil, true, gophercloud.ErrUsernameWithToken{})
   552  }
   553  
   554  func TestCreateFailureTokenIDUserID(t *testing.T) {
   555  	authTokenPostErr(t, tokens.AuthOptions{UserID: "something", TokenID: "12345"}, nil, true, gophercloud.ErrUserIDWithToken{})
   556  }
   557  
   558  func TestCreateFailureTokenIDDomainID(t *testing.T) {
   559  	authTokenPostErr(t, tokens.AuthOptions{DomainID: "something", TokenID: "12345"}, nil, true, gophercloud.ErrDomainIDWithToken{})
   560  }
   561  
   562  func TestCreateFailureTokenIDDomainName(t *testing.T) {
   563  	authTokenPostErr(t, tokens.AuthOptions{DomainName: "something", TokenID: "12345"}, nil, true, gophercloud.ErrDomainNameWithToken{})
   564  }
   565  
   566  func TestCreateFailureMissingUser(t *testing.T) {
   567  	options := tokens.AuthOptions{Password: "supersecure"}
   568  	authTokenPostErr(t, options, nil, false, gophercloud.ErrUsernameOrUserID{})
   569  }
   570  
   571  func TestCreateFailureBothUser(t *testing.T) {
   572  	options := tokens.AuthOptions{
   573  		Password: "supersecure",
   574  		Username: "oops",
   575  		UserID:   "redundancy",
   576  	}
   577  	authTokenPostErr(t, options, nil, false, gophercloud.ErrUsernameOrUserID{})
   578  }
   579  
   580  func TestCreateFailureMissingDomain(t *testing.T) {
   581  	options := tokens.AuthOptions{
   582  		Password: "supersecure",
   583  		Username: "notuniqueenough",
   584  	}
   585  	authTokenPostErr(t, options, nil, false, gophercloud.ErrDomainIDOrDomainName{})
   586  }
   587  
   588  func TestCreateFailureBothDomain(t *testing.T) {
   589  	options := tokens.AuthOptions{
   590  		Password:   "supersecure",
   591  		Username:   "someone",
   592  		DomainID:   "hurf",
   593  		DomainName: "durf",
   594  	}
   595  	authTokenPostErr(t, options, nil, false, gophercloud.ErrDomainIDOrDomainName{})
   596  }
   597  
   598  func TestCreateFailureUserIDDomainID(t *testing.T) {
   599  	options := tokens.AuthOptions{
   600  		UserID:   "100",
   601  		Password: "stuff",
   602  		DomainID: "oops",
   603  	}
   604  	authTokenPostErr(t, options, nil, false, gophercloud.ErrDomainIDWithUserID{})
   605  }
   606  
   607  func TestCreateFailureUserIDDomainName(t *testing.T) {
   608  	options := tokens.AuthOptions{
   609  		UserID:     "100",
   610  		Password:   "sssh",
   611  		DomainName: "oops",
   612  	}
   613  	authTokenPostErr(t, options, nil, false, gophercloud.ErrDomainNameWithUserID{})
   614  }
   615  
   616  func TestCreateFailureScopeProjectNameAlone(t *testing.T) {
   617  	options := tokens.AuthOptions{UserID: "myself", Password: "swordfish"}
   618  	scope := &tokens.Scope{ProjectName: "notenough"}
   619  	authTokenPostErr(t, options, scope, false, gophercloud.ErrScopeDomainIDOrDomainName{})
   620  }
   621  
   622  func TestCreateFailureScopeProjectNameAndID(t *testing.T) {
   623  	options := tokens.AuthOptions{UserID: "myself", Password: "swordfish"}
   624  	scope := &tokens.Scope{ProjectName: "whoops", ProjectID: "toomuch", DomainID: "1234"}
   625  	authTokenPostErr(t, options, scope, false, gophercloud.ErrScopeProjectIDOrProjectName{})
   626  }
   627  
   628  func TestCreateFailureScopeProjectIDAndDomainID(t *testing.T) {
   629  	options := tokens.AuthOptions{UserID: "myself", Password: "swordfish"}
   630  	scope := &tokens.Scope{ProjectID: "toomuch", DomainID: "notneeded"}
   631  	authTokenPostErr(t, options, scope, false, gophercloud.ErrScopeProjectIDAlone{})
   632  }
   633  
   634  func TestCreateFailureScopeProjectIDAndDomainNAme(t *testing.T) {
   635  	options := tokens.AuthOptions{UserID: "myself", Password: "swordfish"}
   636  	scope := &tokens.Scope{ProjectID: "toomuch", DomainName: "notneeded"}
   637  	authTokenPostErr(t, options, scope, false, gophercloud.ErrScopeProjectIDAlone{})
   638  }
   639  
   640  func TestCreateFailureScopeDomainIDAndDomainName(t *testing.T) {
   641  	options := tokens.AuthOptions{UserID: "myself", Password: "swordfish"}
   642  	scope := &tokens.Scope{DomainID: "toomuch", DomainName: "notneeded"}
   643  	authTokenPostErr(t, options, scope, false, gophercloud.ErrScopeDomainIDOrDomainName{})
   644  }
   645  
   646  /*
   647  func TestCreateFailureEmptyScope(t *testing.T) {
   648  	options := tokens.AuthOptions{UserID: "myself", Password: "swordfish"}
   649  	scope := &tokens.Scope{}
   650  	authTokenPostErr(t, options, scope, false, gophercloud.ErrScopeEmpty{})
   651  }
   652  */
   653  
   654  func TestGetRequest(t *testing.T) {
   655  	th.SetupHTTP()
   656  	defer th.TeardownHTTP()
   657  
   658  	client := gophercloud.ServiceClient{
   659  		ProviderClient: &gophercloud.ProviderClient{
   660  			TokenID: "12345abcdef",
   661  		},
   662  		Endpoint: th.Endpoint(),
   663  	}
   664  
   665  	th.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
   666  		th.TestMethod(t, r, "GET")
   667  		th.TestHeaderUnset(t, r, "Content-Type")
   668  		th.TestHeader(t, r, "Accept", "application/json")
   669  		th.TestHeader(t, r, "X-Auth-Token", "12345abcdef")
   670  		th.TestHeader(t, r, "X-Subject-Token", "abcdef12345")
   671  
   672  		w.WriteHeader(http.StatusOK)
   673  		fmt.Fprint(w, `
   674  			{ "token": { "expires_at": "2014-08-29T13:10:01.000000Z" } }
   675  		`)
   676  	})
   677  
   678  	token, err := tokens.Get(context.TODO(), &client, "abcdef12345").Extract()
   679  	if err != nil {
   680  		t.Errorf("Info returned an error: %v", err)
   681  	}
   682  
   683  	expected, _ := time.Parse(time.UnixDate, "Fri Aug 29 13:10:01 UTC 2014")
   684  	if token.ExpiresAt != expected {
   685  		t.Errorf("Expected expiration time %s, but was %s", expected.Format(time.UnixDate), time.Time(token.ExpiresAt).Format(time.UnixDate))
   686  	}
   687  }
   688  
   689  func prepareAuthTokenHandler(t *testing.T, expectedMethod string, status int) gophercloud.ServiceClient {
   690  	client := gophercloud.ServiceClient{
   691  		ProviderClient: &gophercloud.ProviderClient{
   692  			TokenID: "12345abcdef",
   693  		},
   694  		Endpoint: th.Endpoint(),
   695  	}
   696  
   697  	th.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
   698  		th.TestMethod(t, r, expectedMethod)
   699  		th.TestHeaderUnset(t, r, "Content-Type")
   700  		th.TestHeader(t, r, "Accept", "application/json")
   701  		th.TestHeader(t, r, "X-Auth-Token", "12345abcdef")
   702  		th.TestHeader(t, r, "X-Subject-Token", "abcdef12345")
   703  
   704  		w.WriteHeader(status)
   705  	})
   706  
   707  	return client
   708  }
   709  
   710  func TestValidateRequestSuccessful(t *testing.T) {
   711  	th.SetupHTTP()
   712  	defer th.TeardownHTTP()
   713  	client := prepareAuthTokenHandler(t, "HEAD", http.StatusNoContent)
   714  
   715  	ok, err := tokens.Validate(context.TODO(), &client, "abcdef12345")
   716  	if err != nil {
   717  		t.Errorf("Unexpected error from Validate: %v", err)
   718  	}
   719  
   720  	if !ok {
   721  		t.Errorf("Validate returned false for a valid token")
   722  	}
   723  }
   724  
   725  func TestValidateRequestFailure(t *testing.T) {
   726  	th.SetupHTTP()
   727  	defer th.TeardownHTTP()
   728  	client := prepareAuthTokenHandler(t, "HEAD", http.StatusNotFound)
   729  
   730  	ok, err := tokens.Validate(context.TODO(), &client, "abcdef12345")
   731  	if err != nil {
   732  		t.Errorf("Unexpected error from Validate: %v", err)
   733  	}
   734  
   735  	if ok {
   736  		t.Errorf("Validate returned true for an invalid token")
   737  	}
   738  }
   739  
   740  func TestValidateRequestError(t *testing.T) {
   741  	th.SetupHTTP()
   742  	defer th.TeardownHTTP()
   743  	client := prepareAuthTokenHandler(t, "HEAD", http.StatusMethodNotAllowed)
   744  
   745  	_, err := tokens.Validate(context.TODO(), &client, "abcdef12345")
   746  	if err == nil {
   747  		t.Errorf("Missing expected error from Validate")
   748  	}
   749  }
   750  
   751  func TestRevokeRequestSuccessful(t *testing.T) {
   752  	th.SetupHTTP()
   753  	defer th.TeardownHTTP()
   754  	client := prepareAuthTokenHandler(t, "DELETE", http.StatusNoContent)
   755  
   756  	res := tokens.Revoke(context.TODO(), &client, "abcdef12345")
   757  	th.AssertNoErr(t, res.Err)
   758  }
   759  
   760  func TestRevokeRequestError(t *testing.T) {
   761  	th.SetupHTTP()
   762  	defer th.TeardownHTTP()
   763  	client := prepareAuthTokenHandler(t, "DELETE", http.StatusNotFound)
   764  
   765  	res := tokens.Revoke(context.TODO(), &client, "abcdef12345")
   766  	if res.Err == nil {
   767  		t.Errorf("Missing expected error from Revoke")
   768  	}
   769  }
   770  
   771  func TestNoTokenInResponse(t *testing.T) {
   772  	th.SetupHTTP()
   773  	defer th.TeardownHTTP()
   774  
   775  	client := gophercloud.ServiceClient{
   776  		ProviderClient: &gophercloud.ProviderClient{},
   777  		Endpoint:       th.Endpoint(),
   778  	}
   779  
   780  	th.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
   781  		w.WriteHeader(http.StatusCreated)
   782  		fmt.Fprint(w, `{}`)
   783  	})
   784  
   785  	options := tokens.AuthOptions{UserID: "me", Password: "squirrel!"}
   786  	_, err := tokens.Create(context.TODO(), &client, &options).Extract()
   787  	th.AssertNoErr(t, err)
   788  }