Skip to content

Commit

Permalink
GCS testhelper can now list stored objects.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 634534468
  • Loading branch information
evan-gordon authored and copybara-github committed May 20, 2024
1 parent deb247d commit c551d42
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 18 deletions.
15 changes: 14 additions & 1 deletion gcs/gcs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,24 @@ func TestGCSIsBucketInProjectId(t *testing.T) {
}
for _, tc := range cases {
server := testhelpers.NewGCSServer(t)
ctx := context.Background()

gcsClient, err := NewClient(context.Background(), tc.bucketName, server.URL())
gcsClient, err := NewClient(ctx, tc.bucketName, server.URL())
if err != nil {
t.Error("Unexpected error when getting NewClient: ", err)
}
if tc.wantIsBucketInProject {
// Add a file to the bucket so that the bucket is created.
writeCloser := gcsClient.GetFileWriter(ctx, "testFile")
_, err = writeCloser.Write([]byte("Hello World"))
if err != nil {
t.Error("Unexpected error when writing file: ", err)
}
err = writeCloser.Close()
if err != nil {
t.Error("Unexpected error when closing file and uploading data to GCS: ", err)
}
}

gotIsBucketInProject, err := gcsClient.IsBucketInProject(context.Background(), "project")
if err != nil {
Expand Down
84 changes: 67 additions & 17 deletions testhelpers/gcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"mime/multipart"
"net/http"
"net/http/httptest"
"regexp"
"slices"
"strings"
"sync"
"testing"
Expand Down Expand Up @@ -107,36 +109,84 @@ func (gs *GCSServer) URL() string {
}

const uploadPathPrefix = "/upload/storage/v1/b/"
const listPathPrefix = "/b"

// this should match for paths like:
// /b - list buckets
// /b/bucketName/o - list objects
var listPathRegex = regexp.MustCompile(`^/b(?:/.*/o|)$`)

func (gs *GCSServer) handleHTTP(w http.ResponseWriter, req *http.Request) {
if strings.HasPrefix(req.URL.Path, uploadPathPrefix) {
gs.handleUpload(w, req)
} else if strings.HasPrefix(req.URL.Path, listPathPrefix) {
} else if listPathRegex.MatchString(req.URL.Path) {
gs.handleList(w, req)
} else {
gs.handleDownload(w, req)
}
}

// A simple struct to hold the json response for the list buckets and objects calls.
type objectIterResponse struct {
Kind string
NextPageToken string
Items []objectAttrsResponse
}

// Holds the file or bucket attributes for the list buckets / objects calls.
type objectAttrsResponse struct {
Kind string
ID string
Name string
Bucket string
Prefix string
}

// handleList handles the list buckets and list objects calls.
// Does not support pagination (will only ever return a single item).
// TODO b/341405229 - add support for arbitrary buckets.
func (gs *GCSServer) handleList(w http.ResponseWriter, req *http.Request) {
r := struct {
Kind string
NextPageToken string
Items []struct {
Kind string
ID string
Name string
var r objectIterResponse
if req.URL.Path == "/b" {
// List all buckets.
r = objectIterResponse{
Kind: "storage#buckets",
Items: []objectAttrsResponse{},
}
for key := range gs.objects {
currBucket := objectAttrsResponse{
Kind: "storage#bucket",
ID: key.bucket,
Name: key.bucket,
}
if slices.Contains(r.Items, currBucket) {
continue
}
r.Items = append(r.Items, currBucket)
}
}{
Kind: "storage#buckets",
NextPageToken: "",
Items: []struct {
Kind string
ID string
Name string
}{{Kind: "storage#bucket", ID: "bucketName", Name: "bucketName"}},
} else if strings.HasPrefix(req.URL.Path, "/b/") && strings.HasSuffix(req.URL.Path, "/o") {
// List all objects in a bucket.
bucketName := strings.Split(strings.TrimPrefix(req.URL.Path, "/b/"), "/")[0]
// "/b/bucketName/o"
r = objectIterResponse{
Kind: "storage#objects",
Items: []objectAttrsResponse{},
}
queryPrefix := req.URL.Query().Get("prefix")
// find all objects in the server that match the prefix.
for key := range gs.objects {
if strings.Contains(key.name, queryPrefix) && key.bucket == bucketName {
r.Items = append(r.Items, objectAttrsResponse{
Kind: "storage#object",
Name: key.name,
Bucket: bucketName,
Prefix: queryPrefix,
})
}
}
} else {
gs.t.Fatalf("unrecognised list endpoint %s", req.URL.Path)
}

j, err := json.Marshal(r)
if err != nil {
gs.t.Fatalf("failed to marshal json in GCS handleList: %v", err)
Expand Down

0 comments on commit c551d42

Please sign in to comment.