Skip to content

Commit a46b0f5

Browse files
pa250194squaremo
authored andcommitted
Added Tests to GCP provider
Signed-off-by: pa250194 <[email protected]>
1 parent 1fae4f6 commit a46b0f5

File tree

3 files changed

+251
-296
lines changed

3 files changed

+251
-296
lines changed

pkg/gcp/gcp.go

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,26 +49,10 @@ var (
4949
ErrorObjectDoesNotExist = errors.New("object does not exist")
5050
)
5151

52-
type Client interface {
53-
Bucket(string) *gcpStorage.BucketHandle
54-
Close() error
55-
}
56-
57-
type BucketHandle interface {
58-
Attrs(context.Context) (*gcpStorage.BucketAttrs, error)
59-
Object(string) *gcpStorage.ObjectHandle
60-
Objects(context.Context, *gcpStorage.Query) *gcpStorage.ObjectIterator
61-
}
62-
63-
type ObjectHandle interface {
64-
Attrs(context.Context) (*gcpStorage.ObjectAttrs, error)
65-
NewRangeReader(context.Context, int64, int64) (*gcpStorage.Reader, error)
66-
}
67-
6852
type GCPClient struct {
6953
// client for interacting with the Google Cloud
7054
// Storage APIs.
71-
Client
55+
*gcpStorage.Client
7256
// startRange is the starting read value for
7357
// reading the object from bucket.
7458
StartRange int64

pkg/gcp/gcp_test.go

Lines changed: 250 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -18,115 +18,269 @@ package gcp_test
1818

1919
import (
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

3449
var (
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

Comments
 (0)