@@ -18,115 +18,269 @@ package gcp_test
1818
1919import (
2020 "context"
21+ "crypto/tls"
22+ "encoding/json"
23+ "fmt"
24+ "io"
25+ "io/ioutil"
26+ "log"
27+ "net"
28+ "net/http"
29+ "net/http/httptest"
2130 "os"
2231 "path/filepath"
2332 "testing"
2433 "time"
2534
2635 gcpStorage "cloud.google.com/go/storage"
2736 "github.com/fluxcd/source-controller/pkg/gcp"
28- "github.com/fluxcd/source-controller/pkg/gcp/mocks"
29- "github.com/golang/mock/gomock"
30- . "github.com/onsi/ginkgo"
31- . "github.com/onsi/gomega"
37+ "google.golang.org/api/googleapi"
38+ raw "google.golang.org/api/storage/v1"
39+ "gotest.tools/assert"
40+
41+ "google.golang.org/api/option"
42+ )
43+
44+ const (
45+ bucketName string = "test-bucket"
46+ objectName string = "test.yaml"
3247)
3348
3449var (
35- MockCtrl * gomock.Controller
36- MockClient * mocks.MockClient
37- MockBucketHandle * mocks.MockBucketHandle
38- MockObjectHandle * mocks.MockObjectHandle
39- bucketName string = "test-bucket"
40- objectName string = "test.yaml"
41- localPath string
50+ Client * gcpStorage.Client
51+ err error
4252)
4353
44- // mockgen -destination=mocks/mock_gcp_storage.go -package=mocks -source=gcp.go GCPStorageService
45- func TestGCPProvider (t * testing.T ) {
46- MockCtrl = gomock .NewController (GinkgoT ())
47- RegisterFailHandler (Fail )
48- RunSpecs (t , "Test GCP Storage Provider Suite" )
54+ func TestMain (m * testing.M ) {
55+ hc , close := newTestServer (func (w http.ResponseWriter , r * http.Request ) {
56+ io .Copy (ioutil .Discard , r .Body )
57+ w .WriteHeader (200 )
58+ if r .RequestURI == fmt .Sprintf ("/storage/v1/b/%s?alt=json&prettyPrint=false&projection=full" , bucketName ) {
59+ response := getBucket ()
60+ jsonedResp , err := json .Marshal (response )
61+ if err != nil {
62+ log .Fatalf ("error marshalling resp %v\n " , err )
63+ }
64+ _ , err = w .Write (jsonedResp )
65+ if err != nil {
66+ log .Fatalf ("error writing jsonedResp %v\n " , err )
67+ }
68+ } else if r .RequestURI == fmt .Sprintf ("/storage/v1/b/%s/o/%s?alt=json&prettyPrint=false&projection=full" , bucketName , objectName ) {
69+ response := getObject ()
70+ jsonedResp , err := json .Marshal (response )
71+ if err != nil {
72+ log .Fatalf ("error marshalling resp %v\n " , err )
73+ }
74+ _ , err = w .Write (jsonedResp )
75+ if err != nil {
76+ log .Fatalf ("error writing jsonedResp %v\n " , err )
77+ }
78+ } else if r .RequestURI == fmt .Sprintf ("/storage/v1/b/%s/o?alt=json&delimiter=&endOffset=&pageToken=&prefix=&prettyPrint=false&projection=full&startOffset=&versions=false" , bucketName ) {
79+ response := getObject ()
80+ jsonedResp , err := json .Marshal (response )
81+ if err != nil {
82+ log .Fatalf ("error marshalling resp %v\n " , err )
83+ }
84+ _ , err = w .Write (jsonedResp )
85+ if err != nil {
86+ log .Fatalf ("error writing jsonedResp %v\n " , err )
87+ }
88+ } else if r .RequestURI == fmt .Sprintf ("/%s/test.yaml" , bucketName ) || r .RequestURI == fmt .Sprintf ("/storage/v1/b/%s/o/%s?alt=json&prettyPrint=false&projection=full" , bucketName , objectName ) {
89+ response := getObjectFile ()
90+ _ , err = w .Write ([]byte (response ))
91+ if err != nil {
92+ log .Fatalf ("error writing jsonedResp %v\n " , err )
93+ }
94+ }
95+ })
96+ ctx := context .Background ()
97+ Client , err = gcpStorage .NewClient (ctx , option .WithHTTPClient (hc ))
98+ if err != nil {
99+ log .Fatal (err )
100+ }
101+ run := m .Run ()
102+ close ()
103+ os .Exit (run )
104+ }
105+
106+ func TestBucketExists (t * testing.T ) {
107+ gcpClient := & gcp.GCPClient {
108+ Client : Client ,
109+ StartRange : 0 ,
110+ EndRange : - 1 ,
111+ }
112+ exists , err := gcpClient .BucketExists (context .Background (), bucketName )
113+ assert .NilError (t , err )
114+ assert .Assert (t , exists )
115+ }
116+
117+ func TestObjectAttributes (t * testing.T ) {
118+ gcpClient := & gcp.GCPClient {
119+ Client : Client ,
120+ StartRange : 0 ,
121+ EndRange : - 1 ,
122+ }
123+ exists , objectAttrs , err := gcpClient .ObjectAttributes (context .Background (), bucketName , objectName )
124+ if err == gcpStorage .ErrObjectNotExist {
125+ assert .NilError (t , err )
126+ }
127+ assert .NilError (t , err )
128+ assert .Assert (t , exists )
129+ assert .Assert (t , objectAttrs != nil )
49130}
50131
51- var _ = BeforeSuite (func () {
52- MockClient = mocks .NewMockClient (MockCtrl )
53- MockBucketHandle = mocks .NewMockBucketHandle (MockCtrl )
54- MockObjectHandle = mocks .NewMockObjectHandle (MockCtrl )
132+ func TestListObjects (t * testing.T ) {
133+ gcpClient := & gcp.GCPClient {
134+ Client : Client ,
135+ StartRange : 0 ,
136+ EndRange : - 1 ,
137+ }
138+ objectInterator := gcpClient .ListObjects (context .Background (), bucketName , nil )
139+ for {
140+ _ , err := objectInterator .Next ()
141+ if err == gcp .IteratorDone {
142+ break
143+ }
144+ assert .NilError (t , err )
145+ }
146+ assert .Assert (t , objectInterator != nil )
147+ }
148+
149+ func TestFGetObject (t * testing.T ) {
55150 tempDir , err := os .MkdirTemp ("" , bucketName )
56- if err != nil {
57- Expect (err ).ToNot (HaveOccurred ())
151+ assert .NilError (t , err )
152+ defer os .RemoveAll (tempDir )
153+ gcpClient := & gcp.GCPClient {
154+ Client : Client ,
155+ StartRange : 0 ,
156+ EndRange : - 1 ,
58157 }
59- localPath = filepath .Join (tempDir , objectName )
60- MockClient .EXPECT ().Bucket (bucketName ).Return (& gcpStorage.BucketHandle {}).AnyTimes ()
61- MockBucketHandle .EXPECT ().Object (objectName ).Return (& gcpStorage.ObjectHandle {}).AnyTimes ()
62- MockBucketHandle .EXPECT ().Attrs (context .Background ()).Return (& gcpStorage.BucketAttrs {
63- Name : bucketName ,
64- Created : time .Now (),
65- Etag : "test-etag" ,
66- }, nil ).AnyTimes ()
67- MockBucketHandle .EXPECT ().Objects (gomock .Any (), nil ).Return (& gcpStorage.ObjectIterator {}).AnyTimes ()
68- MockObjectHandle .EXPECT ().Attrs (gomock .Any ()).Return (& gcpStorage.ObjectAttrs {
69- Bucket : bucketName ,
70- Name : objectName ,
71- ContentType : "text/x-yaml" ,
72- Etag : "test-etag" ,
73- Size : 125 ,
74- Created : time .Now (),
75- }, nil ).AnyTimes ()
76- MockObjectHandle .EXPECT ().NewRangeReader (gomock .Any (), 10 , 125 ).Return (& gcpStorage.Reader {}, nil ).AnyTimes ()
77- })
78-
79- var _ = Describe ("GCP Storage Provider" , func () {
80- Describe ("Get GCP Storage Provider client from gcp" , func () {
81-
82- Context ("Gcp storage Bucket - BucketExists" , func () {
83- It ("should not return an error when fetching gcp storage bucket" , func () {
84- gcpClient := & gcp.GCPClient {
85- Client : MockClient ,
86- StartRange : 0 ,
87- EndRange : - 1 ,
88- }
89- exists , err := gcpClient .BucketExists (context .Background (), bucketName )
90- Expect (err ).ToNot (HaveOccurred ())
91- Expect (exists ).To (BeTrue ())
92- })
93- })
94- Context ("Gcp storage Bucket - FGetObject" , func () {
95- It ("should get the object from the bucket and download the object locally" , func () {
96- gcpClient := & gcp.GCPClient {
97- Client : MockClient ,
98- StartRange : 0 ,
99- EndRange : - 1 ,
100- }
101- err := gcpClient .FGetObject (context .Background (), bucketName , objectName , localPath )
102- Expect (err ).ToNot (HaveOccurred ())
103- })
104- })
105- Context ("Gcp storage Bucket - ObjectAttributes" , func () {
106- It ("should get the object attributes" , func () {
107- gcpClient := & gcp.GCPClient {
108- Client : MockClient ,
109- StartRange : 0 ,
110- EndRange : - 1 ,
111- }
112- exists , attrs , err := gcpClient .ObjectAttributes (context .Background (), bucketName , objectName )
113- Expect (err ).ToNot (HaveOccurred ())
114- Expect (exists ).To (BeTrue ())
115- Expect (attrs ).ToNot (BeNil ())
116- })
117-
118- Context ("Gcp storage Bucket - SetRange" , func () {
119- It ("should set the range of the io reader seeker for the file download" , func () {
120- gcpClient := & gcp.GCPClient {
121- Client : MockClient ,
122- StartRange : 0 ,
123- EndRange : - 1 ,
124- }
125- gcpClient .SetRange (2 , 5 )
126- Expect (gcpClient .StartRange ).To (Equal (int64 (2 )))
127- Expect (gcpClient .EndRange ).To (Equal (int64 (5 )))
128- })
129- })
130- })
131- })
132- })
158+ localPath := filepath .Join (tempDir , objectName )
159+ err = gcpClient .FGetObject (context .Background (), bucketName , objectName , localPath )
160+ if err != io .EOF {
161+ assert .NilError (t , err )
162+ }
163+ }
164+
165+ func TestSetRange (t * testing.T ) {
166+ gcpClient := & gcp.GCPClient {
167+ Client : Client ,
168+ StartRange : 0 ,
169+ EndRange : - 1 ,
170+ }
171+ gcpClient .SetRange (2 , 5 )
172+ assert .Equal (t , gcpClient .StartRange , int64 (2 ))
173+ assert .Equal (t , gcpClient .EndRange , int64 (5 ))
174+ }
175+
176+ func newTestServer (handler func (w http.ResponseWriter , r * http.Request )) (* http.Client , func ()) {
177+ ts := httptest .NewTLSServer (http .HandlerFunc (handler ))
178+ tlsConf := & tls.Config {InsecureSkipVerify : true }
179+ tr := & http.Transport {
180+ TLSClientConfig : tlsConf ,
181+ DialTLS : func (netw , addr string ) (net.Conn , error ) {
182+ return tls .Dial ("tcp" , ts .Listener .Addr ().String (), tlsConf )
183+ },
184+ }
185+ return & http.Client {Transport : tr }, func () {
186+ tr .CloseIdleConnections ()
187+ ts .Close ()
188+ }
189+ }
190+
191+ func getObject () * raw.Object {
192+ customTime := time .Now ()
193+ retTime := customTime .Add (3 * time .Hour )
194+ return & raw.Object {
195+ Bucket : bucketName ,
196+ Name : objectName ,
197+ EventBasedHold : false ,
198+ TemporaryHold : false ,
199+ RetentionExpirationTime : retTime .Format (time .RFC3339 ),
200+ ContentType : "text/x-yaml" ,
201+ ContentLanguage : "en-us" ,
202+ Size : 1 << 20 ,
203+ CustomTime : customTime .Format (time .RFC3339 ),
204+ Md5Hash : "bFbHCDvedeecefdgmfmhfuRxBdcedGe96S82XJOAXxjJpk=" ,
205+ }
206+ }
207+
208+ func getBucket () * raw.Bucket {
209+ labels := map [string ]string {"a" : "b" }
210+ matchClasses := []string {"STANDARD" }
211+ aTime := time .Date (2021 , 1 , 2 , 0 , 0 , 0 , 0 , time .UTC )
212+ rb := & raw.Bucket {
213+ Name : bucketName ,
214+ Location : "loc" ,
215+ DefaultEventBasedHold : true ,
216+ Metageneration : 3 ,
217+ StorageClass : "sc" ,
218+ TimeCreated : "2021-5-23T04:05:06Z" ,
219+ Versioning : & raw.BucketVersioning {Enabled : true },
220+ Labels : labels ,
221+ Billing : & raw.BucketBilling {RequesterPays : true },
222+ Etag : "BNaB2y5Xr3&5MHDca4SoTNL79lyhahr7MV87ubwjgdtg6ghs" ,
223+ Lifecycle : & raw.BucketLifecycle {
224+ Rule : []* raw.BucketLifecycleRule {{
225+ Action : & raw.BucketLifecycleRuleAction {
226+ Type : "SetStorageClass" ,
227+ StorageClass : "NEARLINE" ,
228+ },
229+ Condition : & raw.BucketLifecycleRuleCondition {
230+ Age : 10 ,
231+ IsLive : googleapi .Bool (true ),
232+ CreatedBefore : "2021-01-02" ,
233+ MatchesStorageClass : matchClasses ,
234+ NumNewerVersions : 3 ,
235+ },
236+ }},
237+ },
238+ RetentionPolicy : & raw.BucketRetentionPolicy {
239+ RetentionPeriod : 3 ,
240+ EffectiveTime : aTime .Format (time .RFC3339 ),
241+ },
242+ IamConfiguration : & raw.BucketIamConfiguration {
243+ BucketPolicyOnly : & raw.BucketIamConfigurationBucketPolicyOnly {
244+ Enabled : true ,
245+ LockedTime : aTime .Format (time .RFC3339 ),
246+ },
247+ UniformBucketLevelAccess : & raw.BucketIamConfigurationUniformBucketLevelAccess {
248+ Enabled : true ,
249+ LockedTime : aTime .Format (time .RFC3339 ),
250+ },
251+ },
252+ Cors : []* raw.BucketCors {
253+ {
254+ MaxAgeSeconds : 3600 ,
255+ Method : []string {"GET" , "POST" },
256+ Origin : []string {"*" },
257+ ResponseHeader : []string {"FOO" },
258+ },
259+ },
260+ Acl : []* raw.BucketAccessControl {
261+ {
Bucket :
bucketName ,
Role :
"READER" ,
Email :
"[email protected] " ,
Entity :
"allUsers" },
262+ },
263+ LocationType : "dual-region" ,
264+ Encryption : & raw.BucketEncryption {DefaultKmsKeyName : "key" },
265+ Logging : & raw.BucketLogging {LogBucket : "lb" , LogObjectPrefix : "p" },
266+ Website : & raw.BucketWebsite {MainPageSuffix : "mps" , NotFoundPage : "404" },
267+ }
268+ return rb
269+ }
270+
271+ func getObjectFile () string {
272+ return `
273+ apiVersion: source.toolkit.fluxcd.io/v1beta1
274+ kind: Bucket
275+ metadata:
276+ name: podinfo
277+ namespace: default
278+ spec:
279+ interval: 5m
280+ provider: aws
281+ bucketName: podinfo
282+ endpoint: s3.amazonaws.com
283+ region: us-east-1
284+ timeout: 30s
285+ `
286+ }
0 commit comments