github.com/gophercloud/gophercloud@v1.11.0/openstack/objectstorage/v1/objects/testing/fixtures_test.go (about) 1 package testing 2 3 import ( 4 "crypto/md5" 5 "fmt" 6 "io" 7 "net/http" 8 "testing" 9 "time" 10 11 "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects" 12 th "github.com/gophercloud/gophercloud/testhelper" 13 fake "github.com/gophercloud/gophercloud/testhelper/client" 14 ) 15 16 type handlerOptions struct { 17 path string 18 } 19 20 type option func(*handlerOptions) 21 22 func WithPath(s string) option { 23 return func(h *handlerOptions) { 24 h.path = s 25 } 26 } 27 28 // HandleDownloadObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 29 // responds with a `Download` response. 30 func HandleDownloadObjectSuccessfully(t *testing.T, options ...option) { 31 ho := handlerOptions{ 32 path: "/testContainer/testObject", 33 } 34 for _, apply := range options { 35 apply(&ho) 36 } 37 38 th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) { 39 date := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) 40 th.TestMethod(t, r, "GET") 41 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 42 th.TestHeader(t, r, "Accept", "application/json") 43 w.Header().Set("Date", date.Format(time.RFC1123)) 44 w.Header().Set("X-Static-Large-Object", "True") 45 46 unModifiedSince := r.Header.Get("If-Unmodified-Since") 47 modifiedSince := r.Header.Get("If-Modified-Since") 48 if unModifiedSince != "" { 49 ums, _ := time.Parse(time.RFC1123, unModifiedSince) 50 if ums.Before(date) || ums.Equal(date) { 51 w.WriteHeader(http.StatusPreconditionFailed) 52 return 53 } 54 } 55 if modifiedSince != "" { 56 ms, _ := time.Parse(time.RFC1123, modifiedSince) 57 if ms.After(date) { 58 w.WriteHeader(http.StatusNotModified) 59 return 60 } 61 } 62 w.Header().Set("Last-Modified", date.Format(time.RFC1123)) 63 w.WriteHeader(http.StatusOK) 64 fmt.Fprintf(w, "Successful download with Gophercloud") 65 }) 66 } 67 68 // ExpectedListInfo is the result expected from a call to `List` when full 69 // info is requested. 70 var ExpectedListInfo = []objects.Object{ 71 { 72 Hash: "451e372e48e0f6b1114fa0724aa79fa1", 73 LastModified: time.Date(2016, time.August, 17, 22, 11, 58, 602650000, time.UTC), 74 Bytes: 14, 75 Name: "goodbye", 76 ContentType: "application/octet-stream", 77 }, 78 { 79 Hash: "451e372e48e0f6b1114fa0724aa79fa1", 80 LastModified: time.Date(2016, time.August, 17, 22, 11, 58, 602650000, time.UTC), 81 Bytes: 14, 82 Name: "hello", 83 ContentType: "application/octet-stream", 84 }, 85 } 86 87 // ExpectedListSubdir is the result expected from a call to `List` when full 88 // info is requested. 89 var ExpectedListSubdir = []objects.Object{ 90 { 91 Subdir: "directory/", 92 }, 93 } 94 95 // ExpectedListNames is the result expected from a call to `List` when just 96 // object names are requested. 97 var ExpectedListNames = []string{"hello", "goodbye"} 98 99 // HandleListObjectsInfoSuccessfully creates an HTTP handler at `/testContainer` on the test handler mux that 100 // responds with a `List` response when full info is requested. 101 func HandleListObjectsInfoSuccessfully(t *testing.T, options ...option) { 102 ho := handlerOptions{ 103 path: "/testContainer", 104 } 105 for _, apply := range options { 106 apply(&ho) 107 } 108 109 th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) { 110 th.TestMethod(t, r, "GET") 111 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 112 th.TestHeader(t, r, "Accept", "application/json") 113 114 w.Header().Set("Content-Type", "application/json") 115 r.ParseForm() 116 marker := r.Form.Get("marker") 117 switch marker { 118 case "": 119 fmt.Fprintf(w, `[ 120 { 121 "hash": "451e372e48e0f6b1114fa0724aa79fa1", 122 "last_modified": "2016-08-17T22:11:58.602650", 123 "bytes": 14, 124 "name": "goodbye", 125 "content_type": "application/octet-stream" 126 }, 127 { 128 "hash": "451e372e48e0f6b1114fa0724aa79fa1", 129 "last_modified": "2016-08-17T22:11:58.602650", 130 "bytes": 14, 131 "name": "hello", 132 "content_type": "application/octet-stream" 133 } 134 ]`) 135 case "hello": 136 fmt.Fprintf(w, `[]`) 137 default: 138 t.Fatalf("Unexpected marker: [%s]", marker) 139 } 140 }) 141 } 142 143 // HandleListSubdirSuccessfully creates an HTTP handler at `/testContainer` on the test handler mux that 144 // responds with a `List` response when full info is requested. 145 func HandleListSubdirSuccessfully(t *testing.T) { 146 th.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) { 147 th.TestMethod(t, r, "GET") 148 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 149 th.TestHeader(t, r, "Accept", "application/json") 150 151 w.Header().Set("Content-Type", "application/json") 152 r.ParseForm() 153 marker := r.Form.Get("marker") 154 switch marker { 155 case "": 156 fmt.Fprintf(w, `[ 157 { 158 "subdir": "directory/" 159 } 160 ]`) 161 case "directory/": 162 fmt.Fprintf(w, `[]`) 163 default: 164 t.Fatalf("Unexpected marker: [%s]", marker) 165 } 166 }) 167 } 168 169 // HandleListObjectNamesSuccessfully creates an HTTP handler at `/testContainer` on the test handler mux that 170 // responds with a `List` response when only object names are requested. 171 func HandleListObjectNamesSuccessfully(t *testing.T) { 172 th.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) { 173 th.TestMethod(t, r, "GET") 174 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 175 th.TestHeader(t, r, "Accept", "text/plain") 176 177 w.Header().Set("Content-Type", "text/plain") 178 r.ParseForm() 179 marker := r.Form.Get("marker") 180 switch marker { 181 case "": 182 fmt.Fprintf(w, "hello\ngoodbye\n") 183 case "goodbye": 184 fmt.Fprintf(w, "") 185 default: 186 t.Fatalf("Unexpected marker: [%s]", marker) 187 } 188 }) 189 } 190 191 // HandleListZeroObjectNames204 creates an HTTP handler at `/testContainer` on the test handler mux that 192 // responds with "204 No Content" when object names are requested. This happens on some, but not all, objectstorage 193 // instances. This case is peculiar in that the server sends no `content-type` header. 194 func HandleListZeroObjectNames204(t *testing.T) { 195 th.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) { 196 th.TestMethod(t, r, "GET") 197 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 198 th.TestHeader(t, r, "Accept", "text/plain") 199 200 w.WriteHeader(http.StatusNoContent) 201 }) 202 } 203 204 // HandleCreateTextObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux 205 // that responds with a `Create` response. A Content-Type of "text/plain" is expected. 206 func HandleCreateTextObjectSuccessfully(t *testing.T, content string, options ...option) { 207 ho := handlerOptions{ 208 path: "/testContainer/testObject", 209 } 210 for _, apply := range options { 211 apply(&ho) 212 } 213 214 th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) { 215 th.TestMethod(t, r, "PUT") 216 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 217 th.TestHeader(t, r, "Content-Type", "text/plain") 218 th.TestHeader(t, r, "Accept", "application/json") 219 th.TestBody(t, r, `Did gyre and gimble in the wabe`) 220 221 hash := md5.New() 222 io.WriteString(hash, content) 223 localChecksum := hash.Sum(nil) 224 225 w.Header().Set("ETag", fmt.Sprintf("%x", localChecksum)) 226 w.WriteHeader(http.StatusCreated) 227 }) 228 } 229 230 // HandleCreateTextWithCacheControlSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler 231 // mux that responds with a `Create` response. A Cache-Control of `max-age="3600", public` is expected. 232 func HandleCreateTextWithCacheControlSuccessfully(t *testing.T, content string) { 233 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 234 th.TestMethod(t, r, "PUT") 235 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 236 th.TestHeader(t, r, "Cache-Control", `max-age="3600", public`) 237 th.TestHeader(t, r, "Accept", "application/json") 238 th.TestBody(t, r, `All mimsy were the borogoves`) 239 240 hash := md5.New() 241 io.WriteString(hash, content) 242 localChecksum := hash.Sum(nil) 243 244 w.Header().Set("ETag", fmt.Sprintf("%x", localChecksum)) 245 w.WriteHeader(http.StatusCreated) 246 }) 247 } 248 249 // HandleCreateTypelessObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler 250 // mux that responds with a `Create` response. No Content-Type header may be present in the request, so that server- 251 // side content-type detection will be triggered properly. 252 func HandleCreateTypelessObjectSuccessfully(t *testing.T, content string) { 253 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 254 th.TestMethod(t, r, "PUT") 255 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 256 th.TestHeader(t, r, "Accept", "application/json") 257 th.TestBody(t, r, `The sky was the color of television, tuned to a dead channel.`) 258 259 if contentType, present := r.Header["Content-Type"]; present { 260 t.Errorf("Expected Content-Type header to be omitted, but was %#v", contentType) 261 } 262 263 hash := md5.New() 264 io.WriteString(hash, content) 265 localChecksum := hash.Sum(nil) 266 267 w.Header().Set("ETag", fmt.Sprintf("%x", localChecksum)) 268 w.WriteHeader(http.StatusCreated) 269 }) 270 } 271 272 // HandleCopyObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 273 // responds with a `Copy` response. 274 func HandleCopyObjectSuccessfully(t *testing.T) { 275 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 276 th.TestMethod(t, r, "COPY") 277 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 278 th.TestHeader(t, r, "Accept", "application/json") 279 th.TestHeader(t, r, "Destination", "/newTestContainer/newTestObject") 280 w.WriteHeader(http.StatusCreated) 281 }) 282 } 283 284 // HandleCopyObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 285 // responds with a `Copy` response. 286 func HandleCopyObjectVersionSuccessfully(t *testing.T) { 287 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 288 th.TestMethod(t, r, "COPY") 289 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 290 th.TestHeader(t, r, "Accept", "application/json") 291 th.TestHeader(t, r, "Destination", "/newTestContainer/newTestObject") 292 th.TestFormValues(t, r, map[string]string{"version-id": "123456788"}) 293 w.Header().Set("X-Object-Version-Id", "123456789") 294 w.WriteHeader(http.StatusCreated) 295 }) 296 } 297 298 // HandleDeleteObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 299 // responds with a `Delete` response. 300 func HandleDeleteObjectSuccessfully(t *testing.T, options ...option) { 301 ho := handlerOptions{ 302 path: "/testContainer/testObject", 303 } 304 for _, apply := range options { 305 apply(&ho) 306 } 307 308 th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) { 309 th.TestMethod(t, r, "DELETE") 310 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 311 th.TestHeader(t, r, "Accept", "application/json") 312 w.WriteHeader(http.StatusNoContent) 313 }) 314 } 315 316 const bulkDeleteResponse = ` 317 { 318 "Response Status": "foo", 319 "Response Body": "bar", 320 "Errors": [], 321 "Number Deleted": 2, 322 "Number Not Found": 0 323 } 324 ` 325 326 // HandleBulkDeleteSuccessfully creates an HTTP handler at `/` on the test 327 // handler mux that responds with a `BulkDelete` response. 328 func HandleBulkDeleteSuccessfully(t *testing.T) { 329 th.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 330 th.TestMethod(t, r, "POST") 331 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 332 th.TestHeader(t, r, "Accept", "application/json") 333 th.TestHeader(t, r, "Content-Type", "text/plain") 334 th.TestFormValues(t, r, map[string]string{ 335 "bulk-delete": "true", 336 }) 337 th.TestBody(t, r, "testContainer/testObject1\ntestContainer/testObject2\n") 338 339 w.Header().Set("Content-Type", "application/json") 340 w.WriteHeader(http.StatusOK) 341 fmt.Fprintf(w, bulkDeleteResponse) 342 }) 343 } 344 345 // HandleUpdateObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 346 // responds with a `Update` response. 347 func HandleUpdateObjectSuccessfully(t *testing.T, options ...option) { 348 ho := handlerOptions{ 349 path: "/testContainer/testObject", 350 } 351 for _, apply := range options { 352 apply(&ho) 353 } 354 355 th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) { 356 th.TestMethod(t, r, "POST") 357 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 358 th.TestHeader(t, r, "Accept", "application/json") 359 th.TestHeader(t, r, "X-Object-Meta-Gophercloud-Test", "objects") 360 th.TestHeader(t, r, "X-Remove-Object-Meta-Gophercloud-Test-Remove", "remove") 361 th.TestHeader(t, r, "Content-Disposition", "") 362 th.TestHeader(t, r, "Content-Encoding", "") 363 th.TestHeader(t, r, "Content-Type", "") 364 th.TestHeaderUnset(t, r, "X-Delete-After") 365 th.TestHeader(t, r, "X-Delete-At", "0") 366 th.TestHeader(t, r, "X-Detect-Content-Type", "false") 367 w.WriteHeader(http.StatusAccepted) 368 }) 369 } 370 371 // HandleGetObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 372 // responds with a `Get` response. 373 func HandleGetObjectSuccessfully(t *testing.T, options ...option) { 374 ho := handlerOptions{ 375 path: "/testContainer/testObject", 376 } 377 for _, apply := range options { 378 apply(&ho) 379 } 380 381 th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) { 382 th.TestMethod(t, r, "HEAD") 383 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 384 th.TestHeader(t, r, "Accept", "application/json") 385 w.Header().Add("X-Object-Meta-Gophercloud-Test", "objects") 386 w.Header().Add("X-Static-Large-Object", "true") 387 w.WriteHeader(http.StatusNoContent) 388 }) 389 }