From b34b05f0590cc193a6c0881fcc99b4bbf47f218d Mon Sep 17 00:00:00 2001 From: Javier Adriel Date: Tue, 24 Jan 2023 21:28:46 -0600 Subject: [PATCH] Tests for getTenantMonitoringResponse, getTenantUsage and getTenantPods (#2599) --- .github/workflows/jobs.yaml | 2 +- operatorapi/tenants.go | 29 +++++++--- operatorapi/tenants_2_test.go | 105 ++++++++++++++++++++++++++++++++-- restapi/admin_arns_test.go | 4 +- restapi/admin_client_mock.go | 4 +- restapi/admin_info_test.go | 2 +- restapi/admin_service_test.go | 6 +- restapi/admin_subnet_test.go | 2 +- 8 files changed, 131 insertions(+), 23 deletions(-) diff --git a/.github/workflows/jobs.yaml b/.github/workflows/jobs.yaml index 85155e9e7..4f5e9c5ba 100644 --- a/.github/workflows/jobs.yaml +++ b/.github/workflows/jobs.yaml @@ -1539,7 +1539,7 @@ jobs: go tool cover -func=all.out | grep total > tmp2 result=`cat tmp2 | awk 'END {print $3}'` result=${result%\%} - threshold=65.4 + threshold=66.1 echo "Result:" echo "$result%" if (( $(echo "$result >= $threshold" |bc -l) )); then diff --git a/operatorapi/tenants.go b/operatorapi/tenants.go index 6830ff26e..daa233829 100644 --- a/operatorapi/tenants.go +++ b/operatorapi/tenants.go @@ -1517,6 +1517,10 @@ func getTenantUsageResponse(session *models.Principal, params operator_api.GetTe if err != nil { return nil, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage) } + return getTenantUsage(ctx, minTenant, k8sClient) +} + +func getTenantUsage(ctx context.Context, minTenant *miniov2.Tenant, k8sClient K8sClientI) (*models.TenantUsage, *models.Error) { minTenant.EnsureDefaults() svcURL := GetTenantServiceURL(minTenant) @@ -1530,16 +1534,15 @@ func getTenantUsageResponse(session *models.Principal, params operator_api.GetTe if err != nil { return nil, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage) } - // create a minioClient interface implementation - // defining the client to be used - adminClient := restapi.AdminClient{Client: mAdmin} - // serialize output + return _getTenantUsage(ctx, restapi.AdminClient{Client: mAdmin}) +} + +func _getTenantUsage(ctx context.Context, adminClient restapi.MinioAdmin) (*models.TenantUsage, *models.Error) { adminInfo, err := restapi.GetAdminInfo(ctx, adminClient) if err != nil { return nil, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage) } - info := &models.TenantUsage{Used: adminInfo.Usage, DiskUsed: adminInfo.DisksUsage} - return info, nil + return &models.TenantUsage{Used: adminInfo.Usage, DiskUsed: adminInfo.DisksUsage}, nil } func getTenantPodsResponse(session *models.Principal, params operator_api.GetTenantPodsParams) ([]*models.TenantPod, *models.Error) { @@ -1556,6 +1559,10 @@ func getTenantPodsResponse(session *models.Principal, params operator_api.GetTen if err != nil { return nil, restapi.ErrorWithContext(ctx, err) } + return getTenantPods(pods), nil +} + +func getTenantPods(pods *corev1.PodList) []*models.TenantPod { retval := []*models.TenantPod{} for _, pod := range pods.Items { var restarts int64 @@ -1575,7 +1582,7 @@ func getTenantPodsResponse(session *models.Principal, params operator_api.GetTen Node: pod.Spec.NodeName, }) } - return retval, nil + return retval } func getPodLogsResponse(session *models.Principal, params operator_api.GetPodLogsParams) (string, *models.Error) { @@ -1929,13 +1936,17 @@ func getTenantMonitoringResponse(session *models.Principal, params operator_api. if err != nil { return nil, restapi.ErrorWithContext(ctx, err) } + return getTenantMonitoring(minInst), nil +} + +func getTenantMonitoring(minInst *miniov2.Tenant) *models.TenantMonitoringInfo { monitoringInfo := &models.TenantMonitoringInfo{} if minInst.Spec.Prometheus != nil { monitoringInfo.PrometheusEnabled = true } else { monitoringInfo.PrometheusEnabled = false - return monitoringInfo, nil + return monitoringInfo } var storageClassName string @@ -2002,7 +2013,7 @@ func getTenantMonitoringResponse(session *models.Principal, params operator_api. if minInst.Spec.Prometheus.SecurityContext != nil { monitoringInfo.SecurityContext = convertK8sSCToModelSC(minInst.Spec.Prometheus.SecurityContext) } - return monitoringInfo, nil + return monitoringInfo } // sets tenant Prometheus monitoring cofiguration fields to values provided diff --git a/operatorapi/tenants_2_test.go b/operatorapi/tenants_2_test.go index 1c56dde08..82080b8c2 100644 --- a/operatorapi/tenants_2_test.go +++ b/operatorapi/tenants_2_test.go @@ -23,31 +23,37 @@ import ( "net/http" "strings" "testing" + "time" "github.com/minio/console/models" "github.com/minio/console/operatorapi/operations" "github.com/minio/console/operatorapi/operations/operator_api" + "github.com/minio/console/restapi" + "github.com/minio/madmin-go/v2" miniov2 "github.com/minio/operator/pkg/apis/minio.min.io/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" k8sErrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" ) type TenantTestSuite struct { suite.Suite - assert *assert.Assertions - opClient opClientMock - k8sclient k8sClientMock + assert *assert.Assertions + opClient opClientMock + k8sclient k8sClientMock + adminClient restapi.AdminClientMock } func (suite *TenantTestSuite) SetupSuite() { suite.assert = assert.New(suite.T()) suite.opClient = opClientMock{} suite.k8sclient = k8sClientMock{} + suite.adminClient = restapi.AdminClientMock{} k8sClientDeleteSecretsCollectionMock = func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { return nil } @@ -700,6 +706,7 @@ func (suite *TenantTestSuite) TestSetTenantAdministratorsWithAdminClientError() suite.assert.NotNil(err) } +// TODO: Mock minio adminclient func (suite *TenantTestSuite) TestSetTenantAdministratorsWithUserPolicyError() { params, _ := suite.initSetTenantAdministratorsRequest() tenant := &miniov2.Tenant{ @@ -715,6 +722,7 @@ func (suite *TenantTestSuite) TestSetTenantAdministratorsWithUserPolicyError() { suite.assert.NotNil(err) } +// TODO: Mock minio adminclient func (suite *TenantTestSuite) TestSetTenantAdministratorsWithGroupPolicyError() { params, _ := suite.initSetTenantAdministratorsRequest() tenant := &miniov2.Tenant{ @@ -996,7 +1004,32 @@ func (suite *TenantTestSuite) initGetTenantUsageRequest() (params operator_api.G return params, api } -func (suite *TenantTestSuite) TestGetTenantPodsHandlerWithoutError() { +func (suite *TenantTestSuite) TestGetTenantUsageWithWrongAdminClient() { + tenant := &miniov2.Tenant{} + usage, err := getTenantUsage(context.Background(), tenant, suite.k8sclient) + suite.assert.Nil(usage) + suite.assert.NotNil(err) +} + +func (suite *TenantTestSuite) TestGetTenantUsageWithError() { + restapi.MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { + return madmin.InfoMessage{}, errors.New("mock-server-info-error") + } + usage, err := _getTenantUsage(context.Background(), suite.adminClient) + suite.assert.Nil(usage) + suite.assert.NotNil(err) +} + +func (suite *TenantTestSuite) TestGetTenantUsageWithNoError() { + restapi.MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { + return madmin.InfoMessage{}, nil + } + usage, err := _getTenantUsage(context.Background(), suite.adminClient) + suite.assert.NotNil(usage) + suite.assert.Nil(err) +} + +func (suite *TenantTestSuite) TestGetTenantPodsHandlerWithError() { params, api := suite.initGetTenantPodsRequest() response := api.OperatorAPIGetTenantPodsHandler.Handle(params, &models.Principal{}) _, ok := response.(*operator_api.GetTenantPodsDefault) @@ -1011,6 +1044,22 @@ func (suite *TenantTestSuite) initGetTenantPodsRequest() (params operator_api.Ge return params, api } +func (suite *TenantTestSuite) TestGetTenantPodsWithoutError() { + pods := getTenantPods(&corev1.PodList{ + Items: []corev1.Pod{ + { + Status: corev1.PodStatus{ + ContainerStatuses: []corev1.ContainerStatus{{}}, + }, + ObjectMeta: metav1.ObjectMeta{ + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + }, + }, + }) + suite.assert.Equal(1, len(pods)) +} + func (suite *TenantTestSuite) TestGetPodLogsHandlerWithError() { params, api := suite.initGetPodLogsRequest() response := api.OperatorAPIGetPodLogsHandler.Handle(params, &models.Principal{}) @@ -1074,6 +1123,54 @@ func (suite *TenantTestSuite) initGetTenantMonitoringRequest() (params operator_ return params, api } +func (suite *TenantTestSuite) TestGetTenantMonitoringWithoutPrometheus() { + tenant := &miniov2.Tenant{} + monitoring := getTenantMonitoring(tenant) + suite.assert.False(monitoring.PrometheusEnabled) +} + +func (suite *TenantTestSuite) TestGetTenantMonitoringWithPrometheus() { + stn := "mock-storage-class" + dc := 10 + runAsUser := int64(1000) + runAsGroup := int64(1000) + fsGroup := int64(1000) + tenant := &miniov2.Tenant{ + Spec: miniov2.TenantSpec{ + Prometheus: &miniov2.PrometheusConfig{ + StorageClassName: &stn, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("1"), + corev1.ResourceMemory: resource.MustParse("1Gi"), + }, + }, + Labels: map[string]string{ + "mock-label": "mock-value", + }, + Annotations: map[string]string{ + "mock-label": "mock-value", + }, + NodeSelector: map[string]string{ + "mock-label": "mock-value", + }, + DiskCapacityDB: &dc, + Image: "mock-image", + InitImage: "mock-init-image", + ServiceAccountName: "mock-service-account-name", + SideCarImage: "mock-sidecar-image", + SecurityContext: &corev1.PodSecurityContext{ + RunAsUser: &runAsUser, + RunAsGroup: &runAsGroup, + FSGroup: &fsGroup, + }, + }, + }, + } + monitoring := getTenantMonitoring(tenant) + suite.assert.True(monitoring.PrometheusEnabled) +} + func (suite *TenantTestSuite) TestSetTenantMonitoringHandlerWithError() { params, api := suite.initSetTenantMonitoringRequest() response := api.OperatorAPISetTenantMonitoringHandler.Handle(params, &models.Principal{}) diff --git a/restapi/admin_arns_test.go b/restapi/admin_arns_test.go index 860d8abb8..c970f16fc 100644 --- a/restapi/admin_arns_test.go +++ b/restapi/admin_arns_test.go @@ -39,7 +39,7 @@ func TestArnsList(t *testing.T) { assert := asrt.New(t) adminClient := AdminClientMock{} // Test-1 : getArns() returns proper arn list - minioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { + MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { return madmin.InfoMessage{ SQSARN: []string{"uno"}, }, nil @@ -54,7 +54,7 @@ func TestArnsList(t *testing.T) { assert.Nil(err, "Error should have been nil") // Test-2 : getArns(ctx) fails for whatever reason - minioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { + MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { return madmin.InfoMessage{}, errors.New("some reason") } diff --git a/restapi/admin_client_mock.go b/restapi/admin_client_mock.go index 24fc0bb43..71bdb26d6 100644 --- a/restapi/admin_client_mock.go +++ b/restapi/admin_client_mock.go @@ -28,7 +28,7 @@ import ( type AdminClientMock struct{} var ( - minioServerInfoMock func(ctx context.Context) (madmin.InfoMessage, error) + MinioServerInfoMock func(ctx context.Context) (madmin.InfoMessage, error) minioChangePasswordMock func(ctx context.Context, accessKey, secretKey string) error minioHelpConfigKVMock func(subSys, key string, envOnly bool) (madmin.Help, error) @@ -87,7 +87,7 @@ var ( ) func (ac AdminClientMock) serverInfo(ctx context.Context) (madmin.InfoMessage, error) { - return minioServerInfoMock(ctx) + return MinioServerInfoMock(ctx) } func (ac AdminClientMock) listRemoteBuckets(ctx context.Context, bucket, arnType string) (targets []madmin.BucketTarget, err error) { diff --git a/restapi/admin_info_test.go b/restapi/admin_info_test.go index 2c0f6ced8..6fefbb8b2 100644 --- a/restapi/admin_info_test.go +++ b/restapi/admin_info_test.go @@ -44,7 +44,7 @@ type AdminInfoTestSuite struct { func (suite *AdminInfoTestSuite) SetupSuite() { suite.assert = assert.New(suite.T()) suite.adminClient = AdminClientMock{} - minioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { + MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { return madmin.InfoMessage{ Servers: []madmin.ServerProperties{{ Disks: []madmin.Disk{{}}, diff --git a/restapi/admin_service_test.go b/restapi/admin_service_test.go index 306ec9296..102b35874 100644 --- a/restapi/admin_service_test.go +++ b/restapi/admin_service_test.go @@ -35,7 +35,7 @@ func TestServiceRestart(t *testing.T) { minioServiceRestartMock = func(ctx context.Context) error { return nil } - minioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { + MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { return madmin.InfoMessage{}, nil } if err := serviceRestart(ctx, adminClient); err != nil { @@ -47,7 +47,7 @@ func TestServiceRestart(t *testing.T) { minioServiceRestartMock = func(ctx context.Context) error { return errors.New("error") } - minioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { + MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { return madmin.InfoMessage{}, nil } if err := serviceRestart(ctx, adminClient); assert.Error(err) { @@ -59,7 +59,7 @@ func TestServiceRestart(t *testing.T) { minioServiceRestartMock = func(ctx context.Context) error { return nil } - minioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { + MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { return madmin.InfoMessage{}, errors.New("error on server info") } if err := serviceRestart(ctx, adminClient); assert.Error(err) { diff --git a/restapi/admin_subnet_test.go b/restapi/admin_subnet_test.go index 031a08b12..e881b83b5 100644 --- a/restapi/admin_subnet_test.go +++ b/restapi/admin_subnet_test.go @@ -47,7 +47,7 @@ func (suite *AdminSubnetTestSuite) SetupSuite() { minioGetConfigKVMock = func(key string) ([]byte, error) { return []byte("subnet license=mock api_key=mock proxy=http://mock.com"), nil } - minioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { + MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { return madmin.InfoMessage{Servers: []madmin.ServerProperties{{}}}, nil } }