2019-07-24 15:40:22 +01:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package uplink_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
2019-08-01 12:14:09 +01:00
|
|
|
"go.uber.org/zap/zaptest"
|
2019-07-24 15:40:22 +01:00
|
|
|
|
|
|
|
"storj.io/storj/internal/testcontext"
|
|
|
|
"storj.io/storj/internal/testplanet"
|
|
|
|
"storj.io/storj/lib/uplink"
|
|
|
|
"storj.io/storj/pkg/storj"
|
|
|
|
)
|
|
|
|
|
|
|
|
type expectedResult struct {
|
|
|
|
path string
|
|
|
|
isPrefix bool
|
|
|
|
}
|
|
|
|
|
|
|
|
type listChallenge struct {
|
|
|
|
commands []string // list commands that should result in the same set of responses
|
|
|
|
expectedResults []expectedResult // results that should come back for each command above
|
|
|
|
}
|
|
|
|
|
|
|
|
type putGetListTest struct {
|
|
|
|
bucket string // bucket to upload to
|
|
|
|
paths []string // test will create a file at every path here
|
|
|
|
listChallenges []listChallenge // set of list commands and expected results
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestPutGetList allows you to create a bucket, a set of paths, and a set of
|
|
|
|
// list challenges that you want to try against that configuring. It will create
|
|
|
|
// a unique file for each path, upload it, download it, and run the list
|
|
|
|
// challenges against it.
|
|
|
|
func TestPutGetList(t *testing.T) {
|
|
|
|
testplanet.Run(t, testplanet.Config{
|
|
|
|
SatelliteCount: 1,
|
|
|
|
StorageNodeCount: 1,
|
|
|
|
UplinkCount: 1},
|
|
|
|
func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
|
|
apiKey := planet.Uplinks[0].APIKey[planet.Satellites[0].ID()]
|
|
|
|
satelliteAddr := planet.Satellites[0].Local().Address.Address
|
|
|
|
|
|
|
|
tests := []putGetListTest{
|
|
|
|
{
|
|
|
|
bucket: "bu1",
|
|
|
|
paths: []string{
|
|
|
|
"a-file",
|
|
|
|
"a/b-file",
|
|
|
|
"a/b/slash-file",
|
|
|
|
"a/b////",
|
|
|
|
"a/b//",
|
|
|
|
"a/b//c-file",
|
|
|
|
"a/b//c/",
|
|
|
|
"//bob",
|
|
|
|
"/",
|
|
|
|
},
|
|
|
|
listChallenges: []listChallenge{
|
|
|
|
{
|
|
|
|
commands: []string{"/"},
|
|
|
|
expectedResults: []expectedResult{
|
|
|
|
{
|
|
|
|
path: "/",
|
|
|
|
isPrefix: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
path: "",
|
|
|
|
isPrefix: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
commands: []string{"//"},
|
|
|
|
expectedResults: []expectedResult{
|
|
|
|
{
|
|
|
|
path: "bob",
|
|
|
|
isPrefix: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
commands: []string{"a", "a/"},
|
|
|
|
expectedResults: []expectedResult{
|
|
|
|
{
|
|
|
|
path: "b/",
|
|
|
|
isPrefix: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
path: "b-file",
|
|
|
|
isPrefix: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
commands: []string{"a/b", "a/b/"},
|
|
|
|
expectedResults: []expectedResult{
|
|
|
|
{
|
|
|
|
path: "/",
|
|
|
|
isPrefix: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
path: "slash-file",
|
|
|
|
isPrefix: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
commands: []string{"a/b//"},
|
|
|
|
expectedResults: []expectedResult{
|
|
|
|
{
|
|
|
|
path: "c/",
|
|
|
|
isPrefix: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
path: "c-file",
|
|
|
|
isPrefix: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
path: "/",
|
|
|
|
isPrefix: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
path: "",
|
|
|
|
isPrefix: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
commands: []string{"a/b///"},
|
|
|
|
expectedResults: []expectedResult{
|
|
|
|
{
|
|
|
|
path: "/",
|
|
|
|
isPrefix: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
commands: []string{"a/b////"},
|
|
|
|
expectedResults: []expectedResult{
|
|
|
|
{
|
|
|
|
path: "",
|
|
|
|
isPrefix: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
runTest(ctx, t, apiKey, satelliteAddr, test)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func runTest(ctx context.Context, t *testing.T, apiKey, satelliteAddr string,
|
|
|
|
test putGetListTest) {
|
|
|
|
|
|
|
|
errCatch := func(fn func() error) { require.NoError(t, fn()) }
|
|
|
|
|
|
|
|
cfg := &uplink.Config{}
|
2019-08-01 12:14:09 +01:00
|
|
|
cfg.Volatile.Log = zaptest.NewLogger(t)
|
2019-07-24 15:40:22 +01:00
|
|
|
cfg.Volatile.TLS.SkipPeerCAWhitelist = true
|
|
|
|
|
|
|
|
ul, err := uplink.NewUplink(ctx, cfg)
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer errCatch(ul.Close)
|
|
|
|
|
|
|
|
key, err := uplink.ParseAPIKey(apiKey)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
p, err := ul.OpenProject(ctx, satelliteAddr, key)
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer errCatch(p.Close)
|
|
|
|
|
|
|
|
_, err = p.CreateBucket(ctx, test.bucket, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
encKey, err := p.SaltedKeyFromPassphrase(ctx, "my secret passphrase")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Make an encryption context
|
|
|
|
access := uplink.NewEncryptionAccessWithDefaultKey(*encKey)
|
|
|
|
|
|
|
|
bu, err := p.OpenBucket(ctx, test.bucket, access)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// First upload files to all the specified paths
|
|
|
|
for _, path := range test.paths {
|
|
|
|
err = bu.UploadObject(ctx, path, strings.NewReader(fmt.Sprintf("%s%s", path, "hi")), nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now run the listChallenges and check the results
|
|
|
|
for _, listChallenge := range test.listChallenges {
|
|
|
|
for _, command := range listChallenge.commands {
|
|
|
|
results, err := bu.ListObjects(ctx, &uplink.ListOptions{
|
|
|
|
Direction: storj.After,
|
|
|
|
Cursor: "",
|
|
|
|
Prefix: command,
|
|
|
|
Recursive: false,
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
compareResults(t, results.Items, listChallenge.expectedResults)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Download all files, make sure they work
|
|
|
|
for _, path := range test.paths {
|
2019-08-13 18:29:02 +01:00
|
|
|
r, err := bu.Download(ctx, path)
|
2019-07-24 15:40:22 +01:00
|
|
|
require.NoError(t, err)
|
2019-08-13 18:29:02 +01:00
|
|
|
|
2019-07-24 15:40:22 +01:00
|
|
|
downloaded, err := ioutil.ReadAll(r)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, fmt.Sprintf("%s%s", path, "hi"), string(downloaded))
|
2019-08-13 18:29:02 +01:00
|
|
|
|
|
|
|
require.NoError(t, r.Close())
|
2019-07-24 15:40:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func compareResults(t *testing.T, items []storj.Object, expected []expectedResult) {
|
|
|
|
require.Equal(t, len(expected), len(items))
|
|
|
|
sort.SliceStable(items, func(i, j int) bool { return items[i].Path < items[j].Path })
|
|
|
|
sort.SliceStable(expected, func(i, j int) bool { return expected[i].path < expected[j].path })
|
|
|
|
for i, item := range items {
|
|
|
|
require.Equal(t, expected[i].path, item.Path)
|
|
|
|
require.Equal(t, expected[i].isPrefix, item.IsPrefix)
|
|
|
|
}
|
|
|
|
}
|