From 756f0048f0cf3f36ec9a32cc1d387f7dff1b118b Mon Sep 17 00:00:00 2001 From: Javier Adriel Date: Thu, 5 Jan 2023 16:54:00 -0600 Subject: [PATCH] Add tests for admin info (#2553) --- restapi/admin_info.go | 25 ++---- restapi/admin_info_test.go | 155 ++++++++++++++++++++++++++++++------- 2 files changed, 132 insertions(+), 48 deletions(-) diff --git a/restapi/admin_info.go b/restapi/admin_info.go index 62474924e..4b552e3b9 100644 --- a/restapi/admin_info.go +++ b/restapi/admin_info.go @@ -33,7 +33,6 @@ import ( "github.com/minio/console/models" "github.com/minio/console/restapi/operations" systemApi "github.com/minio/console/restapi/operations/system" - "github.com/minio/madmin-go/v2" ) func registerAdminInfoHandlers(api *operations.ConsoleAPI) { @@ -94,18 +93,13 @@ func GetAdminInfo(ctx context.Context, client MinioAdmin) (*UsageInfo, error) { } var usedSpace int64 - for _, serv := range serverInfo.Servers { - for _, disk := range serv.Disks { - usedSpace += int64(disk.UsedSpace) - } - } - // serverArray contains the serverProperties which describe the servers in the network var serverArray []*models.ServerProperties for _, serv := range serverInfo.Servers { drives := []*models.ServerDrives{} for _, drive := range serv.Disks { + usedSpace += int64(drive.UsedSpace) drives = append(drives, &models.ServerDrives{ State: drive.State, UUID: drive.UUID, @@ -905,7 +899,7 @@ func getAdminInfoResponse(session *models.Principal, params systemApi.AdminInfoP return nil, ErrorWithContext(ctx, err) } - sessionResp, err2 := getUsageWidgetsForDeployment(ctx, prometheusURL, mAdmin) + sessionResp, err2 := getUsageWidgetsForDeployment(ctx, prometheusURL, AdminClient{Client: mAdmin}) if err2 != nil { return nil, ErrorWithContext(ctx, err2) } @@ -913,7 +907,7 @@ func getAdminInfoResponse(session *models.Principal, params systemApi.AdminInfoP return sessionResp, nil } -func getUsageWidgetsForDeployment(ctx context.Context, prometheusURL string, mAdmin *madmin.AdminClient) (*models.AdminInfoResponse, error) { +func getUsageWidgetsForDeployment(ctx context.Context, prometheusURL string, adminClient MinioAdmin) (*models.AdminInfoResponse, error) { prometheusStatus := models.AdminInfoResponseAdvancedMetricsStatusAvailable if prometheusURL == "" { prometheusStatus = models.AdminInfoResponseAdvancedMetricsStatusNotConfigured @@ -927,10 +921,6 @@ func getUsageWidgetsForDeployment(ctx context.Context, prometheusURL string, mAd doneCh := make(chan error) go func() { defer close(doneCh) - // create a minioClient interface implementation - // defining the client to be used - adminClient := AdminClient{Client: mAdmin} - // serialize output usage, err := GetAdminInfo(ctx, adminClient) if err != nil { @@ -1039,11 +1029,6 @@ func getAdminInfoWidgetResponse(params systemApi.DashboardWidgetDetailsParams) ( prometheusJobID := getPrometheusJobID() prometheusExtraLabels := getPrometheusExtraLabels() - // We test if prometheus URL is reachable. this is meant to avoid unuseful calls and application hang. - if !testPrometheusURL(ctx, prometheusURL) { - return nil, ErrorWithContext(ctx, errors.New("Prometheus URL is unreachable")) - } - selector := fmt.Sprintf(`job="%s"`, prometheusJobID) if strings.TrimSpace(prometheusExtraLabels) != "" { selector = fmt.Sprintf(`job="%s",%s`, prometheusJobID, prometheusExtraLabels) @@ -1052,6 +1037,10 @@ func getAdminInfoWidgetResponse(params systemApi.DashboardWidgetDetailsParams) ( } func getWidgetDetails(ctx context.Context, prometheusURL string, selector string, widgetID int32, step *int32, start *int64, end *int64) (*models.WidgetDetails, *models.Error) { + // We test if prometheus URL is reachable. this is meant to avoid unuseful calls and application hang. + if !testPrometheusURL(ctx, prometheusURL) { + return nil, ErrorWithContext(ctx, errors.New("prometheus URL is unreachable")) + } labelResultsCh := make(chan LabelResults) for _, lbl := range labels { diff --git a/restapi/admin_info_test.go b/restapi/admin_info_test.go index 139d4de33..83b55013c 100644 --- a/restapi/admin_info_test.go +++ b/restapi/admin_info_test.go @@ -1,5 +1,5 @@ // This file is part of MinIO Console Server -// Copyright (c) 2021 MinIO, Inc. +// Copyright (c) 2023 MinIO, Inc. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -18,42 +18,137 @@ package restapi import ( "context" - "errors" + "net/http" + "net/http/httptest" + "os" "testing" + "github.com/minio/console/models" + "github.com/minio/console/restapi/operations" + systemApi "github.com/minio/console/restapi/operations/system" "github.com/minio/madmin-go/v2" - asrt "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" ) -func TestAdminInfo(t *testing.T) { - assert := asrt.New(t) - adminClient := adminClientMock{} - // Test-1 : getAdminInfo() returns proper information +type AdminInfoTestSuite struct { + suite.Suite + assert *assert.Assertions + currentServer string + isServerSet bool + isPrometheusRequest bool + server *httptest.Server + adminClient adminClientMock +} + +func (suite *AdminInfoTestSuite) SetupSuite() { + suite.assert = assert.New(suite.T()) + suite.adminClient = adminClientMock{} minioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { return madmin.InfoMessage{ - Buckets: madmin.Buckets{Count: 10}, - Objects: madmin.Objects{Count: 10}, - Usage: madmin.Usage{Size: 10}, + Servers: []madmin.ServerProperties{{ + Disks: []madmin.Disk{{}}, + }}, + Backend: map[string]interface{}{ + "backendType": "mock", + "rrSCParity": 0.0, + "standardSCParity": 0.0, + }, }, nil } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - serverInfo, err := GetAdminInfo(ctx, adminClient) - assert.NotNil(serverInfo, "server info was returned nil") - if serverInfo != nil { - var actual64 int64 = 10 - assert.Equal(serverInfo.Buckets, actual64, "Incorrect bucket count") - assert.Equal(serverInfo.Objects, actual64, "Incorrect object count") - assert.Equal(serverInfo.Usage, actual64, "Incorrect usage size") - } - assert.Nil(err, "Error should have been nil") - - // Test-2 : getAdminInfo(ctx) fails for whatever reason - minioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) { - return madmin.InfoMessage{}, errors.New("some reason") - } - - serverInfo, err = GetAdminInfo(ctx, adminClient) - assert.Nil(serverInfo, "server info was not returned nil") - assert.NotNil(err, "An error should have ben returned") +} + +func (suite *AdminInfoTestSuite) SetupTest() { + suite.server = httptest.NewServer(http.HandlerFunc(suite.serverHandler)) + suite.currentServer, suite.isServerSet = os.LookupEnv(ConsoleMinIOServer) + os.Setenv(ConsoleMinIOServer, suite.server.URL) +} + +func (suite *AdminInfoTestSuite) serverHandler(w http.ResponseWriter, r *http.Request) { + if suite.isPrometheusRequest { + w.WriteHeader(200) + } else { + w.WriteHeader(400) + } +} + +func (suite *AdminInfoTestSuite) TearDownSuite() { +} + +func (suite *AdminInfoTestSuite) TearDownTest() { + if suite.isServerSet { + os.Setenv(ConsoleMinIOServer, suite.currentServer) + } else { + os.Unsetenv(ConsoleMinIOServer) + } +} + +func (suite *AdminInfoTestSuite) TestRegisterAdminInfoHandlers() { + api := &operations.ConsoleAPI{} + suite.assertHandlersAreNil(api) + registerAdminInfoHandlers(api) + suite.assertHandlersAreNotNil(api) +} + +func (suite *AdminInfoTestSuite) assertHandlersAreNil(api *operations.ConsoleAPI) { + suite.assert.Nil(api.SystemAdminInfoHandler) + suite.assert.Nil(api.SystemDashboardWidgetDetailsHandler) +} + +func (suite *AdminInfoTestSuite) assertHandlersAreNotNil(api *operations.ConsoleAPI) { + suite.assert.NotNil(api.SystemAdminInfoHandler) + suite.assert.NotNil(api.SystemDashboardWidgetDetailsHandler) +} + +func (suite *AdminInfoTestSuite) TestSystemAdminInfoHandlerWithError() { + params, api := suite.initSystemAdminInfoRequest() + response := api.SystemAdminInfoHandler.Handle(params, &models.Principal{}) + _, ok := response.(*systemApi.AdminInfoDefault) + suite.assert.True(ok) +} + +func (suite *AdminInfoTestSuite) initSystemAdminInfoRequest() (params systemApi.AdminInfoParams, api operations.ConsoleAPI) { + registerAdminInfoHandlers(&api) + params.HTTPRequest = &http.Request{} + defaultOnly := false + params.DefaultOnly = &defaultOnly + return params, api +} + +func (suite *AdminInfoTestSuite) TestSystemDashboardWidgetDetailsHandlerWithError() { + params, api := suite.initSystemDashboardWidgetDetailsRequest() + response := api.SystemDashboardWidgetDetailsHandler.Handle(params, &models.Principal{}) + _, ok := response.(*systemApi.DashboardWidgetDetailsDefault) + suite.assert.True(ok) +} + +func (suite *AdminInfoTestSuite) initSystemDashboardWidgetDetailsRequest() (params systemApi.DashboardWidgetDetailsParams, api operations.ConsoleAPI) { + registerAdminInfoHandlers(&api) + params.HTTPRequest = &http.Request{} + return params, api +} + +func (suite *AdminInfoTestSuite) TestGetUsageWidgetsForDeploymentWithoutError() { + ctx := context.Background() + suite.isPrometheusRequest = true + res, err := getUsageWidgetsForDeployment(ctx, suite.server.URL, suite.adminClient) + suite.assert.Nil(err) + suite.assert.NotNil(res) + suite.isPrometheusRequest = false +} + +func (suite *AdminInfoTestSuite) TestGetWidgetDetailsWithoutError() { + ctx := context.Background() + suite.isPrometheusRequest = true + var step int32 = 1 + var start int64 + var end int64 = 1 + res, err := getWidgetDetails(ctx, suite.server.URL, "mock", 1, &step, &start, &end) + suite.assert.Nil(err) + suite.assert.NotNil(res) + suite.isPrometheusRequest = false +} + +func TestAdminInfo(t *testing.T) { + suite.Run(t, new(AdminInfoTestSuite)) }