gcs_client.go
Overview
The gcs_client.go file provides an abstraction layer and wrapper implementations for Google Cloud Storage (GCS) client components. Its primary purpose is to define interfaces representing GCS client, bucket, object, object iterator, and writer behaviors to enable flexible mocking during testing. The file also provides concrete wrapper structs that adapt the official Google Cloud Storage Go client types (storage.Client, storage.BucketHandle, storage.ObjectHandle, storage.ObjectIterator, and storage.Writer) to these interfaces. This design facilitates unit testing by allowing dependency injection of mock clients without requiring actual GCS interactions.
This file is a foundational utility in the Google Cloud Storage Service implementation within the broader Artifact Management system, where it abstracts GCS operations such as uploading, downloading, listing, and deleting versioned blobs as artifacts.
Interfaces
The file declares several key interfaces that define the behavior expected from GCS client components:
gcsClient
type gcsClient interface {
bucket(name string) gcsBucket
}
Represents a GCS client capable of returning a handle to a bucket.
Method:
bucket(name string) gcsBucket: Returns agcsBucketinterface for the specified bucket name.
gcsBucket
type gcsBucket interface {
object(name string) gcsObject
objects(ctx context.Context, q *storage.Query) gcsObjectIterator
}
Represents a GCS bucket handle.
Methods:
object(name string) gcsObject: Returns a handle to a GCS object within the bucket.objects(ctx context.Context, q *storage.Query) gcsObjectIterator: Returns an iterator over objects in the bucket matching a query.
gcsObject
type gcsObject interface {
newWriter(ctx context.Context) gcsWriter
newReader(ctx context.Context) (io.ReadCloser, error)
delete(ctx context.Context) error
attrs(ctx context.Context) (*storage.ObjectAttrs, error)
}
Represents a GCS object handle (an individual blob).
Methods:
newWriter(ctx context.Context) gcsWriter: Returns a writer for uploading to the object.newReader(ctx context.Context) (io.ReadCloser, error): Returns a reader for downloading the object.delete(ctx context.Context) error: Deletes the object.attrs(ctx context.Context) (*storage.ObjectAttrs, error): Retrieves metadata attributes for the object.
gcsObjectIterator
type gcsObjectIterator interface {
next() (*storage.ObjectAttrs, error)
}
Represents an iterator over GCS objects.
Method:
next() (*storage.ObjectAttrs, error): Retrieves the next object's attributes or returns an error.
gcsWriter
type gcsWriter interface {
io.Writer
io.Closer
SetContentType(string)
}
Represents a writer to upload data to GCS.
Embeds standard
io.Writerandio.Closerinterfaces.Additional method:
SetContentType(string): Sets the MIME content type for the object being uploaded.
Wrapper Implementations
Concrete wrapper types adapt the official GCS client types to the above interfaces, enabling the use of interface-typed dependencies and mocking.
gcsClientWrapper
type gcsClientWrapper struct {
client *storage.Client
}
Wraps a
storage.Client.Implements
gcsClient.Method:
bucket(name string) gcsBucket: Returns agcsBucketWrapperwrapping the bucket handle.
gcsBucketWrapper
type gcsBucketWrapper struct {
bucket *storage.BucketHandle
}
Wraps a
storage.BucketHandle.Implements
gcsBucket.Methods:
object(name string) gcsObject: Returns agcsObjectWrapperfor the named object.objects(ctx context.Context, q *storage.Query) gcsObjectIterator: Returns agcsObjectIteratorWrapperwrapping the real GCS iterator.
gcsObjectWrapper
type gcsObjectWrapper struct {
object *storage.ObjectHandle
}
Wraps a
storage.ObjectHandle.Implements
gcsObject.Methods:
newWriter(ctx context.Context) gcsWriter: Returns agcsWriterWrapperwrapping astorage.Writer.newReader(ctx context.Context) (io.ReadCloser, error): Delegates tostorage.ObjectHandle.NewReader.delete(ctx context.Context) error: Delegates tostorage.ObjectHandle.Delete.attrs(ctx context.Context) (*storage.ObjectAttrs, error): Delegates tostorage.ObjectHandle.Attrs.
gcsObjectIteratorWrapper
type gcsObjectIteratorWrapper struct {
iter *storage.ObjectIterator
}
Wraps a
storage.ObjectIterator.Implements
gcsObjectIterator.Method:
next() (*storage.ObjectAttrs, error): Delegates tostorage.ObjectIterator.Next.
gcsWriterWrapper
type gcsWriterWrapper struct {
w *storage.Writer
}
Wraps a
storage.Writer.Implements
gcsWriter.Methods:
Write(p []byte) (n int, err error): Writes bytes to the underlying writer.Close() error: Closes the writer, finalizing the upload.SetContentType(cType string): Sets theContentTypeproperty on the underlying writer.
Implementation Details and Usage Examples
Mocking and Testability
By defining interfaces for GCS client components, this file supports injecting mock implementations during unit tests, enabling testing of artifact storage logic without actual GCS dependencies. The interfaces mirror the minimal subset of GCS client functionality required by the Google Cloud Storage Service.
Wrapper Pattern
The wrappers hold pointers to the real GCS client types and implement the interface methods by forwarding calls to the underlying GCS client. This preserves all GCS client behaviors while enabling interface substitution.
Example: Obtaining an Object Writer
var client gcsClient = &gcsClientWrapper{client: realGCSClient}
bucket := client.bucket("my-bucket")
obj := bucket.object("path/to/object")
writer := obj.newWriter(ctx)
writer.SetContentType("application/octet-stream")
_, err := writer.Write(data)
if err != nil {
// handle error
}
err = writer.Close()
if err != nil {
// handle error
}
This example illustrates the process of writing data to a GCS object using the interface abstraction and wrapper.
Interface Compliance Assertions
At the end of the file, the code includes compile-time assertions verifying that the wrappers implement their respective interfaces:
var (
_ gcsClient = (*gcsClientWrapper)(nil)
_ gcsBucket = (*gcsBucketWrapper)(nil)
_ gcsObject = (*gcsObjectWrapper)(nil)
_ gcsObjectIterator = (*gcsObjectIteratorWrapper)(nil)
_ gcsWriter = (*gcsWriterWrapper)(nil)
)
This ensures that any signature mismatches are caught during compilation.
Interaction with Other Components
This file is a low-level utility used by the Google Cloud Storage Service implementation in the Artifact Management module.
The
gcsClientWrapperand related wrappers provide the abstraction needed to perform versioned artifact operations such as save, load, delete, and list on GCS buckets and objects.Higher-level artifact service code depends on these abstractions to handle streaming uploads/downloads (
gcsWriter,io.ReadCloser), object metadata access, and iteration over stored blobs, enabling version management and scoped naming.The interface design facilitates substituting real GCS clients with in-memory or fake clients during testing, improving test isolation and reliability.
Mermaid Diagram: Interface and Wrapper Structure
classDiagram
class gcsClient {
+bucket(name)
}
class gcsBucket {
+object(name)
+objects(ctx, q)
}
class gcsObject {
+newWriter(ctx)
+newReader(ctx)
+delete(ctx)
+attrs(ctx)
}
class gcsObjectIterator {
+next()
}
class gcsWriter {
+Write()
+Close()
+SetContentType()
}
class gcsClientWrapper {
-client
+bucket(name)
}
class gcsBucketWrapper {
-bucket
+object(name)
+objects(ctx, q)
}
class gcsObjectWrapper {
-object
+newWriter(ctx)
+newReader(ctx)
+delete(ctx)
+attrs(ctx)
}
class gcsObjectIteratorWrapper {
-iter
+next()
}
class gcsWriterWrapper {
-w
+Write()
+Close()
+SetContentType()
}
gcsClient <|.. gcsClientWrapper
gcsBucket <|.. gcsBucketWrapper
gcsObject <|.. gcsObjectWrapper
gcsObjectIterator <|.. gcsObjectIteratorWrapper
gcsWriter <|.. gcsWriterWrapper
gcsClientWrapper --> gcsBucketWrapper : bucket()
gcsBucketWrapper --> gcsObjectWrapper : object()
gcsBucketWrapper --> gcsObjectIteratorWrapper : objects()
gcsObjectWrapper --> gcsWriterWrapper : newWriter()
Summary
This file defines the interfaces and adapter wrappers for Google Cloud Storage client components, enabling mocking and abstraction for artifact storage operations. It provides the building blocks for the Google Cloud Storage Service to implement versioned, scoped artifact persistence with GCS. The design ensures testability by abstracting the real GCS client behind interfaces while preserving all essential operations such as object write/read/delete, iteration, and metadata access.