github.com/uber/kraken@v0.1.4/lib/backend/gcsbackend/client_test.go (about)

     1  // Copyright (c) 2016-2019 Uber Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  package gcsbackend
    15  
    16  import (
    17  	"bytes"
    18  	"fmt"
    19  	"math/rand"
    20  	"strconv"
    21  	"strings"
    22  	"testing"
    23  
    24  	"github.com/uber/kraken/core"
    25  	"github.com/uber/kraken/lib/backend"
    26  	"github.com/uber/kraken/mocks/lib/backend/gcsbackend"
    27  	"github.com/uber/kraken/utils/mockutil"
    28  	"github.com/uber/kraken/utils/randutil"
    29  	"github.com/uber/kraken/utils/rwutil"
    30  
    31  	"cloud.google.com/go/storage"
    32  	"google.golang.org/api/iterator"
    33  
    34  	"github.com/golang/mock/gomock"
    35  	"github.com/stretchr/testify/require"
    36  )
    37  
    38  type clientMocks struct {
    39  	config   Config
    40  	userAuth UserAuthConfig
    41  	gcs      *mockgcsbackend.MockGCS
    42  }
    43  
    44  func newClientMocks(t *testing.T) (*clientMocks, func()) {
    45  	ctrl := gomock.NewController(t)
    46  
    47  	var auth AuthConfig
    48  	auth.GCS.AccessBlob = "access_blob"
    49  
    50  	return &clientMocks{
    51  		config: Config{
    52  			Username:      "test-user",
    53  			Location:      "test-location",
    54  			Bucket:        "test-bucket",
    55  			NamePath:      "identity",
    56  			RootDirectory: "/root",
    57  			ListMaxKeys:   5,
    58  		},
    59  		userAuth: UserAuthConfig{"test-user": auth},
    60  		gcs:      mockgcsbackend.NewMockGCS(ctrl),
    61  	}, ctrl.Finish
    62  }
    63  
    64  func (m *clientMocks) new() *Client {
    65  	c, err := NewClient(m.config, m.userAuth, WithGCS(m.gcs))
    66  	if err != nil {
    67  		panic(err)
    68  	}
    69  	return c
    70  }
    71  
    72  func TestClientFactory(t *testing.T) {
    73  	require := require.New(t)
    74  
    75  	config := Config{
    76  		Username:      "test-user",
    77  		Location:      "test-region",
    78  		Bucket:        "test-bucket",
    79  		NamePath:      "identity",
    80  		RootDirectory: "/root",
    81  	}
    82  	var auth AuthConfig
    83  	auth.GCS.AccessBlob = "access_blob"
    84  	userAuth := UserAuthConfig{"test-user": auth}
    85  	f := factory{}
    86  	_, err := f.Create(config, userAuth)
    87  	fmt.Println(err.Error())
    88  	require.True(strings.Contains(err.Error(), "invalid gcs credentials"))
    89  }
    90  
    91  func TestClientStat(t *testing.T) {
    92  	require := require.New(t)
    93  
    94  	mocks, cleanup := newClientMocks(t)
    95  	defer cleanup()
    96  
    97  	client := mocks.new()
    98  
    99  	var objectAttrs storage.ObjectAttrs
   100  	objectAttrs.Size = 100
   101  
   102  	mocks.gcs.EXPECT().ObjectAttrs("/root/test").Return(&objectAttrs, nil)
   103  
   104  	info, err := client.Stat(core.NamespaceFixture(), "test")
   105  	require.NoError(err)
   106  	require.Equal(core.NewBlobInfo(100), info)
   107  }
   108  
   109  func TestClientDownload(t *testing.T) {
   110  	require := require.New(t)
   111  
   112  	mocks, cleanup := newClientMocks(t)
   113  	defer cleanup()
   114  
   115  	client := mocks.new()
   116  	data := randutil.Text(32)
   117  
   118  	mocks.gcs.EXPECT().Download(
   119  		"/root/test",
   120  		mockutil.MatchWriter(data),
   121  	).Return(int64(len(data)), nil)
   122  
   123  	w := make(rwutil.PlainWriter, len(data))
   124  	require.NoError(client.Download(core.NamespaceFixture(), "test", w))
   125  	require.Equal(data, []byte(w))
   126  }
   127  
   128  func TestClientUpload(t *testing.T) {
   129  	require := require.New(t)
   130  
   131  	mocks, cleanup := newClientMocks(t)
   132  	defer cleanup()
   133  
   134  	client := mocks.new()
   135  
   136  	data := randutil.Text(32)
   137  	dataReader := bytes.NewReader(data)
   138  
   139  	mocks.gcs.EXPECT().Upload(
   140  		"/root/test",
   141  		gomock.Any(),
   142  	).Return(int64(len(data)), nil)
   143  
   144  	require.NoError(client.Upload(core.NamespaceFixture(), "test", dataReader))
   145  }
   146  
   147  func Alphabets(t *testing.T, maxIterate int) *AlphaIterator {
   148  	it := &AlphaIterator{assert: require.New(t), maxIterate: maxIterate}
   149  	it.pageInfo, it.nextFunc = iterator.NewPageInfo(
   150  		it.next,
   151  		func() int { return len(it.elems) },
   152  		func() interface{} { e := it.elems; it.elems = nil; return e })
   153  	return it
   154  }
   155  
   156  // Iterates from 0-maxIterate
   157  type AlphaIterator struct {
   158  	assert     *require.Assertions
   159  	pageInfo   *iterator.PageInfo
   160  	nextFunc   func() error
   161  	elems      []string
   162  	maxIterate int
   163  }
   164  
   165  func (it *AlphaIterator) PageInfo() *iterator.PageInfo {
   166  	return it.pageInfo
   167  }
   168  
   169  func (it *AlphaIterator) next(pageSize int, pageToken string) (string, error) {
   170  	i := 0
   171  	if pageToken != "" {
   172  		var err error
   173  		i, err = strconv.Atoi(pageToken)
   174  		it.assert.NoError(err)
   175  	}
   176  	endCount := i + pageSize
   177  	for ; i < endCount && i < it.maxIterate; i++ {
   178  		it.elems = append(it.elems, "test/"+strconv.Itoa(i))
   179  	}
   180  	if i == it.maxIterate {
   181  		return "", nil
   182  	}
   183  	return strconv.Itoa(i), nil
   184  }
   185  
   186  func TestClientList(t *testing.T) {
   187  	require := require.New(t)
   188  	maxIterate := 100
   189  
   190  	mocks, cleanup := newClientMocks(t)
   191  	defer cleanup()
   192  
   193  	client := mocks.new()
   194  
   195  	contToken := ""
   196  	mocks.gcs.EXPECT().GetObjectIterator(
   197  		"/root/test",
   198  	).AnyTimes().Return(Alphabets(t, maxIterate))
   199  	for i := 0; i < maxIterate; {
   200  		count := (rand.Int() % 10) + 1
   201  		var expected []string
   202  		var ret []string
   203  		for j := i; j < (i+count) && j < maxIterate; j++ {
   204  			expected = append(expected, "test/"+strconv.Itoa(j))
   205  			ret = append(ret, "/root/test/"+strconv.Itoa(j))
   206  		}
   207  
   208  		continuationToken := ""
   209  		if (i + count) < maxIterate {
   210  			strconv.Itoa(i + count)
   211  		}
   212  		mocks.gcs.EXPECT().NextPage(
   213  			gomock.Any(),
   214  		).Return(ret, continuationToken, nil)
   215  
   216  		result, err := client.List("test", backend.ListWithPagination(),
   217  			backend.ListWithMaxKeys(count),
   218  			backend.ListWithContinuationToken(contToken))
   219  		require.NoError(err)
   220  		require.Equal(expected, result.Names)
   221  		contToken = result.ContinuationToken
   222  		i += count
   223  	}
   224  	require.Equal(contToken, "")
   225  }