github.com/gophercloud/gophercloud@v1.11.0/openstack/identity/v3/tokens/testing/requests_test.go (about)

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