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 }