Skip to content

Commit

Permalink
test(stub): added tests for stubs
Browse files Browse the repository at this point in the history
Signed-off-by: Mateusz Urbanek <[email protected]>
  • Loading branch information
shanduur authored and shanduur-akamai committed Dec 5, 2023
1 parent e28078d commit 34a468a
Show file tree
Hide file tree
Showing 9 changed files with 1,021 additions and 123 deletions.
1 change: 1 addition & 0 deletions .github/workflows/99-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:

env:
REGISTRY: docker.io
IMAGE: linode/linode-cosi-driver

jobs:
docker:
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.21
require (
github.com/go-resty/resty/v2 v2.9.1
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1
github.com/linode/linodego v1.25.0
github.com/linode/linodego v1.25.1-0.20231205171049-8990c63f4891
google.golang.org/grpc v1.59.0
sigs.k8s.io/container-object-storage-interface-spec v0.1.0
)
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1 h1:HcUWd006luQPljE73d5sk+/VgYPGUReEVz2y1/qylwY=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1/go.mod h1:w9Y7gY31krpLmrVU5ZPG9H7l9fZuRu5/3R3S3FMtVQ4=
github.com/linode/linodego v1.25.0 h1:zYMz0lTasD503jBu3tSRhzEmXHQN1zptCw5o71ibyyU=
github.com/linode/linodego v1.25.0/go.mod h1:BMZI0pMM/YGjBis7pIXDPbcgYfCZLH0/UvzqtsGtG1c=
github.com/linode/linodego v1.25.1-0.20231205171049-8990c63f4891 h1:BhRySi+szC59OozqpC/MarQ0M+e4ydO7PDEptAXw88o=
github.com/linode/linodego v1.25.1-0.20231205171049-8990c63f4891/go.mod h1:kD7Bf1piWg/AXb9TA0ThAVwzR+GPf6r2PvbTbVk7PMA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
Expand Down
7 changes: 5 additions & 2 deletions pkg/linodeclient/linodeclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ import (
"github.com/linode/linodego"
)

