gopkg.in/goose.v2@v2.0.1/cinder/client_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the LGPLv3, see LICENCE file for details.
     3  
     4  package cinder
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/json"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"net/http"
    12  	"net/url"
    13  
    14  	gc "gopkg.in/check.v1"
    15  )
    16  
    17  const (
    18  	testId        = "test-id"
    19  	testToken     = "test-token"
    20  	testTime      = "test-time"
    21  	testDescr     = "test-description"
    22  	testName      = "test-name"
    23  	testAttrProgr = "test-attribute-prog"
    24  	testAttrProj  = "test-attribute-proj"
    25  	testStatus    = "test-status"
    26  )
    27  
    28  var _ = gc.Suite(&CinderTestSuite{})
    29  
    30  type CinderTestSuite struct {
    31  	client *Client
    32  	*http.ServeMux
    33  }
    34  
    35  func (s *CinderTestSuite) SetUpSuite(c *gc.C) {
    36  
    37  	if *live {
    38  		return
    39  	}
    40  
    41  	endpoint, err := url.Parse("http://volume.testing/v2/" + testId)
    42  	c.Assert(err, gc.IsNil)
    43  
    44  	cinderClient := NewClient(
    45  		testId,
    46  		endpoint,
    47  		SetAuthHeaderFn(func() string { return testToken }, s.localDo),
    48  	)
    49  	s.client = cinderClient
    50  }
    51  
    52  func (s *CinderTestSuite) SetUpTest(c *gc.C) {
    53  
    54  	if *live {
    55  		c.Skip("Only running live tests.")
    56  	}
    57  
    58  	// We want a fresh Muxer so that any paths that aren't explicitly
    59  	// set up by the test are treated as errors.
    60  	s.ServeMux = http.NewServeMux()
    61  }
    62  
    63  func (s *CinderTestSuite) TestCreateSnapshot(c *gc.C) {
    64  
    65  	snapReq := CreateSnapshotSnapshotParams{
    66  		VolumeId:    testId,
    67  		Name:        testName,
    68  		Description: testDescr,
    69  	}
    70  
    71  	numCalls := 0
    72  	s.HandleFunc("/v2/"+testId+"/snapshots", func(w http.ResponseWriter, req *http.Request) {
    73  		numCalls++
    74  
    75  		c.Check(req.Header["X-Auth-Token"], gc.DeepEquals, []string{testToken})
    76  
    77  		reqBody, err := ioutil.ReadAll(req.Body)
    78  		c.Assert(err, gc.IsNil)
    79  
    80  		var receivedReq CreateSnapshotParams
    81  		err = json.Unmarshal(reqBody, &receivedReq)
    82  		c.Assert(err, gc.IsNil)
    83  
    84  		c.Check(receivedReq, gc.DeepEquals, CreateSnapshotParams{Snapshot: snapReq})
    85  
    86  		resp := Snapshot{
    87  			CreatedAt:   "test-time",
    88  			Description: receivedReq.Snapshot.Description,
    89  			ID:          "test-id",
    90  			Name:        receivedReq.Snapshot.Name,
    91  			Size:        1,
    92  			Status:      "test-status",
    93  			VolumeID:    receivedReq.Snapshot.VolumeId,
    94  		}
    95  		respBody, err := json.Marshal(&CreateSnapshotResults{Snapshot: resp})
    96  		c.Assert(err, gc.IsNil)
    97  
    98  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewReader(respBody))
    99  		w.(*responseWriter).StatusCode = 202
   100  	})
   101  
   102  	resp, err := s.client.CreateSnapshot(snapReq)
   103  	c.Assert(numCalls, gc.Equals, 1)
   104  	c.Assert(err, gc.IsNil)
   105  
   106  	c.Check(resp.Snapshot.CreatedAt, gc.Equals, testTime)
   107  	c.Check(resp.Snapshot.Description, gc.Equals, snapReq.Description)
   108  	c.Check(resp.Snapshot.ID, gc.Equals, testId)
   109  	c.Check(resp.Snapshot.Name, gc.Equals, snapReq.Name)
   110  	c.Check(resp.Snapshot.Size, gc.Equals, 1)
   111  	c.Check(resp.Snapshot.Status, gc.Equals, testStatus)
   112  	c.Check(resp.Snapshot.VolumeID, gc.Equals, snapReq.VolumeId)
   113  
   114  }
   115  
   116  func (s *CinderTestSuite) TestDeleteSnapshot(c *gc.C) {
   117  	numCalls := 0
   118  	s.HandleFunc("/v2/"+testId+"/snapshots/"+testId, func(w http.ResponseWriter, req *http.Request) {
   119  		numCalls++
   120  
   121  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
   122  		w.(*responseWriter).StatusCode = 202
   123  	})
   124  
   125  	err := s.client.DeleteSnapshot(testId)
   126  	c.Assert(numCalls, gc.Equals, 1)
   127  	c.Assert(err, gc.IsNil)
   128  }
   129  
   130  func (s *CinderTestSuite) TestGetSnapshot(c *gc.C) {
   131  
   132  	numCalls := 0
   133  	s.HandleFunc("/v2/"+testId+"/snapshots/"+testId, func(w http.ResponseWriter, req *http.Request) {
   134  		numCalls++
   135  
   136  		c.Check(req.Header["X-Auth-Token"], gc.DeepEquals, []string{testToken})
   137  
   138  		resp := Snapshot{
   139  			CreatedAt:                                testTime,
   140  			Description:                              testDescr,
   141  			ID:                                       testId,
   142  			Name:                                     testName,
   143  			Os_Extended_Snapshot_Attributes_Progress: testAttrProgr,
   144  			Os_Extended_Snapshot_Attributes_ProjectID: testAttrProj,
   145  			Size:     1,
   146  			Status:   testStatus,
   147  			VolumeID: testId,
   148  		}
   149  
   150  		respBody, err := json.Marshal(&GetSnapshotResults{Snapshot: resp})
   151  		c.Assert(err, gc.IsNil)
   152  
   153  		w.(*responseWriter).Response.StatusCode = 200
   154  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewReader(respBody))
   155  	})
   156  
   157  	// Test GetSnapshot
   158  	getResp, err := s.client.GetSnapshot(testId)
   159  	c.Assert(err, gc.IsNil)
   160  	c.Assert(numCalls, gc.Equals, 1)
   161  
   162  	c.Check(getResp.Snapshot.CreatedAt, gc.Not(gc.HasLen), 0)
   163  	c.Check(getResp.Snapshot.Description, gc.Equals, testDescr)
   164  	c.Check(getResp.Snapshot.ID, gc.Not(gc.HasLen), 0)
   165  	c.Check(getResp.Snapshot.Name, gc.Equals, testName)
   166  	c.Check(getResp.Snapshot.Size, gc.Equals, 1)
   167  	c.Check(getResp.Snapshot.Status, gc.Equals, testStatus)
   168  	c.Check(getResp.Snapshot.VolumeID, gc.Equals, testId)
   169  }
   170  
   171  func (s *CinderTestSuite) TestGetSnapshotDetail(c *gc.C) {
   172  
   173  	numCalls := 0
   174  	s.HandleFunc("/v2/"+testId+"/snapshots/detail", func(w http.ResponseWriter, req *http.Request) {
   175  		numCalls++
   176  
   177  		c.Check(req.Header["X-Auth-Token"], gc.DeepEquals, []string{testToken})
   178  
   179  		resp := []Snapshot{{
   180  			CreatedAt:                                testTime,
   181  			Description:                              testDescr,
   182  			ID:                                       testId,
   183  			Name:                                     testName,
   184  			Os_Extended_Snapshot_Attributes_Progress: testAttrProgr,
   185  			Os_Extended_Snapshot_Attributes_ProjectID: testAttrProj,
   186  			Size:     1,
   187  			Status:   testStatus,
   188  			VolumeID: testId,
   189  		}}
   190  
   191  		respBody, err := json.Marshal(&GetSnapshotsDetailResults{Snapshots: resp})
   192  		c.Assert(err, gc.IsNil)
   193  
   194  		w.(*responseWriter).Response.StatusCode = 200
   195  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewReader(respBody))
   196  	})
   197  
   198  	detailGetResp, err := s.client.GetSnapshotsDetail()
   199  	c.Assert(err, gc.IsNil)
   200  	c.Assert(detailGetResp.Snapshots, gc.HasLen, 1)
   201  	c.Assert(numCalls, gc.Equals, 1)
   202  
   203  	snapshot := detailGetResp.Snapshots[0]
   204  
   205  	c.Check(snapshot.CreatedAt, gc.Equals, testTime)
   206  	c.Check(snapshot.Description, gc.Equals, testDescr)
   207  	c.Check(snapshot.ID, gc.Equals, testId)
   208  	c.Check(snapshot.Name, gc.Equals, testName)
   209  	c.Check(snapshot.Os_Extended_Snapshot_Attributes_Progress, gc.Equals, testAttrProgr)
   210  	c.Check(snapshot.Os_Extended_Snapshot_Attributes_ProjectID, gc.Equals, testAttrProj)
   211  	c.Check(snapshot.Size, gc.Equals, 1)
   212  	c.Check(snapshot.Status, gc.Equals, testStatus)
   213  	c.Check(snapshot.VolumeID, gc.Equals, testId)
   214  }
   215  
   216  func (s *CinderTestSuite) TestGetSnapshotSimple(c *gc.C) {
   217  
   218  	numCalls := 0
   219  	s.HandleFunc("/v2/"+testId+"/snapshots", func(w http.ResponseWriter, req *http.Request) {
   220  		numCalls++
   221  
   222  		c.Check(req.Header["X-Auth-Token"], gc.DeepEquals, []string{testToken})
   223  
   224  		resp := []Snapshot{{
   225  			CreatedAt:                                testTime,
   226  			Description:                              testDescr,
   227  			ID:                                       testId,
   228  			Name:                                     testName,
   229  			Os_Extended_Snapshot_Attributes_Progress: testAttrProgr,
   230  			Os_Extended_Snapshot_Attributes_ProjectID: testAttrProj,
   231  			Size:     1,
   232  			Status:   testStatus,
   233  			VolumeID: testId,
   234  		}}
   235  
   236  		respBody, err := json.Marshal(&GetSnapshotsDetailResults{Snapshots: resp})
   237  		c.Assert(err, gc.IsNil)
   238  
   239  		w.(*responseWriter).Response.StatusCode = 200
   240  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewReader(respBody))
   241  	})
   242  
   243  	snapshotSimpResp, err := s.client.GetSnapshotsSimple()
   244  	c.Assert(numCalls, gc.Equals, 1)
   245  	c.Assert(err, gc.IsNil)
   246  	c.Assert(snapshotSimpResp.Snapshots, gc.HasLen, 1)
   247  
   248  	snapshot := snapshotSimpResp.Snapshots[0]
   249  
   250  	c.Check(snapshot.CreatedAt, gc.Equals, testTime)
   251  	c.Check(snapshot.Description, gc.Equals, testDescr)
   252  	c.Check(snapshot.ID, gc.Equals, testId)
   253  	c.Check(snapshot.Name, gc.Equals, testName)
   254  	c.Check(snapshot.Size, gc.Equals, 1)
   255  	c.Check(snapshot.Status, gc.Equals, testStatus)
   256  	c.Check(snapshot.VolumeID, gc.Equals, testId)
   257  }
   258  
   259  func (s *CinderTestSuite) TestShowSnapshotMetadata(c *gc.C) {
   260  
   261  	numCalls := 0
   262  	s.HandleFunc("/v2/"+testId+"/snapshots/"+testId+"/metadata", func(w http.ResponseWriter, req *http.Request) {
   263  		numCalls++
   264  
   265  		c.Check(req.Header["X-Auth-Token"], gc.DeepEquals, []string{testToken})
   266  
   267  		resp := Snapshot{
   268  			CreatedAt:                                testTime,
   269  			Description:                              testDescr,
   270  			ID:                                       testId,
   271  			Name:                                     testName,
   272  			Os_Extended_Snapshot_Attributes_Progress: testAttrProgr,
   273  			Os_Extended_Snapshot_Attributes_ProjectID: testAttrProj,
   274  			Size:     1,
   275  			Status:   testStatus,
   276  			VolumeID: testId,
   277  		}
   278  
   279  		respBody, err := json.Marshal(&ShowSnapshotMetadataResults{Snapshot: resp})
   280  		c.Assert(err, gc.IsNil)
   281  
   282  		w.(*responseWriter).Response.StatusCode = 200
   283  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewReader(respBody))
   284  	})
   285  
   286  	resp, err := s.client.ShowSnapshotMetadata(testId)
   287  	c.Assert(err, gc.IsNil)
   288  
   289  	c.Check(resp.Snapshot.CreatedAt, gc.Equals, testTime)
   290  	c.Check(resp.Snapshot.Description, gc.Equals, testDescr)
   291  	c.Check(resp.Snapshot.ID, gc.Equals, testId)
   292  	c.Check(resp.Snapshot.Name, gc.Equals, testName)
   293  	c.Check(resp.Snapshot.Size, gc.Equals, 1)
   294  	c.Check(resp.Snapshot.Status, gc.Equals, testStatus)
   295  	c.Check(resp.Snapshot.VolumeID, gc.Equals, testId)
   296  }
   297  
   298  func (s *CinderTestSuite) TestUpdateSnapshot(c *gc.C) {
   299  
   300  	updateReq := UpdateSnapshotSnapshotParams{testName, testDescr}
   301  
   302  	numCalls := 0
   303  	s.HandleFunc("/v2/"+testId+"/snapshots/"+testId, func(w http.ResponseWriter, req *http.Request) {
   304  		numCalls++
   305  
   306  		c.Check(req.Header["X-Auth-Token"], gc.DeepEquals, []string{testToken})
   307  
   308  		reqBody, err := ioutil.ReadAll(req.Body)
   309  		c.Assert(err, gc.IsNil)
   310  
   311  		var receivedReq UpdateSnapshotParams
   312  		err = json.Unmarshal(reqBody, &receivedReq)
   313  		c.Assert(err, gc.IsNil)
   314  
   315  		c.Check(receivedReq, gc.DeepEquals, UpdateSnapshotParams{Snapshot: updateReq})
   316  
   317  		resp := Snapshot{
   318  			CreatedAt:   testTime,
   319  			Description: updateReq.Description,
   320  			ID:          testId,
   321  			Name:        updateReq.Name,
   322  			Size:        1,
   323  			Status:      testStatus,
   324  			VolumeID:    testId,
   325  		}
   326  
   327  		respBody, err := json.Marshal(&UpdateSnapshotResults{Snapshot: resp})
   328  		c.Assert(err, gc.IsNil)
   329  
   330  		w.(*responseWriter).Response.StatusCode = 200
   331  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewReader(respBody))
   332  	})
   333  
   334  	resp, err := s.client.UpdateSnapshot(testId, updateReq)
   335  	c.Assert(numCalls, gc.Equals, 1)
   336  	c.Assert(err, gc.IsNil)
   337  
   338  	c.Check(resp.Snapshot.CreatedAt, gc.Equals, testTime)
   339  	c.Check(resp.Snapshot.Description, gc.Equals, updateReq.Description)
   340  	c.Check(resp.Snapshot.ID, gc.Equals, testId)
   341  	c.Check(resp.Snapshot.Name, gc.Equals, updateReq.Name)
   342  	c.Check(resp.Snapshot.Size, gc.Equals, 1)
   343  	c.Check(resp.Snapshot.Status, gc.Equals, testStatus)
   344  	c.Check(resp.Snapshot.VolumeID, gc.Equals, testId)
   345  }
   346  
   347  func (s *CinderTestSuite) TestUpdateSnapshotMetadata(c *gc.C) {
   348  
   349  	numCalls := 0
   350  	s.HandleFunc("/v2/"+testId+"/snapshots/"+testId+"/metadata", func(w http.ResponseWriter, req *http.Request) {
   351  		numCalls++
   352  
   353  		c.Check(req.Header["X-Auth-Token"], gc.DeepEquals, []string{testToken})
   354  
   355  		reqBody, err := ioutil.ReadAll(req.Body)
   356  		c.Assert(err, gc.IsNil)
   357  
   358  		var receivedReq UpdateSnapshotMetadataParams
   359  		err = json.Unmarshal(reqBody, &receivedReq)
   360  		c.Assert(err, gc.IsNil)
   361  
   362  		c.Check(receivedReq.Metadata.Key, gc.DeepEquals, "test-key")
   363  
   364  		resp := struct {
   365  			Key string `json:"key"`
   366  		}{
   367  			Key: receivedReq.Metadata.Key,
   368  		}
   369  
   370  		respBody, err := json.Marshal(&UpdateSnapshotMetadataResults{Metadata: resp})
   371  		c.Assert(err, gc.IsNil)
   372  
   373  		w.(*responseWriter).Response.StatusCode = 200
   374  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewReader(respBody))
   375  	})
   376  
   377  	resp, err := s.client.UpdateSnapshotMetadata(testId, "test-key")
   378  	c.Assert(numCalls, gc.Equals, 1)
   379  	c.Assert(err, gc.IsNil)
   380  
   381  	c.Check(resp.Metadata.Key, gc.Equals, "test-key")
   382  }
   383  
   384  func (s *CinderTestSuite) TestCreateVolume(c *gc.C) {
   385  	req := CreateVolumeVolumeParams{
   386  		Description: testDescr,
   387  		Size:        1,
   388  		Name:        testName,
   389  	}
   390  
   391  	numCalls := 0
   392  	s.HandleFunc("/v2/"+testId+"/volumes", func(w http.ResponseWriter, req *http.Request) {
   393  		numCalls++
   394  
   395  		reqBody, err := ioutil.ReadAll(req.Body)
   396  		c.Assert(err, gc.IsNil)
   397  
   398  		var receivedReq CreateVolumeParams
   399  		err = json.Unmarshal(reqBody, &receivedReq)
   400  		c.Assert(err, gc.IsNil)
   401  
   402  		resp := Volume{
   403  			AvailabilityZone: receivedReq.Volume.AvailabilityZone,
   404  			Bootable:         fmt.Sprintf("%v", receivedReq.Volume.Bootable),
   405  			CreatedAt:        "test-time",
   406  			Description:      receivedReq.Volume.Description,
   407  			Name:             receivedReq.Volume.Name,
   408  			Size:             receivedReq.Volume.Size,
   409  			SnapshotID:       testId,
   410  			SourceVolid:      testId,
   411  			Status:           testStatus,
   412  			VolumeType:       "test-volume-type",
   413  		}
   414  
   415  		respBody, err := json.Marshal(&CreateVolumeResults{Volume: resp})
   416  		c.Assert(err, gc.IsNil)
   417  
   418  		w.(*responseWriter).Response.StatusCode = 202
   419  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewReader(respBody))
   420  		c.Assert(w.(*responseWriter).Body, gc.NotNil)
   421  	})
   422  
   423  	resp, err := s.client.CreateVolume(req)
   424  	c.Assert(numCalls, gc.Equals, 1)
   425  	c.Assert(err, gc.IsNil)
   426  
   427  	c.Check(resp.Volume.Name, gc.Equals, req.Name)
   428  	c.Check(resp.Volume.AvailabilityZone, gc.Equals, req.AvailabilityZone)
   429  	c.Check(resp.Volume.Bootable, gc.Equals, fmt.Sprintf("%v", req.Bootable))
   430  	c.Check(resp.Volume.Description, gc.Equals, req.Description)
   431  	c.Check(resp.Volume.Size, gc.Equals, req.Size)
   432  	c.Check(resp.Volume.SnapshotID, gc.Equals, testId)
   433  	c.Check(resp.Volume.SourceVolid, gc.Equals, testId)
   434  	c.Check(resp.Volume.Status, gc.Equals, testStatus)
   435  	c.Check(resp.Volume.VolumeType, gc.Equals, "test-volume-type")
   436  }
   437  
   438  func (s *CinderTestSuite) TestDeleteVolume(c *gc.C) {
   439  
   440  	numCalls := 0
   441  	s.HandleFunc("/v2/"+testId+"/volumes/"+testId, func(w http.ResponseWriter, req *http.Request) {
   442  		numCalls++
   443  
   444  		w.(*responseWriter).Response.StatusCode = 202
   445  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewBuffer([]byte{}))
   446  	})
   447  
   448  	err := s.client.DeleteVolume(testId)
   449  	c.Assert(numCalls, gc.Equals, 1)
   450  	c.Assert(err, gc.IsNil)
   451  }
   452  
   453  func (s *CinderTestSuite) TestUpdateVolume(c *gc.C) {
   454  
   455  	updateReq := UpdateVolumeVolumeParams{testName, testDescr}
   456  
   457  	numCalls := 0
   458  	s.HandleFunc("/v2/"+testId+"/volumes/"+testId, func(w http.ResponseWriter, req *http.Request) {
   459  		numCalls++
   460  
   461  		reqBody, err := ioutil.ReadAll(req.Body)
   462  		c.Assert(err, gc.IsNil)
   463  
   464  		var receivedReq UpdateVolumeParams
   465  		err = json.Unmarshal(reqBody, &receivedReq)
   466  		c.Assert(err, gc.IsNil)
   467  
   468  		resp := Volume{
   469  			AvailabilityZone: "test-avail-zone",
   470  			Bootable:         "false",
   471  			CreatedAt:        "test-time",
   472  			Description:      receivedReq.Volume.Description,
   473  			Name:             receivedReq.Volume.Name,
   474  			Size:             1,
   475  			SnapshotID:       testId,
   476  			SourceVolid:      testId,
   477  			Status:           testStatus,
   478  			VolumeType:       "test-volume-type",
   479  		}
   480  
   481  		respBody, err := json.Marshal(&CreateVolumeResults{Volume: resp})
   482  		c.Assert(err, gc.IsNil)
   483  
   484  		w.(*responseWriter).Response.StatusCode = 200
   485  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewReader(respBody))
   486  		c.Assert(w.(*responseWriter).Body, gc.NotNil)
   487  	})
   488  
   489  	resp, err := s.client.UpdateVolume(testId, updateReq)
   490  	c.Assert(numCalls, gc.Equals, 1)
   491  	c.Assert(err, gc.IsNil)
   492  
   493  	c.Check(resp.Volume.Name, gc.Equals, updateReq.Name)
   494  	c.Check(resp.Volume.AvailabilityZone, gc.Equals, "test-avail-zone")
   495  	c.Check(resp.Volume.Description, gc.Equals, updateReq.Description)
   496  	c.Check(resp.Volume.Size, gc.Equals, 1)
   497  	c.Check(resp.Volume.SnapshotID, gc.Equals, testId)
   498  	c.Check(resp.Volume.SourceVolid, gc.Equals, testId)
   499  	c.Check(resp.Volume.Status, gc.Equals, testStatus)
   500  	c.Check(resp.Volume.VolumeType, gc.Equals, "test-volume-type")
   501  }
   502  
   503  func (s *CinderTestSuite) TestUpdateVolumeType(c *gc.C) {
   504  
   505  	numCalls := 0
   506  	s.HandleFunc("/v2/"+testId+"/types/"+testId, func(w http.ResponseWriter, req *http.Request) {
   507  		numCalls++
   508  
   509  		resp := struct {
   510  			ExtraSpecs struct {
   511  				Capabilities string `json:"capabilities"`
   512  			} `json:"extra_specs"`
   513  			ID   string `json:"id"`
   514  			Name string `json:"name"`
   515  		}{
   516  			ID:   testId,
   517  			Name: testName,
   518  		}
   519  
   520  		respBody, err := json.Marshal(&UpdateVolumeTypeResults{VolumeType: resp})
   521  		c.Assert(err, gc.IsNil)
   522  
   523  		w.(*responseWriter).Response.StatusCode = 200
   524  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewBuffer(respBody))
   525  	})
   526  
   527  	resp, err := s.client.UpdateVolumeType(testId, "test-volume-type")
   528  	c.Assert(numCalls, gc.Equals, 1)
   529  	c.Assert(err, gc.IsNil)
   530  
   531  	c.Check(resp.VolumeType.Name, gc.Equals, testName)
   532  	c.Check(resp.VolumeType.ID, gc.Equals, testId)
   533  }
   534  
   535  func (s *CinderTestSuite) TestUpdateVolumeTypeExtraSpecs(c *gc.C) {
   536  
   537  	const (
   538  		testType  = "test-type"
   539  		testSpecs = "test-xtra-specs"
   540  	)
   541  
   542  	numCalls := 0
   543  	s.HandleFunc("/v2/"+testId+"/types/"+testId, func(w http.ResponseWriter, req *http.Request) {
   544  		numCalls++
   545  
   546  		reqBody, err := ioutil.ReadAll(req.Body)
   547  		c.Assert(err, gc.IsNil)
   548  
   549  		var receivedReq UpdateVolumeTypeExtraSpecsParams
   550  		err = json.Unmarshal(reqBody, &receivedReq)
   551  		c.Assert(err, gc.IsNil)
   552  		c.Check(receivedReq.ExtraSpecs, gc.Equals, testSpecs)
   553  		c.Check(receivedReq.VolumeType, gc.Equals, testType)
   554  
   555  		resp := struct {
   556  			ExtraSpecs struct {
   557  				Capabilities string `json:"capabilities"`
   558  			} `json:"extra_specs"`
   559  			ID   string `json:"id"`
   560  			Name string `json:"name"`
   561  		}{
   562  			ID:   testId,
   563  			Name: testName,
   564  			ExtraSpecs: struct {
   565  				Capabilities string `json:"capabilities"`
   566  			}{
   567  				Capabilities: testSpecs,
   568  			},
   569  		}
   570  
   571  		respBody, err := json.Marshal(&UpdateVolumeTypeResults{VolumeType: resp})
   572  		c.Assert(err, gc.IsNil)
   573  
   574  		w.(*responseWriter).Response.StatusCode = 200
   575  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewBuffer(respBody))
   576  	})
   577  
   578  	resp, err := s.client.UpdateVolumeTypeExtraSpecs(testId, testType, testSpecs)
   579  	c.Assert(numCalls, gc.Equals, 1)
   580  	c.Assert(err, gc.IsNil)
   581  
   582  	c.Check(resp.VolumeType.ExtraSpecs.Capabilities, gc.Equals, testSpecs)
   583  	c.Check(resp.VolumeType.ID, gc.Equals, testId)
   584  	c.Check(resp.VolumeType.Name, gc.Equals, testName)
   585  }
   586  
   587  func (s *CinderTestSuite) TestGetVolumesDetail(c *gc.C) {
   588  
   589  	numCalls := 0
   590  	s.HandleFunc("/v2/"+testId+"/volumes/", func(w http.ResponseWriter, req *http.Request) {
   591  		numCalls++
   592  
   593  		resp := []Volume{{
   594  			AvailabilityZone:            "test-availability-zone",
   595  			CreatedAt:                   testTime,
   596  			Description:                 testDescr,
   597  			ID:                          testId,
   598  			Name:                        testName,
   599  			Os_Vol_Host_Attr_Host:       "test-host",
   600  			Os_Vol_Tenant_Attr_TenantID: testId,
   601  			Size:                        1,
   602  			SnapshotID:                  testId,
   603  			SourceVolid:                 testId,
   604  			Status:                      testStatus,
   605  			VolumeType:                  "test-volume-type",
   606  		}}
   607  
   608  		respBody, err := json.Marshal(&GetVolumesDetailResults{Volumes: resp})
   609  		c.Assert(err, gc.IsNil)
   610  
   611  		w.(*responseWriter).Response.StatusCode = 200
   612  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewBuffer(respBody))
   613  	})
   614  
   615  	resp, err := s.client.GetVolumesDetail()
   616  	c.Assert(numCalls, gc.Equals, 1)
   617  	c.Assert(err, gc.IsNil)
   618  	c.Assert(resp.Volumes, gc.HasLen, 1)
   619  
   620  	volume := resp.Volumes[0]
   621  
   622  	c.Check(volume.AvailabilityZone, gc.Equals, "test-availability-zone")
   623  	c.Check(volume.CreatedAt, gc.Equals, testTime)
   624  	c.Check(volume.Description, gc.Equals, testDescr)
   625  	c.Check(volume.ID, gc.Equals, testId)
   626  	c.Check(volume.Name, gc.Equals, testName)
   627  	c.Check(volume.Os_Vol_Host_Attr_Host, gc.Equals, "test-host")
   628  	c.Check(volume.Os_Vol_Tenant_Attr_TenantID, gc.Equals, testId)
   629  	c.Check(volume.Size, gc.Equals, 1)
   630  	c.Check(volume.SnapshotID, gc.Equals, testId)
   631  	c.Check(volume.SourceVolid, gc.Equals, testId)
   632  	c.Check(volume.Status, gc.Equals, testStatus)
   633  	c.Check(volume.VolumeType, gc.Equals, "test-volume-type")
   634  }
   635  
   636  func (s *CinderTestSuite) TestGetVolumesSimple(c *gc.C) {
   637  
   638  	numCalls := 0
   639  	s.HandleFunc("/v2/"+testId+"/volumes", func(w http.ResponseWriter, req *http.Request) {
   640  		numCalls++
   641  
   642  		resp := []Volume{{
   643  			ID:   testId,
   644  			Name: testName,
   645  		}}
   646  
   647  		respBody, err := json.Marshal(&GetVolumesSimpleResults{Volumes: resp})
   648  		c.Assert(err, gc.IsNil)
   649  
   650  		w.(*responseWriter).Response.StatusCode = 200
   651  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewBuffer(respBody))
   652  	})
   653  
   654  	resp, err := s.client.GetVolumesSimple()
   655  	c.Assert(numCalls, gc.Equals, 1)
   656  	c.Assert(err, gc.IsNil)
   657  	c.Assert(resp.Volumes, gc.HasLen, 1)
   658  
   659  	volume := resp.Volumes[0]
   660  
   661  	c.Check(volume.ID, gc.Equals, testId)
   662  	c.Check(volume.Name, gc.Equals, testName)
   663  }
   664  
   665  func (s *CinderTestSuite) TestCreateVolumeType(c *gc.C) {
   666  	origReq := CreateVolumeTypeVolumeTypeParams{
   667  		Name: "test-volume-type",
   668  		ExtraSpecs: CreateVolumeTypeVolumeTypeExtraSpecsParams{
   669  			Capabilities: "gpu",
   670  		},
   671  	}
   672  
   673  	numCalls := 0
   674  	s.HandleFunc("/v2/"+testId+"/types", func(w http.ResponseWriter, req *http.Request) {
   675  		numCalls++
   676  
   677  		reqBody, err := ioutil.ReadAll(req.Body)
   678  		c.Assert(err, gc.IsNil)
   679  
   680  		var receivedReq CreateVolumeTypeParams
   681  		err = json.Unmarshal(reqBody, &receivedReq)
   682  		c.Assert(err, gc.IsNil)
   683  
   684  		c.Check(receivedReq.VolumeType, gc.DeepEquals, origReq)
   685  
   686  		resp := struct {
   687  			ExtraSpecs struct {
   688  				Capabilities string `json:"capabilities"`
   689  			} `json:"extra_specs"`
   690  			ID   string `json:"id"`
   691  			Name string `json:"name"`
   692  		}{
   693  			ID: "test-id",
   694  			ExtraSpecs: struct {
   695  				Capabilities string `json:"capabilities"`
   696  			}{
   697  				Capabilities: receivedReq.VolumeType.ExtraSpecs.Capabilities,
   698  			},
   699  			Name: receivedReq.VolumeType.Name,
   700  		}
   701  
   702  		respBody, err := json.Marshal(&CreateVolumeTypeResults{VolumeType: resp})
   703  		c.Assert(err, gc.IsNil)
   704  
   705  		w.(*responseWriter).StatusCode = 200
   706  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewBuffer(respBody))
   707  	})
   708  
   709  	resp, err := s.client.CreateVolumeType(origReq)
   710  	c.Assert(err, gc.IsNil)
   711  	c.Assert(resp.VolumeType.ID, gc.Not(gc.HasLen), 0)
   712  
   713  	c.Check(resp.VolumeType.ExtraSpecs.Capabilities, gc.Equals, origReq.ExtraSpecs.Capabilities)
   714  	c.Check(resp.VolumeType.Name, gc.Equals, origReq.Name)
   715  }
   716  
   717  func (s *CinderTestSuite) TestDeleteVolumeType(c *gc.C) {
   718  
   719  	numCalls := 0
   720  	s.HandleFunc("/v2/"+testId+"/types/", func(w http.ResponseWriter, req *http.Request) {
   721  		numCalls++
   722  
   723  		w.(*responseWriter).StatusCode = 202
   724  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewBuffer([]byte{}))
   725  	})
   726  
   727  	err := s.client.DeleteVolumeType(testId)
   728  	c.Assert(numCalls, gc.Equals, 1)
   729  	c.Assert(err, gc.IsNil)
   730  }
   731  
   732  func (s *CinderTestSuite) TestGetVolumeType(c *gc.C) {
   733  
   734  	numCalls := 0
   735  	s.HandleFunc("/v2/"+testId+"/types/"+testId, func(w http.ResponseWriter, req *http.Request) {
   736  		numCalls++
   737  
   738  		resp := struct {
   739  			ExtraSpecs struct {
   740  				Capabilities string `json:"capabilities"`
   741  			} `json:"extra_specs"`
   742  			ID   string `json:"id"`
   743  			Name string `json:"name"`
   744  		}{
   745  			ID: testId,
   746  			ExtraSpecs: struct {
   747  				Capabilities string `json:"capabilities"`
   748  			}{
   749  				Capabilities: "test-capability",
   750  			},
   751  			Name: testName,
   752  		}
   753  
   754  		respBody, err := json.Marshal(&GetVolumeTypeResults{VolumeType: resp})
   755  		c.Assert(err, gc.IsNil)
   756  
   757  		w.(*responseWriter).StatusCode = 200
   758  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewBuffer(respBody))
   759  	})
   760  
   761  	resp, err := s.client.GetVolumeType(testId)
   762  	c.Assert(numCalls, gc.Equals, 1)
   763  	c.Assert(err, gc.IsNil)
   764  	c.Assert(resp.VolumeType.ID, gc.Not(gc.HasLen), 0)
   765  
   766  	c.Check(resp.VolumeType.ExtraSpecs.Capabilities, gc.Equals, "test-capability")
   767  	c.Check(resp.VolumeType.Name, gc.Equals, testName)
   768  }
   769  
   770  func (s *CinderTestSuite) TestGetVolumeTypes(c *gc.C) {
   771  
   772  	numCalls := 0
   773  	s.HandleFunc("/v2/"+testId+"/types", func(w http.ResponseWriter, req *http.Request) {
   774  		numCalls++
   775  
   776  		resp := []VolumeType{{
   777  			ID: testId,
   778  			ExtraSpecs: struct {
   779  				Capabilities string `json:"capabilities"`
   780  			}{
   781  				Capabilities: "test-capability",
   782  			},
   783  			Name: testName,
   784  		}}
   785  
   786  		respBody, err := json.Marshal(&GetVolumeTypesResults{VolumeTypes: resp})
   787  		c.Assert(err, gc.IsNil)
   788  
   789  		w.(*responseWriter).StatusCode = 200
   790  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewBuffer(respBody))
   791  	})
   792  
   793  	resp, err := s.client.GetVolumeTypes()
   794  	c.Assert(numCalls, gc.Equals, 1)
   795  	c.Assert(err, gc.IsNil)
   796  	c.Assert(resp.VolumeTypes, gc.HasLen, 1)
   797  
   798  	volumeType := resp.VolumeTypes[0]
   799  
   800  	c.Check(volumeType.ExtraSpecs.Capabilities, gc.Equals, "test-capability")
   801  	c.Check(volumeType.Name, gc.Equals, testName)
   802  	c.Check(volumeType.ID, gc.Equals, testId)
   803  }
   804  
   805  func (s *CinderTestSuite) TestGetAvailabilityZones(c *gc.C) {
   806  
   807  	numCalls := 0
   808  	s.HandleFunc("/v2/"+testId+"/os-availability-zone", func(w http.ResponseWriter, req *http.Request) {
   809  		numCalls++
   810  
   811  		resp := []AvailabilityZone{{
   812  			Name: "zone-1",
   813  			State: AvailabilityZoneState{
   814  				Available: true,
   815  			},
   816  		}}
   817  
   818  		respBody, err := json.Marshal(&GetAvailabilityZonesResults{AvailabilityZoneInfo: resp})
   819  		c.Assert(err, gc.IsNil)
   820  
   821  		w.(*responseWriter).StatusCode = 200
   822  		w.(*responseWriter).Body = ioutil.NopCloser(bytes.NewBuffer(respBody))
   823  	})
   824  
   825  	zones, err := s.client.ListVolumeAvailabilityZones()
   826  	c.Assert(numCalls, gc.Equals, 1)
   827  	c.Assert(err, gc.IsNil)
   828  	c.Assert(zones, gc.HasLen, 1)
   829  
   830  	zone := zones[0]
   831  
   832  	c.Check(zone.Name, gc.Equals, "zone-1")
   833  	c.Check(zone.State.Available, gc.Equals, true)
   834  }
   835  
   836  func (s *CinderTestSuite) localDo(req *http.Request) (*http.Response, error) {
   837  	handler, matchedPattern := s.Handler(req)
   838  	if matchedPattern == "" {
   839  		return nil, fmt.Errorf("no test handler registered for %s", req.URL.Path)
   840  	}
   841  
   842  	var response http.Response
   843  	handler.ServeHTTP(&responseWriter{&response}, req)
   844  
   845  	return &response, nil
   846  }
   847  
   848  type responseWriter struct {
   849  	*http.Response
   850  }
   851  
   852  func (w *responseWriter) Header() http.Header {
   853  	return w.Response.Header
   854  }
   855  
   856  func (w *responseWriter) Write(data []byte) (int, error) {
   857  	return len(data), w.Response.Write(bytes.NewBuffer(data))
   858  }
   859  
   860  func (w *responseWriter) WriteHeader(statusCode int) {
   861  	w.Response.StatusCode = statusCode
   862  }