1package testing 2 3import ( 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// HandleDownloadObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 17// responds with a `Download` response. 18func HandleDownloadObjectSuccessfully(t *testing.T) { 19 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 20 date := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) 21 th.TestMethod(t, r, "GET") 22 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 23 th.TestHeader(t, r, "Accept", "application/json") 24 w.Header().Set("Date", date.Format(time.RFC1123)) 25 w.Header().Set("X-Static-Large-Object", "True") 26 27 unModifiedSince := r.Header.Get("If-Unmodified-Since") 28 modifiedSince := r.Header.Get("If-Modified-Since") 29 if unModifiedSince != "" { 30 ums, _ := time.Parse(time.RFC1123, unModifiedSince) 31 if ums.Before(date) || ums.Equal(date) { 32 w.WriteHeader(http.StatusPreconditionFailed) 33 return 34 } 35 } 36 if modifiedSince != "" { 37 ms, _ := time.Parse(time.RFC1123, modifiedSince) 38 if ms.After(date) { 39 w.WriteHeader(http.StatusNotModified) 40 return 41 } 42 } 43 w.Header().Set("Last-Modified", date.Format(time.RFC1123)) 44 w.WriteHeader(http.StatusOK) 45 fmt.Fprintf(w, "Successful download with Gophercloud") 46 }) 47} 48 49// ExpectedListInfo is the result expected from a call to `List` when full 50// info is requested. 51var ExpectedListInfo = []objects.Object{ 52 { 53 Hash: "451e372e48e0f6b1114fa0724aa79fa1", 54 LastModified: time.Date(2016, time.August, 17, 22, 11, 58, 602650000, time.UTC), 55 Bytes: 14, 56 Name: "goodbye", 57 ContentType: "application/octet-stream", 58 }, 59 { 60 Hash: "451e372e48e0f6b1114fa0724aa79fa1", 61 LastModified: time.Date(2016, time.August, 17, 22, 11, 58, 602650000, time.UTC), 62 Bytes: 14, 63 Name: "hello", 64 ContentType: "application/octet-stream", 65 }, 66} 67 68// ExpectedListSubdir is the result expected from a call to `List` when full 69// info is requested. 70var ExpectedListSubdir = []objects.Object{ 71 { 72 Subdir: "directory/", 73 }, 74} 75 76// ExpectedListNames is the result expected from a call to `List` when just 77// object names are requested. 78var ExpectedListNames = []string{"hello", "goodbye"} 79 80// HandleListObjectsInfoSuccessfully creates an HTTP handler at `/testContainer` on the test handler mux that 81// responds with a `List` response when full info is requested. 82func HandleListObjectsInfoSuccessfully(t *testing.T) { 83 th.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) { 84 th.TestMethod(t, r, "GET") 85 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 86 th.TestHeader(t, r, "Accept", "application/json") 87 88 w.Header().Set("Content-Type", "application/json") 89 r.ParseForm() 90 marker := r.Form.Get("marker") 91 switch marker { 92 case "": 93 fmt.Fprintf(w, `[ 94 { 95 "hash": "451e372e48e0f6b1114fa0724aa79fa1", 96 "last_modified": "2016-08-17T22:11:58.602650", 97 "bytes": 14, 98 "name": "goodbye", 99 "content_type": "application/octet-stream" 100 }, 101 { 102 "hash": "451e372e48e0f6b1114fa0724aa79fa1", 103 "last_modified": "2016-08-17T22:11:58.602650", 104 "bytes": 14, 105 "name": "hello", 106 "content_type": "application/octet-stream" 107 } 108 ]`) 109 case "hello": 110 fmt.Fprintf(w, `[]`) 111 default: 112 t.Fatalf("Unexpected marker: [%s]", marker) 113 } 114 }) 115} 116 117// HandleListSubdirSuccessfully creates an HTTP handler at `/testContainer` on the test handler mux that 118// responds with a `List` response when full info is requested. 119func HandleListSubdirSuccessfully(t *testing.T) { 120 th.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) { 121 th.TestMethod(t, r, "GET") 122 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 123 th.TestHeader(t, r, "Accept", "application/json") 124 125 w.Header().Set("Content-Type", "application/json") 126 r.ParseForm() 127 marker := r.Form.Get("marker") 128 switch marker { 129 case "": 130 fmt.Fprintf(w, `[ 131 { 132 "subdir": "directory/" 133 } 134 ]`) 135 case "directory/": 136 fmt.Fprintf(w, `[]`) 137 default: 138 t.Fatalf("Unexpected marker: [%s]", marker) 139 } 140 }) 141} 142 143// HandleListObjectNamesSuccessfully creates an HTTP handler at `/testContainer` on the test handler mux that 144// responds with a `List` response when only object names are requested. 145func HandleListObjectNamesSuccessfully(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", "text/plain") 150 151 w.Header().Set("Content-Type", "text/plain") 152 r.ParseForm() 153 marker := r.Form.Get("marker") 154 switch marker { 155 case "": 156 fmt.Fprintf(w, "hello\ngoodbye\n") 157 case "goodbye": 158 fmt.Fprintf(w, "") 159 default: 160 t.Fatalf("Unexpected marker: [%s]", marker) 161 } 162 }) 163} 164 165// HandleCreateTextObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux 166// that responds with a `Create` response. A Content-Type of "text/plain" is expected. 167func HandleCreateTextObjectSuccessfully(t *testing.T, content string) { 168 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 169 th.TestMethod(t, r, "PUT") 170 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 171 th.TestHeader(t, r, "Content-Type", "text/plain") 172 th.TestHeader(t, r, "Accept", "application/json") 173 th.TestBody(t, r, `Did gyre and gimble in the wabe`) 174 175 hash := md5.New() 176 io.WriteString(hash, content) 177 localChecksum := hash.Sum(nil) 178 179 w.Header().Set("ETag", fmt.Sprintf("%x", localChecksum)) 180 w.WriteHeader(http.StatusCreated) 181 }) 182} 183 184// HandleCreateTextWithCacheControlSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler 185// mux that responds with a `Create` response. A Cache-Control of `max-age="3600", public` is expected. 186func HandleCreateTextWithCacheControlSuccessfully(t *testing.T, content string) { 187 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 188 th.TestMethod(t, r, "PUT") 189 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 190 th.TestHeader(t, r, "Cache-Control", `max-age="3600", public`) 191 th.TestHeader(t, r, "Accept", "application/json") 192 th.TestBody(t, r, `All mimsy were the borogoves`) 193 194 hash := md5.New() 195 io.WriteString(hash, content) 196 localChecksum := hash.Sum(nil) 197 198 w.Header().Set("ETag", fmt.Sprintf("%x", localChecksum)) 199 w.WriteHeader(http.StatusCreated) 200 }) 201} 202 203// HandleCreateTypelessObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler 204// mux that responds with a `Create` response. No Content-Type header may be present in the request, so that server- 205// side content-type detection will be triggered properly. 206func HandleCreateTypelessObjectSuccessfully(t *testing.T, content string) { 207 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 208 th.TestMethod(t, r, "PUT") 209 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 210 th.TestHeader(t, r, "Accept", "application/json") 211 th.TestBody(t, r, `The sky was the color of television, tuned to a dead channel.`) 212 213 if contentType, present := r.Header["Content-Type"]; present { 214 t.Errorf("Expected Content-Type header to be omitted, but was %#v", contentType) 215 } 216 217 hash := md5.New() 218 io.WriteString(hash, content) 219 localChecksum := hash.Sum(nil) 220 221 w.Header().Set("ETag", fmt.Sprintf("%x", localChecksum)) 222 w.WriteHeader(http.StatusCreated) 223 }) 224} 225 226// HandleCopyObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 227// responds with a `Copy` response. 228func HandleCopyObjectSuccessfully(t *testing.T) { 229 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 230 th.TestMethod(t, r, "COPY") 231 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 232 th.TestHeader(t, r, "Accept", "application/json") 233 th.TestHeader(t, r, "Destination", "/newTestContainer/newTestObject") 234 w.WriteHeader(http.StatusCreated) 235 }) 236} 237 238// HandleDeleteObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 239// responds with a `Delete` response. 240func HandleDeleteObjectSuccessfully(t *testing.T) { 241 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 242 th.TestMethod(t, r, "DELETE") 243 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 244 th.TestHeader(t, r, "Accept", "application/json") 245 w.WriteHeader(http.StatusNoContent) 246 }) 247} 248 249const bulkDeleteResponse = ` 250{ 251 "Response Status": "foo", 252 "Response Body": "bar", 253 "Errors": [], 254 "Number Deleted": 2, 255 "Number Not Found": 0 256} 257` 258 259// HandleBulkDeleteSuccessfully creates an HTTP handler at `/` on the test 260// handler mux that responds with a `BulkDelete` response. 261func HandleBulkDeleteSuccessfully(t *testing.T) { 262 th.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 263 th.TestMethod(t, r, "POST") 264 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 265 th.TestHeader(t, r, "Accept", "application/json") 266 th.TestHeader(t, r, "Content-Type", "text/plain") 267 th.TestFormValues(t, r, map[string]string{ 268 "bulk-delete": "true", 269 }) 270 th.TestBody(t, r, "testContainer/testObject1\ntestContainer/testObject2\n") 271 272 w.Header().Set("Content-Type", "application/json") 273 w.WriteHeader(http.StatusOK) 274 fmt.Fprintf(w, bulkDeleteResponse) 275 }) 276} 277 278// HandleUpdateObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 279// responds with a `Update` response. 280func HandleUpdateObjectSuccessfully(t *testing.T) { 281 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 282 th.TestMethod(t, r, "POST") 283 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 284 th.TestHeader(t, r, "Accept", "application/json") 285 th.TestHeader(t, r, "X-Object-Meta-Gophercloud-Test", "objects") 286 th.TestHeader(t, r, "X-Remove-Object-Meta-Gophercloud-Test-Remove", "remove") 287 w.WriteHeader(http.StatusAccepted) 288 }) 289} 290 291// HandleGetObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that 292// responds with a `Get` response. 293func HandleGetObjectSuccessfully(t *testing.T) { 294 th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) { 295 th.TestMethod(t, r, "HEAD") 296 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) 297 th.TestHeader(t, r, "Accept", "application/json") 298 w.Header().Add("X-Object-Meta-Gophercloud-Test", "objects") 299 w.Header().Add("X-Static-Large-Object", "true") 300 w.WriteHeader(http.StatusNoContent) 301 }) 302} 303