diff --git a/operatorapi/config.go b/operatorapi/config.go index 0d3db589b..4f826453a 100644 --- a/operatorapi/config.go +++ b/operatorapi/config.go @@ -73,6 +73,5 @@ func getMarketplace() string { // Get DirectPVMode func getDirectPVEnabled() bool { currentMode := env.Get(DirectPVMode, "off") - return currentMode == "on" } diff --git a/operatorapi/config_test.go b/operatorapi/config_test.go index a2b85791b..680cfb5ed 100644 --- a/operatorapi/config_test.go +++ b/operatorapi/config_test.go @@ -19,6 +19,8 @@ package operatorapi import ( "os" "testing" + + "github.com/stretchr/testify/assert" ) func Test_getK8sSAToken(t *testing.T) { @@ -96,3 +98,39 @@ func Test_getMarketplace(t *testing.T) { }) } } + +func Test_getDirectPVEnabled(t *testing.T) { + type args struct { + setEnv bool + } + tests := []struct { + name string + want bool + args args + }{ + { + name: "DirectPV Mode is Set", + want: true, + args: args{ + setEnv: true, + }, + }, + { + name: "DirectPV Mode is not set", + want: false, + args: args{ + setEnv: false, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.args.setEnv { + os.Setenv(DirectPVMode, "on") + } else { + os.Unsetenv(DirectPVMode) + } + assert.Equalf(t, tt.want, getDirectPVEnabled(), "getDirectPVEnabled()") + }) + } +} diff --git a/operatorapi/logs_test.go b/operatorapi/logs_test.go new file mode 100644 index 000000000..bfc863d2e --- /dev/null +++ b/operatorapi/logs_test.go @@ -0,0 +1,110 @@ +// This file is part of MinIO Console Server +// Copyright (c) 2022 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 +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package operatorapi + +import ( + "flag" + "fmt" + "testing" + + "github.com/minio/cli" + "github.com/stretchr/testify/assert" +) + +func TestContext_Load(t *testing.T) { + type fields struct { + Host string + HTTPPort int + HTTPSPort int + TLSRedirect string + TLSCertificate string + TLSKey string + TLSca string + } + type args struct { + values map[string]string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "valid args", + args: args{ + values: map[string]string{ + "tls-redirect": "on", + }, + }, + wantErr: false, + }, + { + name: "invalid args", + args: args{ + values: map[string]string{ + "tls-redirect": "aaaa", + }, + }, + wantErr: true, + }, + { + name: "invalid port http", + args: args{ + values: map[string]string{ + "tls-redirect": "on", + "port": "65536", + }, + }, + wantErr: true, + }, + { + name: "invalid port https", + args: args{ + values: map[string]string{ + "tls-redirect": "on", + "port": "65534", + "tls-port": "65536", + }, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Context{} + + fs := flag.NewFlagSet("flags", flag.ContinueOnError) + for k, v := range tt.args.values { + fs.String(k, v, "ok") + } + + ctx := cli.NewContext(nil, fs, &cli.Context{}) + + err := c.Load(ctx) + if tt.wantErr { + assert.NotNilf(t, err, fmt.Sprintf("Load(%v)", err)) + } else { + assert.Nilf(t, err, fmt.Sprintf("Load(%v)", err)) + } + }) + } +} + +func Test_logInfo(t *testing.T) { + logInfo("message", nil) +} diff --git a/operatorapi/parity_test.go b/operatorapi/parity_test.go index 1f74e56a2..04802c330 100644 --- a/operatorapi/parity_test.go +++ b/operatorapi/parity_test.go @@ -18,9 +18,13 @@ package operatorapi import ( "encoding/json" + "net/http" "reflect" "testing" + "github.com/minio/console/operatorapi/operations/operator_api" + "github.com/stretchr/testify/assert" + "github.com/minio/console/models" ) @@ -77,3 +81,51 @@ func Test_getParityInfo(t *testing.T) { }) } } + +func Test_getParityResponse(t *testing.T) { + type args struct { + params operator_api.GetParityParams + } + tests := []struct { + name string + args args + want models.ParityResponse + wantErr bool + }{ + { + name: "valid", + args: args{ + params: operator_api.GetParityParams{ + HTTPRequest: &http.Request{}, + DisksPerNode: 4, + Nodes: 4, + }, + }, + want: models.ParityResponse{"EC:8", "EC:7", "EC:6", "EC:5", "EC:4", "EC:3", "EC:2"}, + wantErr: false, + }, + { + name: "invalid", + args: args{ + params: operator_api.GetParityParams{ + HTTPRequest: &http.Request{}, + DisksPerNode: -4, + Nodes: 4, + }, + }, + want: models.ParityResponse(nil), + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, got1 := getParityResponse(tt.args.params) + assert.Equalf(t, tt.want, got, "getParityResponse(%v)", tt.args.params) + if tt.wantErr { + assert.NotNilf(t, got1, "getParityResponse(%v)", tt.args.params) + } else { + assert.Nilf(t, got1, "getParityResponse(%v)", tt.args.params) + } + }) + } +} diff --git a/operatorapi/utils_test.go b/operatorapi/utils_test.go index 0e6055882..71e7452c1 100644 --- a/operatorapi/utils_test.go +++ b/operatorapi/utils_test.go @@ -228,3 +228,27 @@ func TestGenerateTenantConfigurationFile(t *testing.T) { }) } } + +func Test_stringPtr(t *testing.T) { + type args struct { + str string + } + tests := []struct { + name string + args args + wantNil bool + }{ + { + name: "get a pointer", + args: args{ + str: "", + }, + wantNil: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.NotNilf(t, stringPtr(tt.args.str), "stringPtr(%v)", tt.args.str) + }) + } +} diff --git a/restapi/client-admin.go b/restapi/client-admin.go index 4121438e2..942cb1f88 100644 --- a/restapi/client-admin.go +++ b/restapi/client-admin.go @@ -87,7 +87,6 @@ type MinioAdmin interface { delConfigKV(ctx context.Context, kv string) (err error) serviceRestart(ctx context.Context) error serverInfo(ctx context.Context) (madmin.InfoMessage, error) - startProfiling(ctx context.Context, profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error) stopProfiling(ctx context.Context) (io.ReadCloser, error) serviceTrace(ctx context.Context, threshold int64, s3, internal, storage, os, errTrace bool) <-chan madmin.ServiceTraceInfo diff --git a/restapi/config_test.go b/restapi/config_test.go new file mode 100644 index 000000000..a4cb38195 --- /dev/null +++ b/restapi/config_test.go @@ -0,0 +1,393 @@ +// This file is part of MinIO Console Server +// 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 +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package restapi + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetHostname(t *testing.T) { + os.Setenv(ConsoleHostname, "x") + defer os.Unsetenv(ConsoleHostname) + assert.Equalf(t, "x", GetHostname(), "GetHostname()") +} + +func TestGetPort(t *testing.T) { + type args struct { + env string + } + tests := []struct { + name string + args args + want int + }{ + { + name: "valid port", + args: args{ + env: "9091", + }, + want: 9091, + }, + { + name: "invalid port", + args: args{ + env: "duck", + }, + want: 9090, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + os.Setenv(ConsolePort, tt.args.env) + assert.Equalf(t, tt.want, GetPort(), "GetPort()") + os.Unsetenv(ConsolePort) + }) + } +} + +func TestGetTLSPort(t *testing.T) { + type args struct { + env string + } + tests := []struct { + name string + args args + want int + }{ + { + name: "valid port", + args: args{ + env: "9444", + }, + want: 9444, + }, + { + name: "invalid port", + args: args{ + env: "duck", + }, + want: 9443, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + os.Setenv(ConsoleTLSPort, tt.args.env) + assert.Equalf(t, tt.want, GetTLSPort(), "GetTLSPort()") + os.Unsetenv(ConsoleTLSPort) + }) + } +} + +func TestGetSecureAllowedHosts(t *testing.T) { + type args struct { + env string + } + tests := []struct { + name string + args args + want []string + }{ + { + name: "valid hosts", + args: args{ + env: "host1,host2", + }, + want: []string{"host1", "host2"}, + }, + { + name: "empty hosts", + args: args{ + env: "", + }, + want: []string{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + os.Setenv(ConsoleSecureAllowedHosts, tt.args.env) + assert.Equalf(t, tt.want, GetSecureAllowedHosts(), "GetSecureAllowedHosts()") + os.Unsetenv(ConsoleSecureAllowedHosts) + }) + } +} + +func TestGetSecureHostsProxyHeaders(t *testing.T) { + type args struct { + env string + } + tests := []struct { + name string + args args + want []string + }{ + { + name: "valid headers", + args: args{ + env: "header1,header2", + }, + want: []string{"header1", "header2"}, + }, + { + name: "empty headers", + args: args{ + env: "", + }, + want: []string{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + os.Setenv(ConsoleSecureHostsProxyHeaders, tt.args.env) + assert.Equalf(t, tt.want, GetSecureHostsProxyHeaders(), "GetSecureHostsProxyHeaders()") + os.Unsetenv(ConsoleSecureHostsProxyHeaders) + }) + } +} + +func TestGetSecureSTSSeconds(t *testing.T) { + type args struct { + env string + } + tests := []struct { + name string + args args + want int64 + }{ + { + name: "valid", + args: args{ + env: "1", + }, + want: 1, + }, + { + name: "invalid", + args: args{ + env: "duck", + }, + want: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + os.Setenv(ConsoleSecureSTSSeconds, tt.args.env) + assert.Equalf(t, tt.want, GetSecureSTSSeconds(), "GetSecureSTSSeconds()") + os.Unsetenv(ConsoleSecureSTSSeconds) + }) + } +} + +func Test_getLogSearchAPIToken(t *testing.T) { + type args struct { + env string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "env set", + args: args{ + env: "value", + }, + want: "value", + }, + { + name: "env not set", + args: args{ + env: "", + }, + want: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + os.Setenv(ConsoleLogQueryAuthToken, tt.args.env) + assert.Equalf(t, tt.want, getLogSearchAPIToken(), "getLogSearchAPIToken()") + os.Setenv(ConsoleLogQueryAuthToken, tt.args.env) + }) + } +} + +func Test_getPrometheusURL(t *testing.T) { + type args struct { + env string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "env set", + args: args{ + env: "value", + }, + want: "value", + }, + { + name: "env not set", + args: args{ + env: "", + }, + want: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + os.Setenv(PrometheusURL, tt.args.env) + assert.Equalf(t, tt.want, getPrometheusURL(), "getPrometheusURL()") + os.Setenv(PrometheusURL, tt.args.env) + }) + } +} + +func Test_getPrometheusJobID(t *testing.T) { + type args struct { + env string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "env set", + args: args{ + env: "value", + }, + want: "value", + }, + { + name: "env not set", + args: args{ + env: "", + }, + want: "minio-job", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + os.Setenv(PrometheusJobID, tt.args.env) + assert.Equalf(t, tt.want, getPrometheusJobID(), "getPrometheusJobID()") + os.Setenv(PrometheusJobID, tt.args.env) + }) + } +} + +func Test_getMaxConcurrentUploadsLimit(t *testing.T) { + type args struct { + env string + } + tests := []struct { + name string + args args + want int64 + }{ + { + name: "valid", + args: args{ + env: "1", + }, + want: 1, + }, + { + name: "invalid", + args: args{ + env: "duck", + }, + want: 10, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + os.Setenv(ConsoleMaxConcurrentUploads, tt.args.env) + assert.Equalf(t, tt.want, getMaxConcurrentUploadsLimit(), "getMaxConcurrentUploadsLimit()") + os.Unsetenv(ConsoleMaxConcurrentUploads) + }) + } +} + +func Test_getMaxConcurrentDownloadsLimit(t *testing.T) { + type args struct { + env string + } + tests := []struct { + name string + args args + want int64 + }{ + { + name: "valid", + args: args{ + env: "1", + }, + want: 1, + }, + { + name: "invalid", + args: args{ + env: "duck", + }, + want: 20, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + os.Setenv(ConsoleMaxConcurrentDownloads, tt.args.env) + assert.Equalf(t, tt.want, getMaxConcurrentDownloadsLimit(), "getMaxConcurrentDownloadsLimit()") + os.Unsetenv(ConsoleMaxConcurrentDownloads) + }) + } +} + +func Test_getConsoleDevMode(t *testing.T) { + type args struct { + env string + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "value set", + args: args{ + env: "on", + }, + want: true, + }, + { + name: "value not set", + args: args{ + env: "", + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + os.Setenv(ConsoleDevMode, tt.args.env) + assert.Equalf(t, tt.want, getConsoleDevMode(), "getConsoleDevMode()") + os.Unsetenv(ConsoleDevMode) + }) + } +} diff --git a/restapi/logs_test.go b/restapi/logs_test.go new file mode 100644 index 000000000..790f92d85 --- /dev/null +++ b/restapi/logs_test.go @@ -0,0 +1,110 @@ +// This file is part of MinIO Console Server +// Copyright (c) 2022 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 +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package restapi + +import ( + "flag" + "fmt" + "testing" + + "github.com/minio/cli" + "github.com/stretchr/testify/assert" +) + +func TestContext_Load(t *testing.T) { + type fields struct { + Host string + HTTPPort int + HTTPSPort int + TLSRedirect string + TLSCertificate string + TLSKey string + TLSca string + } + type args struct { + values map[string]string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "valid args", + args: args{ + values: map[string]string{ + "tls-redirect": "on", + }, + }, + wantErr: false, + }, + { + name: "invalid args", + args: args{ + values: map[string]string{ + "tls-redirect": "aaaa", + }, + }, + wantErr: true, + }, + { + name: "invalid port http", + args: args{ + values: map[string]string{ + "tls-redirect": "on", + "port": "65536", + }, + }, + wantErr: true, + }, + { + name: "invalid port https", + args: args{ + values: map[string]string{ + "tls-redirect": "on", + "port": "65534", + "tls-port": "65536", + }, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Context{} + + fs := flag.NewFlagSet("flags", flag.ContinueOnError) + for k, v := range tt.args.values { + fs.String(k, v, "ok") + } + + ctx := cli.NewContext(nil, fs, &cli.Context{}) + + err := c.Load(ctx) + if tt.wantErr { + assert.NotNilf(t, err, fmt.Sprintf("Load(%v)", err)) + } else { + assert.Nilf(t, err, fmt.Sprintf("Load(%v)", err)) + } + }) + } +} + +func Test_logInfo(t *testing.T) { + logInfo("message", nil) +} diff --git a/restapi/utils_test.go b/restapi/utils_test.go index 910199b75..9c6a9e790 100644 --- a/restapi/utils_test.go +++ b/restapi/utils_test.go @@ -244,3 +244,76 @@ func TestRandomCharString(t *testing.T) { }) } } + +func TestValidateEncodedStyles(t *testing.T) { + type args struct { + encodedStyles string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "valid", + args: args{ + encodedStyles: "ewogICJiYWNrZ3JvdW5kQ29sb3IiOiAiIzI3ODdjNiIsCiAgImZvbnRDb2xvciI6ICIjZmYwIiwKICAiYnV0dG9uU3R5bGVzIjogewogICAgImJhY2tncm91bmRDb2xvciI6ICIjZWRlYWE4IiwKICAgICJ0ZXh0Q29sb3IiOiAiIzJiMmEyYSIsCiAgICAiaG92ZXJDb2xvciI6ICIjZWRlYWE4IiwKICAgICJob3ZlclRleHQiOiAiIzJiMmEyYSIsCiAgICAiYWN0aXZlQ29sb3IiOiAiI2VkZWFhOCIsCiAgICAiYWN0aXZlVGV4dCI6ICIjMmIyYTJhIgogIH0KfQ==", + }, + wantErr: false, + }, + { + name: "invalid config", + args: args{ + encodedStyles: "ewogICJvb3JnbGUiOiAic3MiCn0===", + }, + wantErr: true, + }, + { + name: "invalid style config", + args: args{ + encodedStyles: "e30=", + }, + wantErr: true, + }, + { + name: "invalid base64", + args: args{ + encodedStyles: "duck", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.wantErr { + assert.NotNilf(t, ValidateEncodedStyles(tt.args.encodedStyles), "Wanted an error") + } else { + assert.Nilf(t, ValidateEncodedStyles(tt.args.encodedStyles), "Did not wanted an error") + } + }) + } +} + +func TestSanitizeEncodedPrefix1(t *testing.T) { + type args struct { + rawPrefix string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "input sanitized", + args: args{ + rawPrefix: "x y", + }, + want: "x+y", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equalf(t, tt.want, SanitizeEncodedPrefix(tt.args.rawPrefix), "SanitizeEncodedPrefix(%v)", tt.args.rawPrefix) + }) + } +}