1package swift
2
3import (
4	"io/ioutil"
5	"os"
6	"reflect"
7	"strconv"
8	"strings"
9	"testing"
10
11	"github.com/ncw/swift/swifttest"
12
13	"github.com/docker/distribution/context"
14	storagedriver "github.com/docker/distribution/registry/storage/driver"
15	"github.com/docker/distribution/registry/storage/driver/testsuites"
16
17	"gopkg.in/check.v1"
18)
19
20// Hook up gocheck into the "go test" runner.
21func Test(t *testing.T) { check.TestingT(t) }
22
23var swiftDriverConstructor func(prefix string) (*Driver, error)
24
25func init() {
26	var (
27		username           string
28		password           string
29		authURL            string
30		tenant             string
31		tenantID           string
32		domain             string
33		domainID           string
34		tenantDomain       string
35		tenantDomainID     string
36		trustID            string
37		container          string
38		region             string
39		AuthVersion        int
40		endpointType       string
41		insecureSkipVerify bool
42		secretKey          string
43		accessKey          string
44		containerKey       bool
45		tempURLMethods     []string
46
47		swiftServer *swifttest.SwiftServer
48		err         error
49	)
50	username = os.Getenv("SWIFT_USERNAME")
51	password = os.Getenv("SWIFT_PASSWORD")
52	authURL = os.Getenv("SWIFT_AUTH_URL")
53	tenant = os.Getenv("SWIFT_TENANT_NAME")
54	tenantID = os.Getenv("SWIFT_TENANT_ID")
55	domain = os.Getenv("SWIFT_DOMAIN_NAME")
56	domainID = os.Getenv("SWIFT_DOMAIN_ID")
57	tenantDomain = os.Getenv("SWIFT_DOMAIN_NAME")
58	tenantDomainID = os.Getenv("SWIFT_DOMAIN_ID")
59	trustID = os.Getenv("SWIFT_TRUST_ID")
60	container = os.Getenv("SWIFT_CONTAINER_NAME")
61	region = os.Getenv("SWIFT_REGION_NAME")
62	AuthVersion, _ = strconv.Atoi(os.Getenv("SWIFT_AUTH_VERSION"))
63	endpointType = os.Getenv("SWIFT_ENDPOINT_TYPE")
64	insecureSkipVerify, _ = strconv.ParseBool(os.Getenv("SWIFT_INSECURESKIPVERIFY"))
65	secretKey = os.Getenv("SWIFT_SECRET_KEY")
66	accessKey = os.Getenv("SWIFT_ACCESS_KEY")
67	containerKey, _ = strconv.ParseBool(os.Getenv("SWIFT_TEMPURL_CONTAINERKEY"))
68	tempURLMethods = strings.Split(os.Getenv("SWIFT_TEMPURL_METHODS"), ",")
69
70	if username == "" || password == "" || authURL == "" || container == "" {
71		if swiftServer, err = swifttest.NewSwiftServer("localhost"); err != nil {
72			panic(err)
73		}
74		username = "swifttest"
75		password = "swifttest"
76		authURL = swiftServer.AuthURL
77		container = "test"
78	}
79
80	prefix, err := ioutil.TempDir("", "driver-")
81	if err != nil {
82		panic(err)
83	}
84	defer os.Remove(prefix)
85
86	swiftDriverConstructor = func(root string) (*Driver, error) {
87		parameters := Parameters{
88			username,
89			password,
90			authURL,
91			tenant,
92			tenantID,
93			domain,
94			domainID,
95			tenantDomain,
96			tenantDomainID,
97			trustID,
98			region,
99			AuthVersion,
100			container,
101			root,
102			endpointType,
103			insecureSkipVerify,
104			defaultChunkSize,
105			secretKey,
106			accessKey,
107			containerKey,
108			tempURLMethods,
109		}
110
111		return New(parameters)
112	}
113
114	driverConstructor := func() (storagedriver.StorageDriver, error) {
115		return swiftDriverConstructor(prefix)
116	}
117
118	testsuites.RegisterSuite(driverConstructor, testsuites.NeverSkip)
119}
120
121func TestEmptyRootList(t *testing.T) {
122	validRoot, err := ioutil.TempDir("", "driver-")
123	if err != nil {
124		t.Fatalf("unexpected error creating temporary directory: %v", err)
125	}
126	defer os.Remove(validRoot)
127
128	rootedDriver, err := swiftDriverConstructor(validRoot)
129	if err != nil {
130		t.Fatalf("unexpected error creating rooted driver: %v", err)
131	}
132
133	emptyRootDriver, err := swiftDriverConstructor("")
134	if err != nil {
135		t.Fatalf("unexpected error creating empty root driver: %v", err)
136	}
137
138	slashRootDriver, err := swiftDriverConstructor("/")
139	if err != nil {
140		t.Fatalf("unexpected error creating slash root driver: %v", err)
141	}
142
143	filename := "/test"
144	contents := []byte("contents")
145	ctx := context.Background()
146	err = rootedDriver.PutContent(ctx, filename, contents)
147	if err != nil {
148		t.Fatalf("unexpected error creating content: %v", err)
149	}
150
151	keys, _ := emptyRootDriver.List(ctx, "/")
152	for _, path := range keys {
153		if !storagedriver.PathRegexp.MatchString(path) {
154			t.Fatalf("unexpected string in path: %q != %q", path, storagedriver.PathRegexp)
155		}
156	}
157
158	keys, _ = slashRootDriver.List(ctx, "/")
159	for _, path := range keys {
160		if !storagedriver.PathRegexp.MatchString(path) {
161			t.Fatalf("unexpected string in path: %q != %q", path, storagedriver.PathRegexp)
162		}
163	}
164
165	// Create an object with a path nested under the existing object
166	err = rootedDriver.PutContent(ctx, filename+"/file1", contents)
167	if err != nil {
168		t.Fatalf("unexpected error creating content: %v", err)
169	}
170
171	err = rootedDriver.Delete(ctx, filename)
172	if err != nil {
173		t.Fatalf("failed to delete: %v", err)
174	}
175
176	keys, err = rootedDriver.List(ctx, "/")
177	if err != nil {
178		t.Fatalf("failed to list objects after deletion: %v", err)
179	}
180
181	if len(keys) != 0 {
182		t.Fatal("delete did not remove nested objects")
183	}
184}
185
186func TestFilenameChunking(t *testing.T) {
187	// Test valid input and sizes
188	input := []string{"a", "b", "c", "d", "e"}
189	expecteds := [][][]string{
190		{
191			{"a"},
192			{"b"},
193			{"c"},
194			{"d"},
195			{"e"},
196		},
197		{
198			{"a", "b"},
199			{"c", "d"},
200			{"e"},
201		},
202		{
203			{"a", "b", "c"},
204			{"d", "e"},
205		},
206		{
207			{"a", "b", "c", "d"},
208			{"e"},
209		},
210		{
211			{"a", "b", "c", "d", "e"},
212		},
213		{
214			{"a", "b", "c", "d", "e"},
215		},
216	}
217	for i, expected := range expecteds {
218		actual, err := chunkFilenames(input, i+1)
219		if !reflect.DeepEqual(actual, expected) {
220			t.Fatalf("chunk %v didn't match expected value %v", actual, expected)
221		}
222		if err != nil {
223			t.Fatalf("unexpected error chunking filenames: %v", err)
224		}
225	}
226
227	// Test nil input
228	actual, err := chunkFilenames(nil, 5)
229	if len(actual) != 0 {
230		t.Fatal("chunks were returned when passed nil")
231	}
232	if err != nil {
233		t.Fatalf("unexpected error chunking filenames: %v", err)
234	}
235
236	// Test 0 and < 0 sizes
237	_, err = chunkFilenames(nil, 0)
238	if err == nil {
239		t.Fatal("expected error for size = 0")
240	}
241	_, err = chunkFilenames(nil, -1)
242	if err == nil {
243		t.Fatal("expected error for size = -1")
244	}
245}
246