1
// Copyright 2013 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
9
. "launchpad.net/gocheck"
11
"launchpad.net/juju-core/errors"
16
type StorageSuite struct {
20
var _ = Suite(new(StorageSuite))
22
// TestTransport is used as an http.Client.Transport for testing. It records
23
// the latest request, and returns a predetermined Response and error.
24
type TestTransport struct {
26
Response *http.Response
30
func (t *TestTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
32
return t.Response, t.Error
35
func makeResponse(content string, status int) *http.Response {
36
return &http.Response{
37
Status: fmt.Sprintf("%d", status),
39
Body: ioutil.NopCloser(strings.NewReader(content)),
43
// testStorageContext is a struct implementing the storageContext interface
44
// used in test. It will return, via getContainer() and getStorageContext()
45
// the objects used at creation time.
46
type testStorageContext struct {
48
storageContext *gwacl.StorageContext
51
func (context *testStorageContext) getContainer() string {
52
return context.container
55
func (context *testStorageContext) getStorageContext() (*gwacl.StorageContext, error) {
56
return context.storageContext, nil
59
// makeAzureStorage creates a test azureStorage object that will talk to a
60
// fake http server set up to always return the given http.Response object.
61
// makeAzureStorage returns an azureStorage object and a TestTransport object.
62
// The TestTransport object can be used to check that the expected query has
63
// been issued to the test server.
64
func makeAzureStorage(response *http.Response, container string, account string) (azureStorage, *TestTransport) {
65
transport := &TestTransport{Response: response}
66
client := &http.Client{Transport: transport}
67
storageContext := gwacl.NewTestStorageContext(client)
68
storageContext.Account = account
69
context := &testStorageContext{container: container, storageContext: storageContext}
70
azStorage := azureStorage{context}
71
return azStorage, transport
74
var blobListResponse = `
75
<?xml version="1.0" encoding="utf-8"?>
76
<EnumerationResults ContainerName="http://myaccount.blob.core.windows.net/mycontainer">
77
<Prefix>prefix</Prefix>
78
<Marker>marker</Marker>
79
<MaxResults>maxresults</MaxResults>
80
<Delimiter>delimiter</Delimiter>
92
</EnumerationResults>`
94
func (StorageSuite) TestList(c *C) {
95
container := "container"
96
response := makeResponse(blobListResponse, http.StatusOK)
97
azStorage, transport := makeAzureStorage(response, container, "account")
99
names, err := azStorage.List(prefix)
101
// The prefix has been passed down as a query parameter.
102
c.Check(transport.Request.URL.Query()["prefix"], DeepEquals, []string{prefix})
103
// The container name is used in the requested URL.
104
c.Check(transport.Request.URL.String(), Matches, ".*"+container+".*")
105
c.Check(names, DeepEquals, []string{"prefix-1", "prefix-2"})
108
func (StorageSuite) TestGet(c *C) {
109
blobContent := "test blob"
110
container := "container"
111
filename := "blobname"
112
response := makeResponse(blobContent, http.StatusOK)
113
azStorage, transport := makeAzureStorage(response, container, "account")
114
reader, err := azStorage.Get(filename)
116
c.Assert(reader, NotNil)
119
context, err := azStorage.getStorageContext()
121
c.Check(transport.Request.URL.String(), Matches, context.GetFileURL(container, filename)+"?.*")
122
data, err := ioutil.ReadAll(reader)
124
c.Check(string(data), Equals, blobContent)
127
func (StorageSuite) TestGetReturnsNotFoundIf404(c *C) {
128
container := "container"
129
filename := "blobname"
130
response := makeResponse("not found", http.StatusNotFound)
131
azStorage, _ := makeAzureStorage(response, container, "account")
132
_, err := azStorage.Get(filename)
133
c.Assert(err, NotNil)
134
c.Check(errors.IsNotFoundError(err), Equals, true)
137
func (StorageSuite) TestPut(c *C) {
138
blobContent := "test blob"
139
container := "container"
140
filename := "blobname"
141
response := makeResponse("", http.StatusCreated)
142
azStorage, transport := makeAzureStorage(response, container, "account")
143
err := azStorage.Put(filename, strings.NewReader(blobContent), int64(len(blobContent)))
146
context, err := azStorage.getStorageContext()
148
c.Check(transport.Request.URL.String(), Matches, context.GetFileURL(container, filename)+"?.*")
151
func (StorageSuite) TestRemove(c *C) {
152
container := "container"
153
filename := "blobname"
154
response := makeResponse("", http.StatusAccepted)
155
azStorage, transport := makeAzureStorage(response, container, "account")
156
err := azStorage.Remove(filename)
159
context, err := azStorage.getStorageContext()
161
c.Check(transport.Request.URL.String(), Matches, context.GetFileURL(container, filename)+"?.*")
162
c.Check(transport.Request.Method, Equals, "DELETE")
165
func (StorageSuite) TestRemoveErrors(c *C) {
166
container := "container"
167
filename := "blobname"
168
response := makeResponse("", http.StatusForbidden)
169
azStorage, _ := makeAzureStorage(response, container, "account")
170
err := azStorage.Remove(filename)
171
c.Assert(err, NotNil)
174
func (StorageSuite) TestRemoveNonExistantBlobSucceeds(c *C) {
175
container := "container"
176
filename := "blobname"
177
response := makeResponse("", http.StatusNotFound)
178
azStorage, _ := makeAzureStorage(response, container, "account")
179
err := azStorage.Remove(filename)
183
func (StorageSuite) TestURL(c *C) {
184
container := "container"
185
filename := "blobname"
187
azStorage, _ := makeAzureStorage(nil, container, account)
188
URL, err := azStorage.URL(filename)
190
c.Check(URL, Matches, fmt.Sprintf("http://%s.blob.core.windows.net/%s/%s", account, container, filename))