From 1cdcdbb81e0c60c49ac4cd98c5fcdc04c5ef7232 Mon Sep 17 00:00:00 2001 From: Vidya Reddy <59590642+Vidya2606@users.noreply.github.com> Date: Tue, 2 Apr 2024 23:38:31 -0700 Subject: [PATCH 1/3] Adding the client interface and unit tests for getTenantID func --- cmd/setup-gh.go | 17 +++++++++++- go.mod | 3 +- go.sum | 2 ++ pkg/providers/azure.go | 24 ++++++++-------- pkg/providers/azure_test.go | 48 ++++++++++++++++++++++++++++++++ pkg/providers/mock/azure.go | 55 +++++++++++++++++++++++++++++++++++++ 6 files changed, 134 insertions(+), 15 deletions(-) create mode 100644 pkg/providers/azure_test.go create mode 100644 pkg/providers/mock/azure.go diff --git a/cmd/setup-gh.go b/cmd/setup-gh.go index 2a719726..b302dcc6 100644 --- a/cmd/setup-gh.go +++ b/cmd/setup-gh.go @@ -4,6 +4,8 @@ import ( "context" "errors" "fmt" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription" + "github.com/Azure/draft/pkg/cred" "github.com/manifoldco/promptui" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -24,11 +26,24 @@ func newSetUpCmd() *cobra.Command { application and service principle, and will configure that application to trust github.`, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() + + azCred, err := cred.GetCred() + if err != nil { + return fmt.Errorf("getting credentials: %w", err) + } + + client, err := armsubscription.NewTenantsClient(azCred, nil) + if err != nil { + return fmt.Errorf("creating tenants client: %w", err) + } + + sc.AzTenantClient = client + fillSetUpConfig(sc) s := spinner.CreateSpinner("--> Setting up Github OIDC...") s.Start() - err := runProviderSetUp(ctx, sc, s) + err = runProviderSetUp(ctx, sc, s) s.Stop() if err != nil { return err diff --git a/go.mod b/go.mod index 23d0dd84..fda29140 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/Azure/draft go 1.18 require ( + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription v1.2.0 github.com/briandowns/spinner v1.18.1 @@ -17,6 +18,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.4 + go.uber.org/mock v0.4.0 golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e gopkg.in/yaml.v3 v3.0.1 helm.sh/helm/v3 v3.11.1 @@ -28,7 +30,6 @@ require ( ) require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.0 // indirect diff --git a/go.sum b/go.sum index 5d245082..e8046c62 100644 --- a/go.sum +++ b/go.sum @@ -319,6 +319,8 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= diff --git a/pkg/providers/azure.go b/pkg/providers/azure.go index 2f81d029..53a7dd53 100644 --- a/pkg/providers/azure.go +++ b/pkg/providers/azure.go @@ -5,11 +5,11 @@ import ( "encoding/json" "errors" "fmt" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "os/exec" "time" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription" - "github.com/Azure/draft/pkg/cred" "github.com/Azure/draft/pkg/spinner" bo "github.com/cenkalti/backoff/v4" @@ -26,6 +26,7 @@ type SetUpCmd struct { tenantId string appObjectId string spObjectId string + AzTenantClient azTenantClient } func InitiateAzureOIDCFlow(ctx context.Context, sc *SetUpCmd, s spinner.Spinner) error { @@ -182,7 +183,7 @@ func (sc *SetUpCmd) assignSpRole() error { func (sc *SetUpCmd) getTenantId(ctx context.Context) error { log.Debug("getting Azure tenant ID") - tenants, err := listTenants(ctx) + tenants, err := sc.listTenants(ctx) if err != nil { return fmt.Errorf("listing tenants: %w", err) } @@ -198,21 +199,18 @@ func (sc *SetUpCmd) getTenantId(ctx context.Context) error { return nil } -func listTenants(ctx context.Context) ([]armsubscription.TenantIDDescription, error) { +//go:generate mockgen -source=./azure.go -destination=./mock/azure.go . +type azTenantClient interface { + NewListPager(options *armsubscription.TenantsClientListOptions) *runtime.Pager[armsubscription.TenantsClientListResponse] +} + +func (sc *SetUpCmd) listTenants(ctx context.Context) ([]armsubscription.TenantIDDescription, error) { log.Debug("listing Azure subscriptions") - cred, err := cred.GetCred() - if err != nil { - return nil, fmt.Errorf("getting credentials: %w", err) - } + var tenants []armsubscription.TenantIDDescription - client, err := armsubscription.NewTenantsClient(cred, nil) - if err != nil { - return nil, fmt.Errorf("creating tenants client: %w", err) - } + pager := sc.AzTenantClient.NewListPager(nil) - var tenants []armsubscription.TenantIDDescription - pager := client.NewListPager(nil) for pager.More() { page, err := pager.NextPage(ctx) if err != nil { diff --git a/pkg/providers/azure_test.go b/pkg/providers/azure_test.go new file mode 100644 index 00000000..bf7bba75 --- /dev/null +++ b/pkg/providers/azure_test.go @@ -0,0 +1,48 @@ +package providers + +import ( + "context" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription" + mock_providers "github.com/Azure/draft/pkg/providers/mock" + "go.uber.org/mock/gomock" + "testing" +) + +func TestGetTenantId(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + testId := "00000000-0000-0000-0000-000000000000" + testTenantId := "/tenants/00000000-0000-0000-0000-000000000000" + testNextLink := "https://pkg.go.dev/github.com" + testTenantDesc := armsubscription.TenantIDDescription{ID: &testId, TenantID: &testTenantId} + testTenantDescArray := []*armsubscription.TenantIDDescription{&testTenantDesc} + testTenantListResult := armsubscription.TenantListResult{NextLink: &testNextLink, Value: testTenantDescArray} + responses := []armsubscription.TenantsClientListResponse{{testTenantListResult}} + testReadResponses := 0 + testPagerHandler := runtime.PagingHandler[armsubscription.TenantsClientListResponse]{ + More: func(t armsubscription.TenantsClientListResponse) bool { return testReadResponses < len(responses) }, + Fetcher: func(ctx context.Context, response *armsubscription.TenantsClientListResponse) (armsubscription.TenantsClientListResponse, error) { + resp := responses[testReadResponses] + testReadResponses++ + return resp, nil + }, + Tracer: tracing.Tracer{}, + } + mockClient := mock_providers.NewMockazTenantClient(ctrl) + + var mockPager = runtime.NewPager[armsubscription.TenantsClientListResponse](testPagerHandler) + + mockClient.EXPECT().NewListPager(gomock.Nil()).Return(mockPager).Times(1) + + sc := &SetUpCmd{ + AzTenantClient: mockClient, + } + + err := sc.getTenantId(context.Background()) + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } +} diff --git a/pkg/providers/mock/azure.go b/pkg/providers/mock/azure.go new file mode 100644 index 00000000..7873409b --- /dev/null +++ b/pkg/providers/mock/azure.go @@ -0,0 +1,55 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./azure.go +// +// Generated by this command: +// +// mockgen -source=./azure.go -destination=./mock/azure.go . +// + +// Package mock_providers is a generated GoMock package. +package mock_providers + +import ( + reflect "reflect" + + runtime "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" + armsubscription "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription" + gomock "go.uber.org/mock/gomock" +) + +// MockazTenantClient is a mock of azTenantClient interface. +type MockazTenantClient struct { + ctrl *gomock.Controller + recorder *MockazTenantClientMockRecorder +} + +// MockazTenantClientMockRecorder is the mock recorder for MockazTenantClient. +type MockazTenantClientMockRecorder struct { + mock *MockazTenantClient +} + +// NewMockazTenantClient creates a new mock instance. +func NewMockazTenantClient(ctrl *gomock.Controller) *MockazTenantClient { + mock := &MockazTenantClient{ctrl: ctrl} + mock.recorder = &MockazTenantClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockazTenantClient) EXPECT() *MockazTenantClientMockRecorder { + return m.recorder +} + +// NewListPager mocks base method. +func (m *MockazTenantClient) NewListPager(options *armsubscription.TenantsClientListOptions) *runtime.Pager[armsubscription.TenantsClientListResponse] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewListPager", options) + ret0, _ := ret[0].(*runtime.Pager[armsubscription.TenantsClientListResponse]) + return ret0 +} + +// NewListPager indicates an expected call of NewListPager. +func (mr *MockazTenantClientMockRecorder) NewListPager(options any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListPager", reflect.TypeOf((*MockazTenantClient)(nil).NewListPager), options) +} From 9240ed11b41d0daee6b94373f46a4038a1b6718d Mon Sep 17 00:00:00 2001 From: Vidya Reddy <59590642+Vidya2606@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:15:57 -0700 Subject: [PATCH 2/3] Added more unit tests --- cmd/setup-gh.go | 2 +- go.mod | 13 +- go.sum | 23 ++++ pkg/providers/az_client.go | 15 +++ pkg/providers/azure.go | 12 +- pkg/providers/azure_test.go | 117 ++++++++++++++++-- pkg/providers/mock/{azure.go => az_client.go} | 4 +- 7 files changed, 155 insertions(+), 31 deletions(-) create mode 100644 pkg/providers/az_client.go rename pkg/providers/mock/{azure.go => az_client.go} (94%) diff --git a/cmd/setup-gh.go b/cmd/setup-gh.go index b302dcc6..ba57770c 100644 --- a/cmd/setup-gh.go +++ b/cmd/setup-gh.go @@ -37,7 +37,7 @@ application and service principle, and will configure that application to trust return fmt.Errorf("creating tenants client: %w", err) } - sc.AzTenantClient = client + sc.AzClient.AzTenantClient = client fillSetUpConfig(sc) diff --git a/go.mod b/go.mod index fda29140..3a66a3a3 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/Azure/draft go 1.18 require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription v1.2.0 github.com/briandowns/spinner v1.18.1 @@ -30,7 +30,7 @@ require ( ) require ( - github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect @@ -43,6 +43,7 @@ require ( github.com/go-openapi/swag v0.19.14 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v5 v5.0.0 // indirect + github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.9 // indirect @@ -72,10 +73,10 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xlab/treeprint v1.1.0 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/text v0.14.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index e8046c62..69e68a2c 100644 --- a/go.sum +++ b/go.sum @@ -13,10 +13,14 @@ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiy dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 h1:fb8kj/Dh4CSwgsOzHeZY4Xh68cFVbzXx+ONXGMY//4w= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0/go.mod h1:uReU2sSxZExRPBAg3qKzmAucSi51+SP1OhohieR821Q= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 h1:d81/ng9rET2YqdVkVwkb6EXeRrLJIwyGnJcAlAWKwhs= github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription v1.2.0 h1:UrGzkHueDwAWDdjQxC+QaXHd4tVCkISYE9j7fSSXF8k= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription v1.2.0/go.mod h1:qskvSQeW+cxEE2bcKYyKimB1/KiQ9xpJ99bcHY0BX6c= github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= @@ -103,6 +107,8 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -313,6 +319,7 @@ github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -332,6 +339,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -354,6 +363,7 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -370,8 +380,11 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -382,6 +395,7 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -401,18 +415,26 @@ golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -436,6 +458,7 @@ golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/providers/az_client.go b/pkg/providers/az_client.go new file mode 100644 index 00000000..13dc4e0f --- /dev/null +++ b/pkg/providers/az_client.go @@ -0,0 +1,15 @@ +package providers + +import ( + "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription" +) + +type AzClient struct { + AzTenantClient azTenantClient +} + +//go:generate mockgen -source=./az_client.go -destination=./mock/az_client.go . +type azTenantClient interface { + NewListPager(options *armsubscription.TenantsClientListOptions) *runtime.Pager[armsubscription.TenantsClientListResponse] +} diff --git a/pkg/providers/azure.go b/pkg/providers/azure.go index 53a7dd53..35dea3b4 100644 --- a/pkg/providers/azure.go +++ b/pkg/providers/azure.go @@ -5,11 +5,10 @@ import ( "encoding/json" "errors" "fmt" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription" "os/exec" "time" - "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription" "github.com/Azure/draft/pkg/spinner" bo "github.com/cenkalti/backoff/v4" @@ -26,7 +25,7 @@ type SetUpCmd struct { tenantId string appObjectId string spObjectId string - AzTenantClient azTenantClient + AzClient AzClient } func InitiateAzureOIDCFlow(ctx context.Context, sc *SetUpCmd, s spinner.Spinner) error { @@ -199,17 +198,12 @@ func (sc *SetUpCmd) getTenantId(ctx context.Context) error { return nil } -//go:generate mockgen -source=./azure.go -destination=./mock/azure.go . -type azTenantClient interface { - NewListPager(options *armsubscription.TenantsClientListOptions) *runtime.Pager[armsubscription.TenantsClientListResponse] -} - func (sc *SetUpCmd) listTenants(ctx context.Context) ([]armsubscription.TenantIDDescription, error) { log.Debug("listing Azure subscriptions") var tenants []armsubscription.TenantIDDescription - pager := sc.AzTenantClient.NewListPager(nil) + pager := sc.AzClient.AzTenantClient.NewListPager(nil) for pager.More() { page, err := pager.NextPage(ctx) diff --git a/pkg/providers/azure_test.go b/pkg/providers/azure_test.go index bf7bba75..082f38b2 100644 --- a/pkg/providers/azure_test.go +++ b/pkg/providers/azure_test.go @@ -2,17 +2,46 @@ package providers import ( "context" + "errors" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription" mock_providers "github.com/Azure/draft/pkg/providers/mock" "go.uber.org/mock/gomock" + "strings" "testing" ) +func setupMockClientAndPager(ctrl *gomock.Controller, responses []armsubscription.TenantsClientListResponse) *mock_providers.MockazTenantClient { + mockClient := mock_providers.NewMockazTenantClient(ctrl) + + // Define a minimal paging handler function that returns the provided responses + mockPagerHandler := runtime.PagingHandler[armsubscription.TenantsClientListResponse]{ + More: func(t armsubscription.TenantsClientListResponse) bool { return false }, + Fetcher: func(ctx context.Context, response *armsubscription.TenantsClientListResponse) (armsubscription.TenantsClientListResponse, error) { + if len(responses) == 0 { + return armsubscription.TenantsClientListResponse{}, nil + } + resp := responses[0] + responses = responses[1:] + return resp, nil + }, + Tracer: tracing.Tracer{}, + } + + // Create a mock pager with the paging handler + mockPager := runtime.NewPager[armsubscription.TenantsClientListResponse](mockPagerHandler) + + mockClient.EXPECT().NewListPager(gomock.Nil()).Return(mockPager).Times(1) + + return mockClient +} + func TestGetTenantId(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() + + // Define test data testId := "00000000-0000-0000-0000-000000000000" testTenantId := "/tenants/00000000-0000-0000-0000-000000000000" testNextLink := "https://pkg.go.dev/github.com" @@ -20,29 +49,91 @@ func TestGetTenantId(t *testing.T) { testTenantDescArray := []*armsubscription.TenantIDDescription{&testTenantDesc} testTenantListResult := armsubscription.TenantListResult{NextLink: &testNextLink, Value: testTenantDescArray} responses := []armsubscription.TenantsClientListResponse{{testTenantListResult}} - testReadResponses := 0 - testPagerHandler := runtime.PagingHandler[armsubscription.TenantsClientListResponse]{ - More: func(t armsubscription.TenantsClientListResponse) bool { return testReadResponses < len(responses) }, + + mockClient := setupMockClientAndPager(ctrl, responses) + + sc := &SetUpCmd{ + AzClient: AzClient{ + AzTenantClient: mockClient, + }, + } + + err := sc.getTenantId(context.Background()) + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } +} + +// Test case for the getTenantId function when listing tenants encounters an error +func TestGetTenantId_ListTenantsError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // Setup mock client and pager to return an error when listing tenants + mockClient := mock_providers.NewMockazTenantClient(ctrl) + mockPager := runtime.NewPager[armsubscription.TenantsClientListResponse](runtime.PagingHandler[armsubscription.TenantsClientListResponse]{ + More: func(t armsubscription.TenantsClientListResponse) bool { return false }, Fetcher: func(ctx context.Context, response *armsubscription.TenantsClientListResponse) (armsubscription.TenantsClientListResponse, error) { - resp := responses[testReadResponses] - testReadResponses++ - return resp, nil + return armsubscription.TenantsClientListResponse{}, errors.New("error listing tenants") }, Tracer: tracing.Tracer{}, + }) + mockClient.EXPECT().NewListPager(gomock.Nil()).Return(mockPager).Times(1) + + sc := &SetUpCmd{ + AzClient: AzClient{ + AzTenantClient: mockClient, + }, } - mockClient := mock_providers.NewMockazTenantClient(ctrl) - var mockPager = runtime.NewPager[armsubscription.TenantsClientListResponse](testPagerHandler) + err := sc.getTenantId(context.Background()) - mockClient.EXPECT().NewListPager(gomock.Nil()).Return(mockPager).Times(1) + if err == nil || !strings.Contains(err.Error(), "error listing tenants") { + t.Errorf("Expected error listing tenants, got: %v", err) + } +} + +// Test case for the getTenantId function when tenant list is empty +func TestGetTenantId_EmptyTenantList(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // Setup mock client and pager with no responses + mockClient := setupMockClientAndPager(ctrl, []armsubscription.TenantsClientListResponse{}) sc := &SetUpCmd{ - AzTenantClient: mockClient, + AzClient: AzClient{ + AzTenantClient: mockClient, + }, } err := sc.getTenantId(context.Background()) - - if err != nil { - t.Errorf("Unexpected error: %v", err) + + if err == nil || !strings.Contains(err.Error(), "no tenants found") { + t.Errorf("Expected error no tenants found, got: %v", err) + } +} + +// Test case for the getTenantId function when a nil tenant is encountered in the list +func TestGetTenantId_NilTenantInList(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // Define test data with a nil tenant in the list + testTenantDescArray := []*armsubscription.TenantIDDescription{nil} + + mockClient := setupMockClientAndPager(ctrl, []armsubscription.TenantsClientListResponse{{TenantListResult: armsubscription.TenantListResult{Value: testTenantDescArray}}}) + + sc := &SetUpCmd{ + AzClient: AzClient{ + AzTenantClient: mockClient, + }, + } + + err := sc.getTenantId(context.Background()) + + if err == nil || !strings.Contains(err.Error(), "nil tenant") { + t.Errorf("Expected error nil tenant, got: %v", err) } } diff --git a/pkg/providers/mock/azure.go b/pkg/providers/mock/az_client.go similarity index 94% rename from pkg/providers/mock/azure.go rename to pkg/providers/mock/az_client.go index 7873409b..b383fd5e 100644 --- a/pkg/providers/mock/azure.go +++ b/pkg/providers/mock/az_client.go @@ -1,9 +1,9 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: ./azure.go +// Source: ./az_client.go // // Generated by this command: // -// mockgen -source=./azure.go -destination=./mock/azure.go . +// mockgen -source=./az_client.go -destination=./mock/az_client.go . // // Package mock_providers is a generated GoMock package. From 4a225e716a6f11cc61858aabdb93ceeb630afa17 Mon Sep 17 00:00:00 2001 From: Vidya Reddy <59590642+Vidya2606@users.noreply.github.com> Date: Fri, 12 Apr 2024 11:48:22 -0700 Subject: [PATCH 3/3] Renamed files --- pkg/providers/{az_client.go => az-client.go} | 0 pkg/providers/mock/{az_client.go => az-client.go} | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename pkg/providers/{az_client.go => az-client.go} (100%) rename pkg/providers/mock/{az_client.go => az-client.go} (95%) diff --git a/pkg/providers/az_client.go b/pkg/providers/az-client.go similarity index 100% rename from pkg/providers/az_client.go rename to pkg/providers/az-client.go diff --git a/pkg/providers/mock/az_client.go b/pkg/providers/mock/az-client.go similarity index 95% rename from pkg/providers/mock/az_client.go rename to pkg/providers/mock/az-client.go index b383fd5e..cf77c55a 100644 --- a/pkg/providers/mock/az_client.go +++ b/pkg/providers/mock/az-client.go @@ -1,9 +1,9 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: ./az_client.go +// Source: ./az-client.go // // Generated by this command: // -// mockgen -source=./az_client.go -destination=./mock/az_client.go . +// mockgen -source=./az-client.go -destination=./mock/az-client.go . // // Package mock_providers is a generated GoMock package.