1package testing 2 3import ( 4 "bytes" 5 "crypto/md5" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "strings" 10 "testing" 11 "time" 12 13 "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects" 14 "github.com/gophercloud/gophercloud/pagination" 15 th "github.com/gophercloud/gophercloud/testhelper" 16 fake "github.com/gophercloud/gophercloud/testhelper/client" 17) 18 19var ( 20 loc, _ = time.LoadLocation("GMT") 21) 22 23func TestDownloadReader(t *testing.T) { 24 th.SetupHTTP() 25 defer th.TeardownHTTP() 26 HandleDownloadObjectSuccessfully(t) 27 28 response := objects.Download(fake.ServiceClient(), "testContainer", "testObject", nil) 29 defer response.Body.Close() 30 31 // Check reader 32 buf := bytes.NewBuffer(make([]byte, 0)) 33 io.CopyN(buf, response.Body, 10) 34 th.CheckEquals(t, "Successful", string(buf.Bytes())) 35} 36 37func TestDownloadExtraction(t *testing.T) { 38 th.SetupHTTP() 39 defer th.TeardownHTTP() 40 HandleDownloadObjectSuccessfully(t) 41 42 response := objects.Download(fake.ServiceClient(), "testContainer", "testObject", nil) 43 44 // Check []byte extraction 45 bytes, err := response.ExtractContent() 46 th.AssertNoErr(t, err) 47 th.CheckEquals(t, "Successful download with Gophercloud", string(bytes)) 48 49 expected := &objects.DownloadHeader{ 50 ContentLength: 36, 51 ContentType: "text/plain; charset=utf-8", 52 Date: time.Date(2009, time.November, 10, 23, 0, 0, 0, loc), 53 StaticLargeObject: true, 54 } 55 actual, err := response.Extract() 56 th.AssertNoErr(t, err) 57 th.CheckDeepEquals(t, expected, actual) 58} 59 60func TestListObjectInfo(t *testing.T) { 61 th.SetupHTTP() 62 defer th.TeardownHTTP() 63 HandleListObjectsInfoSuccessfully(t) 64 65 count := 0 66 options := &objects.ListOpts{Full: true} 67 err := objects.List(fake.ServiceClient(), "testContainer", options).EachPage(func(page pagination.Page) (bool, error) { 68 count++ 69 actual, err := objects.ExtractInfo(page) 70 th.AssertNoErr(t, err) 71 72 th.CheckDeepEquals(t, ExpectedListInfo, actual) 73 74 return true, nil 75 }) 76 th.AssertNoErr(t, err) 77 th.CheckEquals(t, count, 1) 78} 79 80func TestListObjectSubdir(t *testing.T) { 81 th.SetupHTTP() 82 defer th.TeardownHTTP() 83 HandleListSubdirSuccessfully(t) 84 85 count := 0 86 options := &objects.ListOpts{Full: true, Prefix: "", Delimiter: "/"} 87 err := objects.List(fake.ServiceClient(), "testContainer", options).EachPage(func(page pagination.Page) (bool, error) { 88 count++ 89 actual, err := objects.ExtractInfo(page) 90 th.AssertNoErr(t, err) 91 92 th.CheckDeepEquals(t, ExpectedListSubdir, actual) 93 94 return true, nil 95 }) 96 th.AssertNoErr(t, err) 97 th.CheckEquals(t, count, 1) 98} 99 100func TestListObjectNames(t *testing.T) { 101 th.SetupHTTP() 102 defer th.TeardownHTTP() 103 HandleListObjectNamesSuccessfully(t) 104 105 // Check without delimiter. 106 count := 0 107 options := &objects.ListOpts{Full: false} 108 err := objects.List(fake.ServiceClient(), "testContainer", options).EachPage(func(page pagination.Page) (bool, error) { 109 count++ 110 actual, err := objects.ExtractNames(page) 111 if err != nil { 112 t.Errorf("Failed to extract container names: %v", err) 113 return false, err 114 } 115 116 th.CheckDeepEquals(t, ExpectedListNames, actual) 117 118 return true, nil 119 }) 120 th.AssertNoErr(t, err) 121 th.CheckEquals(t, count, 1) 122 123 // Check with delimiter. 124 count = 0 125 options = &objects.ListOpts{Full: false, Delimiter: "/"} 126 err = objects.List(fake.ServiceClient(), "testContainer", options).EachPage(func(page pagination.Page) (bool, error) { 127 count++ 128 actual, err := objects.ExtractNames(page) 129 if err != nil { 130 t.Errorf("Failed to extract container names: %v", err) 131 return false, err 132 } 133 134 th.CheckDeepEquals(t, ExpectedListNames, actual) 135 136 return true, nil 137 }) 138 th.AssertNoErr(t, err) 139 th.CheckEquals(t, count, 1) 140} 141 142func TestCreateObject(t *testing.T) { 143 th.SetupHTTP() 144 defer th.TeardownHTTP() 145 146 content := "Did gyre and gimble in the wabe" 147 148 HandleCreateTextObjectSuccessfully(t, content) 149 150 options := &objects.CreateOpts{ContentType: "text/plain", Content: strings.NewReader(content)} 151 res := objects.Create(fake.ServiceClient(), "testContainer", "testObject", options) 152 th.AssertNoErr(t, res.Err) 153} 154 155func TestCreateObjectWithCacheControl(t *testing.T) { 156 th.SetupHTTP() 157 defer th.TeardownHTTP() 158 159 content := "All mimsy were the borogoves" 160 161 HandleCreateTextWithCacheControlSuccessfully(t, content) 162 163 options := &objects.CreateOpts{ 164 CacheControl: `max-age="3600", public`, 165 Content: strings.NewReader(content), 166 } 167 res := objects.Create(fake.ServiceClient(), "testContainer", "testObject", options) 168 th.AssertNoErr(t, res.Err) 169} 170 171func TestCreateObjectWithoutContentType(t *testing.T) { 172 th.SetupHTTP() 173 defer th.TeardownHTTP() 174 175 content := "The sky was the color of television, tuned to a dead channel." 176 177 HandleCreateTypelessObjectSuccessfully(t, content) 178 179 res := objects.Create(fake.ServiceClient(), "testContainer", "testObject", &objects.CreateOpts{Content: strings.NewReader(content)}) 180 th.AssertNoErr(t, res.Err) 181} 182 183/* 184func TestErrorIsRaisedForChecksumMismatch(t *testing.T) { 185 th.SetupHTTP() 186 defer th.TeardownHTTP() 187 188 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 189 w.Header().Set("ETag", "acbd18db4cc2f85cedef654fccc4a4d8") 190 w.WriteHeader(http.StatusCreated) 191 }) 192 193 content := strings.NewReader("The sky was the color of television, tuned to a dead channel.") 194 res := Create(fake.ServiceClient(), "testContainer", "testObject", &CreateOpts{Content: content}) 195 196 err := fmt.Errorf("Local checksum does not match API ETag header") 197 th.AssertDeepEquals(t, err, res.Err) 198} 199*/ 200 201func TestCopyObject(t *testing.T) { 202 th.SetupHTTP() 203 defer th.TeardownHTTP() 204 HandleCopyObjectSuccessfully(t) 205 206 options := &objects.CopyOpts{Destination: "/newTestContainer/newTestObject"} 207 res := objects.Copy(fake.ServiceClient(), "testContainer", "testObject", options) 208 th.AssertNoErr(t, res.Err) 209} 210 211func TestDeleteObject(t *testing.T) { 212 th.SetupHTTP() 213 defer th.TeardownHTTP() 214 HandleDeleteObjectSuccessfully(t) 215 216 res := objects.Delete(fake.ServiceClient(), "testContainer", "testObject", nil) 217 th.AssertNoErr(t, res.Err) 218} 219 220func TestUpateObjectMetadata(t *testing.T) { 221 th.SetupHTTP() 222 defer th.TeardownHTTP() 223 HandleUpdateObjectSuccessfully(t) 224 225 options := &objects.UpdateOpts{Metadata: map[string]string{"Gophercloud-Test": "objects"}} 226 res := objects.Update(fake.ServiceClient(), "testContainer", "testObject", options) 227 th.AssertNoErr(t, res.Err) 228} 229 230func TestGetObject(t *testing.T) { 231 th.SetupHTTP() 232 defer th.TeardownHTTP() 233 HandleGetObjectSuccessfully(t) 234 235 expected := map[string]string{"Gophercloud-Test": "objects"} 236 actual, err := objects.Get(fake.ServiceClient(), "testContainer", "testObject", nil).ExtractMetadata() 237 th.AssertNoErr(t, err) 238 th.CheckDeepEquals(t, expected, actual) 239 240 getOpts := objects.GetOpts{ 241 Newest: true, 242 } 243 actualHeaders, err := objects.Get(fake.ServiceClient(), "testContainer", "testObject", getOpts).Extract() 244 th.AssertNoErr(t, err) 245 th.AssertEquals(t, actualHeaders.StaticLargeObject, true) 246} 247 248func TestETag(t *testing.T) { 249 content := "some example object" 250 createOpts := objects.CreateOpts{ 251 Content: strings.NewReader(content), 252 NoETag: true, 253 } 254 255 _, headers, _, err := createOpts.ToObjectCreateParams() 256 th.AssertNoErr(t, err) 257 _, ok := headers["ETag"] 258 th.AssertEquals(t, ok, false) 259 260 hash := md5.New() 261 io.WriteString(hash, content) 262 localChecksum := fmt.Sprintf("%x", hash.Sum(nil)) 263 264 createOpts = objects.CreateOpts{ 265 Content: strings.NewReader(content), 266 ETag: localChecksum, 267 } 268 269 _, headers, _, err = createOpts.ToObjectCreateParams() 270 th.AssertNoErr(t, err) 271 th.AssertEquals(t, headers["ETag"], localChecksum) 272} 273 274func TestObjectCreateParamsWithoutSeek(t *testing.T) { 275 content := "I do not implement Seek()" 276 buf := bytes.NewBuffer([]byte(content)) 277 278 createOpts := objects.CreateOpts{Content: buf} 279 reader, headers, _, err := createOpts.ToObjectCreateParams() 280 281 th.AssertNoErr(t, err) 282 283 _, ok := reader.(io.ReadSeeker) 284 th.AssertEquals(t, ok, true) 285 286 c, err := ioutil.ReadAll(reader) 287 th.AssertNoErr(t, err) 288 289 th.AssertEquals(t, content, string(c)) 290 291 _, ok = headers["ETag"] 292 th.AssertEquals(t, true, ok) 293} 294 295func TestObjectCreateParamsWithSeek(t *testing.T) { 296 content := "I implement Seek()" 297 createOpts := objects.CreateOpts{Content: strings.NewReader(content)} 298 reader, headers, _, err := createOpts.ToObjectCreateParams() 299 300 th.AssertNoErr(t, err) 301 302 _, ok := reader.(io.ReadSeeker) 303 th.AssertEquals(t, ok, true) 304 305 c, err := ioutil.ReadAll(reader) 306 th.AssertNoErr(t, err) 307 308 th.AssertEquals(t, content, string(c)) 309 310 _, ok = headers["ETag"] 311 th.AssertEquals(t, true, ok) 312} 313