From 5e1dc48def3cc9d44d5a25fa3dddaec0cc9fcd0d Mon Sep 17 00:00:00 2001 From: Venkat Venkatasubramanian Date: Mon, 29 Jan 2024 17:44:24 -0800 Subject: [PATCH] Update go client to support default tags --- client/configuration.go | 28 +++++-- client/configuration_test.go | 133 +++++++++++++++++++++++++++++++++ internal/configuration.go | 12 +++ internal/configuration_test.go | 76 +++++++++++++++++++ 4 files changed, 244 insertions(+), 5 deletions(-) create mode 100644 client/configuration_test.go create mode 100644 internal/configuration_test.go diff --git a/client/configuration.go b/client/configuration.go index f2e404d..b12640e 100644 --- a/client/configuration.go +++ b/client/configuration.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "os" + "strings" "github.com/infobloxopen/bloxone-go-client/internal" ) @@ -18,11 +19,11 @@ const ( HeaderClient = "x-infoblox-client" HeaderSDK = "x-infoblox-sdk" HeaderAuthorization = "Authorization" + version = "0.1" + sdkIdentifier = "golang-sdk" + clientIdentifier = "automation" ) -const version = "0.1" -const sdkIdentifier = "golang-sdk" - // Configuration stores the configuration of the API client type Configuration struct { // ClientName is the name of the client using the SDK. @@ -43,6 +44,9 @@ type Configuration struct { // HTTPClient to use for the SDK. // Optional. The default HTTPClient will be used if not provided. HTTPClient *http.Client + + // Default global tags the client can set for all requests. + DefaultTags map[string]string } func (c Configuration) internal(basePath string) (*internal.Configuration, error) { @@ -83,12 +87,26 @@ func (c Configuration) internal(basePath string) (*internal.Configuration, error userAgent := fmt.Sprintf("bloxone-%s/%s", sdkIdentifier, version) - return &internal.Configuration{ + ic := &internal.Configuration{ DefaultHeader: defaultHeaders, UserAgent: userAgent, Debug: false, OperationServers: nil, Servers: []internal.ServerConfiguration{{URL: cspURL}}, HTTPClient: httpClient, - }, nil + DefaultTags: make(map[string]string), + } + // Add default tags set + if c.DefaultTags != nil { + ic.AddDefaultTags(c.DefaultTags) + } + + // setting up custom tag to identify the client + dfTags := make(map[string]string) + // Extract client from ClientName string + // Format: /version#commit + dfTags[clientIdentifier] = strings.Split(c.ClientName, "/")[0] + ic.AddDefaultTags(dfTags) + + return ic, nil } diff --git a/client/configuration_test.go b/client/configuration_test.go new file mode 100644 index 0000000..060d0f6 --- /dev/null +++ b/client/configuration_test.go @@ -0,0 +1,133 @@ +package client + +import ( + "fmt" + "net/http" + "os" + "reflect" + "testing" + + "github.com/infobloxopen/bloxone-go-client/internal" +) + +func TestConfiguration_internal(t *testing.T) { + type fields struct { + ClientName string + CSPURL string + APIKey string + HTTPClient *http.Client + DefaultTags map[string]string + } + type args struct { + basePath string + } + tests := []struct { + name string + fields fields + args args + want *internal.Configuration + wantErr bool + }{ + { + "empty API key", + fields{ + APIKey: "", + }, + args{basePath: ""}, + nil, + true, + }, + {"empty clientName", + fields{ + ClientName: "", + }, + args{basePath: ""}, + nil, + true, + }, + { + "empty DefaultTags", + fields{ + ClientName: "terraform/v1.1#yug278872h", + APIKey: "12323455", + }, + args{basePath: ""}, + &internal.Configuration{ + DefaultHeader: map[string]string{ + HeaderAuthorization: "Token 12323455", + HeaderClient: "terraform/v1.1#yug278872h", + HeaderSDK: sdkIdentifier, + }, + Debug: false, + UserAgent: fmt.Sprintf("bloxone-%s/%s", sdkIdentifier, version), + Servers: []internal.ServerConfiguration{{URL: "https://csp.infoblox.com"}}, + HTTPClient: http.DefaultClient, + DefaultTags: map[string]string{ + clientIdentifier: "terraform", + }, + }, + false, + }, + { + "DefaultTags provided", + fields{ + CSPURL: "https://stage.csp.infoblox.com", + ClientName: "terraformv1.1#yug278872h", + APIKey: "12323455", + DefaultTags: map[string]string{ + "site": "A", + "env": "test", + }, + }, + args{basePath: ""}, + &internal.Configuration{ + DefaultHeader: map[string]string{ + HeaderAuthorization: "Token 12323455", + HeaderClient: "terraformv1.1#yug278872h", + HeaderSDK: sdkIdentifier, + }, + Debug: false, + UserAgent: fmt.Sprintf("bloxone-%s/%s", sdkIdentifier, version), + Servers: []internal.ServerConfiguration{{URL: "https://stage.csp.infoblox.com"}}, + HTTPClient: http.DefaultClient, + DefaultTags: map[string]string{ + clientIdentifier: "terraformv1.1#yug278872h", + "site": "A", + "env": "test", + }, + }, + false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var curEnvVal string + c := Configuration{ + ClientName: tt.fields.ClientName, + CSPURL: tt.fields.CSPURL, + APIKey: tt.fields.APIKey, + HTTPClient: tt.fields.HTTPClient, + DefaultTags: tt.fields.DefaultTags, + } + if c.CSPURL != "" { + curEnvVal = os.Getenv(ENVBloxOneCSPURL) + t.Setenv(ENVBloxOneCSPURL, c.CSPURL) + } + + got, err := c.internal(tt.args.basePath) + if (err != nil) != tt.wantErr { + t.Errorf("internal() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("internal() got = %v, want %v", got, tt.want) + } + t.Cleanup(func() { + // Set it to the value prior to executing the test + if c.CSPURL != "" { + t.Setenv(ENVBloxOneCSPURL, curEnvVal) + } + }) + }) + } +} diff --git a/internal/configuration.go b/internal/configuration.go index 2a34dce..45fa11c 100644 --- a/internal/configuration.go +++ b/internal/configuration.go @@ -73,6 +73,7 @@ type Configuration struct { Servers ServerConfigurations OperationServers map[string]ServerConfigurations HTTPClient *http.Client + DefaultTags map[string]string } // NewConfiguration returns a new Configuration object @@ -89,6 +90,7 @@ func NewConfiguration() *Configuration { }, }, OperationServers: map[string]ServerConfigurations{}, + DefaultTags: make(map[string]string), } return cfg } @@ -98,6 +100,16 @@ func (c *Configuration) AddDefaultHeader(key string, value string) { c.DefaultHeader[key] = value } +func (c *Configuration) AddDefaultTags(m map[string]string) { + for k, v := range m { + c.DefaultTags[k] = v + } +} + +func (c *Configuration) GetDefaultTags() map[string]string { + return c.DefaultTags +} + // URL formats template on a index using given variables func (sc ServerConfigurations) URL(index int, variables map[string]string) (string, error) { if index < 0 || len(sc) <= index { diff --git a/internal/configuration_test.go b/internal/configuration_test.go new file mode 100644 index 0000000..aacf059 --- /dev/null +++ b/internal/configuration_test.go @@ -0,0 +1,76 @@ +package internal + +import ( + "reflect" + "testing" +) + +func TestConfiguration_AddDefaultTags(t *testing.T) { + type fields struct { + DefaultTags map[string]string + } + type args struct { + m map[string]string + } + tests := []struct { + name string + fields fields + args args + expected map[string]string + }{ + { + name: "empty fields", + fields: fields{ + DefaultTags: map[string]string{}, + }, + args: args{ + m: map[string]string{}, + }, + expected: map[string]string{}, + }, { + name: "existing fields", + fields: fields{ + DefaultTags: map[string]string{ + "key1": "value1", + }, + }, + args: args{ + m: map[string]string{ + "key2": "value2", + }, + }, + expected: map[string]string{ + "key1": "value1", + "key2": "value2", + }, + }, + { + name: "overriding fields", + fields: fields{ + DefaultTags: map[string]string{ + "key1": "value1", + }, + }, + args: args{ + m: map[string]string{ + "key1": "value2", + }, + }, + expected: map[string]string{ + "key1": "value2", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Configuration{ + DefaultTags: tt.fields.DefaultTags, + } + c.AddDefaultTags(tt.args.m) + if !reflect.DeepEqual(c.GetDefaultTags(), tt.expected) { + t.Errorf("internal() want = %v, got = %v", tt.expected, c.GetDefaultTags()) + return + } + }) + } +}