// LinodeClient defines a subset of all Linode Client methods required by COSI.
type LinodeClient interface {
// Client defines a subset of all Linode Client methods required by COSI.
type Client interface {
CreateObjectStorageBucket(context.Context, linodego.ObjectStorageBucketCreateOptions) (*linodego.ObjectStorageBucket, error)
GetObjectStorageBucket(context.Context, string, string) (*linodego.ObjectStorageBucket, error)
DeleteObjectStorageBucket(context.Context, string, string) error

GetObjectStorageBucketAccess(context.Context, string, string) (*linodego.ObjectStorageBucketAccess, error)
UpdateObjectStorageBucketAccess(context.Context, string, string, linodego.ObjectStorageBucketUpdateAccessOptions) error

CreateObjectStorageKey(context.Context, linodego.ObjectStorageKeyCreateOptions) (*linodego.ObjectStorageKey, error)
ListObjectStorageKeys(context.Context, *linodego.ListOptions) ([]linodego.ObjectStorageKey, error)
GetObjectStorageKey(context.Context, int) (*linodego.ObjectStorageKey, error)
Expand Down
189 changes: 133 additions & 56 deletions pkg/linodeclient/stubclient/stubclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import (
"context"
"errors"
"fmt"
"math/rand"
"net/http"

"github.com/linode/linode-cosi-driver/pkg/linodeclient"
"github.com/linode/linodego"
)

Expand All @@ -40,36 +40,38 @@ var ErrUnexpectedError = errors.New("unexpected error")
// Client is a stub implementation of the linodeclient.LinodeClient interface.
// It provides placeholder methods for object storage operations.
type Client struct {
objectStorageBuckets map[string]*linodego.ObjectStorageBucket
objectStorageKeys map[int]*linodego.ObjectStorageKey
objectStorageBuckets map[string]*linodego.ObjectStorageBucket
objectStorageBucketAccesses map[string]*linodego.ObjectStorageBucketAccess
objectStorageKeys map[int]*linodego.ObjectStorageKey
}

var _ linodeclient.Client = (*Client)(nil)

// New creates a new instance of the Client with optional object storage objects.
// This is a stub function.
func New(objs ...interface{}) *Client {
func New(opts ...Option) *Client {
c := &Client{
objectStorageBuckets: make(map[string]*linodego.ObjectStorageBucket),
objectStorageKeys: make(map[int]*linodego.ObjectStorageKey),
objectStorageBuckets: make(map[string]*linodego.ObjectStorageBucket),
objectStorageBucketAccesses: make(map[string]*linodego.ObjectStorageBucketAccess),
objectStorageKeys: make(map[int]*linodego.ObjectStorageKey),
}

for _, obj := range objs {
switch obj := obj.(type) {
case *linodego.ObjectStorageBucket:
key := fmt.Sprintf("%s/%s", obj.Cluster, obj.Label)
c.objectStorageBuckets[key] = obj

case *linodego.ObjectStorageKey:
key := obj.ID
c.objectStorageKeys[key] = obj

default:
panic(fmt.Sprintf("unrecognized type: %T", obj))
}
for _, opt := range opts {
opt(c)
}

return c
}

func validateACL(acl linodego.ObjectStorageACL) bool {
switch acl {
case linodego.ACLPrivate, linodego.ACLAuthenticatedRead, linodego.ACLPublicRead, linodego.ACLPublicReadWrite:
return true
default:
return false
}
}

// CreateObjectStorageBucket is a stub function that stubs the behavior of CreateObjectStorageBucket call from linodego.Client.
func (c *Client) CreateObjectStorageBucket(ctx context.Context, opt linodego.ObjectStorageBucketCreateOptions) (*linodego.ObjectStorageBucket, error) {
if v := ctx.Value(ForcedFailure); v != nil {
Expand All @@ -83,21 +85,36 @@ func (c *Client) CreateObjectStorageBucket(ctx context.Context, opt linodego.Obj

key := fmt.Sprintf("%s/%s", opt.Cluster, opt.Label)

obj, ok := c.objectStorageBuckets[key]
bucket, ok := c.objectStorageBuckets[key]
if ok {
return obj, nil
return bucket, nil
}

obj = &linodego.ObjectStorageBucket{
Label: opt.Label,
Cluster: opt.Cluster,
if !validateACL(opt.ACL) {
return nil, &linodego.Error{
Code: http.StatusBadRequest,
}
}

// stub discards ACL and cors settings
bucket = &linodego.ObjectStorageBucket{
Label: opt.Label,
Cluster: opt.Cluster,
Hostname: fmt.Sprintf("%s.linodeobjects.com", opt.Label),
}
c.objectStorageBuckets[key] = bucket

c.objectStorageBuckets[key] = obj
corsEnabled := false
if opt.CorsEnabled != nil {
corsEnabled = *opt.CorsEnabled
}

return obj, nil
access := &linodego.ObjectStorageBucketAccess{
ACL: opt.ACL,
CorsEnabled: corsEnabled,
}
c.objectStorageBucketAccesses[key] = access

return bucket, nil
}

// GetObjectStorageBucket is a stub function that stubs the behavior of GetObjectStorageBucket call from linodego.Client.
Expand Down Expand Up @@ -151,6 +168,69 @@ func (c *Client) DeleteObjectStorageBucket(ctx context.Context, clusterID, label
}
}

// GetObjectStorageBucketAccess is a stub function that stubs the behavior of GetObjectStorageBucketAccess call from linodego.Client.
func (c *Client) GetObjectStorageBucketAccess(ctx context.Context, clusterID, label string) (*linodego.ObjectStorageBucketAccess, error) {
if v := ctx.Value(ForcedFailure); v != nil {
switch v := v.(type) {
case error:
return nil, v
default:
return nil, ErrUnexpectedError
}
}

key := fmt.Sprintf("%s/%s", clusterID, label)

obj, ok := c.objectStorageBucketAccesses[key]
if ok {
return obj, nil
}

return nil, &linodego.Error{
Code: http.StatusNotFound,
}
}

// UpdateObjectStorageBucketAccess is a stub function that stubs the behavior of UpdateObjectStorageBucketAccess call from linodego.Client.
func (c *Client) UpdateObjectStorageBucketAccess(ctx context.Context, clusterID, label string, opt linodego.ObjectStorageBucketUpdateAccessOptions) error {
if v := ctx.Value(ForcedFailure); v != nil {
switch v := v.(type) {
case error:
return v
default:
return ErrUnexpectedError
}
}

key := fmt.Sprintf("%s/%s", clusterID, label)

access, ok := c.objectStorageBucketAccesses[key]
if !ok {
return &linodego.Error{
Code: http.StatusNotFound,
}
}

corsEnabled := access.CorsEnabled
if opt.CorsEnabled != nil {
corsEnabled = *opt.CorsEnabled
}

if !validateACL(opt.ACL) {
return &linodego.Error{
Code: http.StatusBadRequest,
}
}

access = &linodego.ObjectStorageBucketAccess{
ACL: opt.ACL,
CorsEnabled: corsEnabled,
}
c.objectStorageBucketAccesses[key] = access

return nil
}

// CreateObjectStorageKey is a stub function that stubs the behavior of CreateObjectStorageKey call from linodego.Client.
func (c *Client) CreateObjectStorageKey(ctx context.Context, opt linodego.ObjectStorageKeyCreateOptions) (*linodego.ObjectStorageKey, error) {
if v := ctx.Value(ForcedFailure); v != nil {
Expand All @@ -163,7 +243,7 @@ func (c *Client) CreateObjectStorageKey(ctx context.Context, opt linodego.Object
}

limited := false
if opt.BucketAccess != nil && len(*opt.BucketAccess) == 0 {
if opt.BucketAccess != nil && len(*opt.BucketAccess) != 0 {
limited = true
}

Expand All @@ -175,15 +255,8 @@ func (c *Client) CreateObjectStorageKey(ctx context.Context, opt linodego.Object
Limited: limited,
}

for {
rid := rand.Int() // #nosec G404
if _, ok := c.objectStorageKeys[rid]; !ok {
obj.ID = rid
c.objectStorageKeys[rid] = obj

break
}
}
id := len(c.objectStorageKeys)
c.objectStorageKeys[id] = obj

return obj, nil
}
Expand All @@ -199,36 +272,40 @@ func (c *Client) ListObjectStorageKeys(ctx context.Context, opt *linodego.ListOp
}
}

var list []linodego.ObjectStorageKey
list := []linodego.ObjectStorageKey{}

for _, obj := range c.objectStorageKeys {
list = append(list, *obj)
}

startIndex := (opt.Page - 1) * opt.PageSize
endIndex := startIndex + opt.PageSize
if opt != nil && opt.PageOptions != nil {
if opt.PageSize < 0 {
opt.PageSize = 100
}

if endIndex <= 0 {
endIndex = len(list) - 1
}
if opt.Page <= 0 {
opt.Page = 1
}

// check for out-of-bounds
if startIndex >= len(list) {
return nil, nil
}
startIndex := (opt.Page - 1) * opt.PageSize

// adjust endIndex if it exceeds the length of the slice
if endIndex > len(list) {
endIndex = len(list)
}
endIndex := startIndex + opt.PageSize

// check for out-of-bounds
if startIndex >= len(list) {
return []linodego.ObjectStorageKey{}, nil
}

// adjust endIndex if it exceeds the length of the slice
if endIndex > len(list) {
endIndex = len(list)
}

// fail if start index is larger than end index
if startIndex > endIndex {
return nil, nil
// return the specified page
return list[startIndex:endIndex], nil
}

// return the specified page
return list[startIndex:endIndex], nil
return list, nil
}

// GetObjectStorageKey is a stub function that stubs the behavior of GetObjectStorageKey call from linodego.Client.
Expand Down
Loading

0 comments on commit 34a468a

Please sign in to comment.