github.com/vnpaycloud-console/gophercloud/v2@v2.0.5/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/vnpaycloud-console/gophercloud/v2/openstack/objectstorage/v1/objects" 12 th "github.com/vnpaycloud-console/gophercloud/v2/testhelper" 13 fake "github.com/vnpaycloud-console/gophercloud/v2/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.Fprint(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{"goodbye", "hello"} 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 if err := r.ParseForm(); err != nil { 116 t.Errorf("Failed to parse request form %v", err) 117 } 118 marker := r.Form.Get("marker") 119 switch marker { 120 case "": 121 fmt.Fprint(w, `[ 122 { 123 "hash": "451e372e48e0f6b1114fa0724aa79fa1", 124 "last_modified": "2016-08-17T22:11:58.602650", 125 "bytes": 14, 126 "name": "goodbye", 127 "content_type": "application/octet-stream" 128 }, 129 { 130 "hash": "451e372e48e0f6b1114fa0724aa79fa1", 131 "last_modified": "2016-08-17T22:11:58.602650", 132 "bytes": 14, 133 "name": "hello", 134 "content_type": "application/octet-stream" 135 } 136 ]`) 137 case "hello": 138 fmt.Fprint(w, `[]`) 139 default: 140 t.Fatalf("Unexpected marker: [%s]", marker) 141 } 142 }) 143 } 144 145 // HandleListSubdirSuccessfully creates an HTTP handler at `/testContainer` on the test handler mux that 146 // responds with a `List` response when full info is requested. 147 func HandleListSubdirSuccessfully(t *testing.T) { 148 th.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) { 149 th.TestMethod(t, r, "GET") 150 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 151 th.TestHeader(t, r, "Accept", "application/json") 152 153 w.Header().Set("Content-Type", "application/json") 154 if err := r.ParseForm(); err != nil { 155 t.Errorf("Failed to parse request form %v", err) 156 } 157 marker := r.Form.Get("marker") 158 switch marker { 159 case "": 160 fmt.Fprint(w, `[ 161 { 162 "subdir": "directory/" 163 } 164 ]`) 165 case "directory/": 166 fmt.Fprint(w, `[]`) 167 default: 168 t.Fatalf("Unexpected marker: [%s]", marker) 169 } 170 }) 171 } 172 173 // HandleListZeroObjectNames204 creates an HTTP handler at `/testContainer` on the test handler mux that 174 // responds with "204 No Content" when object names are requested. This happens on some, but not all, objectstorage 175 // instances. This case is peculiar in that the server sends no `content-type` header. 176 func HandleListZeroObjectNames204(t *testing.T) { 177 th.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) { 178 th.TestMethod(t, r, "GET") 179 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 180 th.TestHeader(t, r, "Accept", "application/json") 181 182 w.WriteHeader(http.StatusNoContent) 183 }) 184 } 185 186 // HandleCreateTextObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux 187 // that responds with a `Create` response. A Content-Type of "text/plain" is expected. 188 func HandleCreateTextObjectSuccessfully(t *testing.T, content string, options ...option) { 189 ho := handlerOptions{ 190 path: "/testContainer/testObject", 191 } 192 for _, apply := range options { 193 apply(&ho) 194 } 195 196 th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) { 197 th.TestMethod(t, r, "PUT") 198 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 199 th.TestHeader(t, r, "Content-Type", "text/plain") 200 th.TestHeader(t, r, "Accept", "application/json") 201 th.TestBody(t, r, `Did gyre and gimble in the wabe`) 202 203 hash := md5.New() 204 _, err := io.WriteString(hash, content) 205 th.AssertNoErr(t, err) 206 localChecksum := hash.Sum(nil) 207 208 w.Header().Set("ETag", fmt.Sprintf("%x", localChecksum)) 209 w.WriteHeader(http.StatusCreated) 210 }) 211 } 212 213 // HandleCreateTextWithCacheControlSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler 214 // mux that responds with a `Create` response. A Cache-Control of `max-age="3600", public` is expected. 215 func HandleCreateTextWithCacheControlSuccessfully(t *testing.T, content string) { 216 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 217 th.TestMethod(t, r, "PUT") 218 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 219 th.TestHeader(t, r, "Cache-Control", `max-age="3600", public`) 220 th.TestHeader(t, r, "Accept", "application/json") 221 th.TestBody(t, r, `All mimsy were the borogoves`) 222 223 hash := md5.New() 224 _, err := io.WriteString(hash, content) 225 th.AssertNoErr(t, err) 226 localChecksum := hash.Sum(nil) 227 228 w.Header().Set("ETag", fmt.Sprintf("%x", localChecksum)) 229 w.WriteHeader(http.StatusCreated) 230 }) 231 } 232 233 // HandleCreateTypelessObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler 234 // mux that responds with a `Create` response. No Content-Type header may be present in the request, so that server- 235 // side content-type detection will be triggered properly. 236 func HandleCreateTypelessObjectSuccessfully(t *testing.T, content string) { 237 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 238 th.TestMethod(t, r, "PUT") 239 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 240 th.TestHeader(t, r, "Accept", "application/json") 241 th.TestBody(t, r, `The sky was the color of television, tuned to a dead channel.`) 242 243 if contentType, present := r.Header["Content-Type"]; present { 244 t.Errorf("Expected Content-Type header to be omitted, but was %#v", contentType) 245 } 246 247 hash := md5.New() 248 _, err := io.WriteString(hash, content) 249 th.AssertNoErr(t, err) 250 localChecksum := hash.Sum(nil) 251 252 w.Header().Set("ETag", fmt.Sprintf("%x", localChecksum)) 253 w.WriteHeader(http.StatusCreated) 254 }) 255 } 256 257 // HandleCopyObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 258 // responds with a `Copy` response. 259 func HandleCopyObjectSuccessfully(t *testing.T, destination string) { 260 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 261 th.TestMethod(t, r, "COPY") 262 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 263 th.TestHeader(t, r, "Accept", "application/json") 264 th.TestHeader(t, r, "Destination", destination) 265 w.WriteHeader(http.StatusCreated) 266 }) 267 } 268 269 // HandleCopyObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 270 // responds with a `Copy` response. 271 func HandleCopyObjectVersionSuccessfully(t *testing.T) { 272 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 273 th.TestMethod(t, r, "COPY") 274 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 275 th.TestHeader(t, r, "Accept", "application/json") 276 th.TestHeader(t, r, "Destination", "/newTestContainer/newTestObject") 277 th.TestFormValues(t, r, map[string]string{"version-id": "123456788"}) 278 w.Header().Set("X-Object-Version-Id", "123456789") 279 w.WriteHeader(http.StatusCreated) 280 }) 281 } 282 283 // HandleDeleteObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 284 // responds with a `Delete` response. 285 func HandleDeleteObjectSuccessfully(t *testing.T, options ...option) { 286 ho := handlerOptions{ 287 path: "/testContainer/testObject", 288 } 289 for _, apply := range options { 290 apply(&ho) 291 } 292 293 th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) { 294 th.TestMethod(t, r, "DELETE") 295 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 296 th.TestHeader(t, r, "Accept", "application/json") 297 w.WriteHeader(http.StatusNoContent) 298 }) 299 } 300 301 const bulkDeleteResponse = ` 302 { 303 "Response Status": "foo", 304 "Response Body": "bar", 305 "Errors": [], 306 "Number Deleted": 2, 307 "Number Not Found": 0 308 } 309 ` 310 311 // HandleBulkDeleteSuccessfully creates an HTTP handler at `/` on the test 312 // handler mux that responds with a `BulkDelete` response. 313 func HandleBulkDeleteSuccessfully(t *testing.T) { 314 th.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 315 th.TestMethod(t, r, "POST") 316 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 317 th.TestHeader(t, r, "Accept", "application/json") 318 th.TestHeader(t, r, "Content-Type", "text/plain") 319 th.TestFormValues(t, r, map[string]string{ 320 "bulk-delete": "true", 321 }) 322 th.TestBody(t, r, "testContainer/testObject1\ntestContainer/testObject2\n") 323 324 w.Header().Set("Content-Type", "application/json") 325 w.WriteHeader(http.StatusOK) 326 fmt.Fprint(w, bulkDeleteResponse) 327 }) 328 } 329 330 // HandleUpdateObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 331 // responds with a `Update` response. 332 func HandleUpdateObjectSuccessfully(t *testing.T, options ...option) { 333 ho := handlerOptions{ 334 path: "/testContainer/testObject", 335 } 336 for _, apply := range options { 337 apply(&ho) 338 } 339 340 th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) { 341 th.TestMethod(t, r, "POST") 342 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 343 th.TestHeader(t, r, "Accept", "application/json") 344 th.TestHeader(t, r, "X-Object-Meta-Gophercloud-Test", "objects") 345 th.TestHeader(t, r, "X-Remove-Object-Meta-Gophercloud-Test-Remove", "remove") 346 th.TestHeader(t, r, "Content-Disposition", "") 347 th.TestHeader(t, r, "Content-Encoding", "") 348 th.TestHeader(t, r, "Content-Type", "") 349 th.TestHeaderUnset(t, r, "X-Delete-After") 350 th.TestHeader(t, r, "X-Delete-At", "0") 351 th.TestHeader(t, r, "X-Detect-Content-Type", "false") 352 w.WriteHeader(http.StatusAccepted) 353 }) 354 } 355 356 // HandleGetObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 357 // responds with a `Get` response. 358 func HandleGetObjectSuccessfully(t *testing.T, options ...option) { 359 ho := handlerOptions{ 360 path: "/testContainer/testObject", 361 } 362 for _, apply := range options { 363 apply(&ho) 364 } 365 366 th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) { 367 th.TestMethod(t, r, "HEAD") 368 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 369 th.TestHeader(t, r, "Accept", "application/json") 370 w.Header().Add("X-Object-Meta-Gophercloud-Test", "objects") 371 w.Header().Add("X-Static-Large-Object", "true") 372 w.WriteHeader(http.StatusNoContent) 373 }) 374 }