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