github.com/verrazzano/verrazzano@v1.7.0/tools/vz/cmd/analyze/analyze_test.go (about)

     1  // Copyright (c) 2022, 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package analyze
     5  
     6  import (
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/verrazzano/verrazzano/tools/vz/pkg/constants"
     9  	"github.com/verrazzano/verrazzano/tools/vz/test/helpers"
    10  	"k8s.io/cli-runtime/pkg/genericclioptions"
    11  	"os"
    12  	"path/filepath"
    13  	"testing"
    14  )
    15  
    16  const imagePullCase1 = "../../pkg/analysis/test/cluster/image-pull-case1/"
    17  const ingressIPNotFound = "../../pkg/analysis/test/cluster/ingress-ip-not-found"
    18  
    19  const loadBalancerErr = "Error syncing load balancer: failed to ensure load balancer: awaiting load balancer: context deadline exceeded"
    20  const noIPFoundErr = "Verrazzano install failed as no IP found for service ingress-controller-ingress-nginx-controller with type LoadBalancer"
    21  
    22  // TestAnalyzeDefaultFromReadOnlyDir
    23  // GIVEN a CLI analyze command
    24  // WHEN I call cmd.Execute from read only dir with a valid capture-dir and report-format set to "summary"
    25  // THEN expect the command to do the analysis and generate report file into tmp dir
    26  func TestAnalyzeDefaultFromReadOnlyDir(t *testing.T) {
    27  	stdoutFile, stderrFile := createStdTempFiles(t)
    28  	defer func() {
    29  		os.Remove(stdoutFile.Name())
    30  		os.Remove(stderrFile.Name())
    31  	}()
    32  	rc := helpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: stdoutFile, ErrOut: stderrFile})
    33  	cmd := NewCmdAnalyze(rc)
    34  	assert.NotNil(t, cmd)
    35  	pwd, err := os.Getwd()
    36  	assert.Nil(t, err)
    37  	cmd.PersistentFlags().Set(constants.DirectoryFlagName, pwd+"/"+ingressIPNotFound)
    38  	cmd.PersistentFlags().Set(constants.ReportFormatFlagName, constants.SummaryReport)
    39  	assert.Nil(t, os.Chdir("/"))
    40  	defer os.Chdir(pwd)
    41  	err = cmd.Execute()
    42  	assert.Nil(t, err)
    43  	if fileMatched, _ := filepath.Glob(os.TempDir() + "/" + constants.VzAnalysisReportTmpFile); len(fileMatched) == 1 {
    44  		os.Remove(fileMatched[0])
    45  		assert.NoFileExists(t, fileMatched[0])
    46  	}
    47  }
    48  
    49  // TestAnalyzeCommandDetailedReport
    50  // GIVEN a CLI analyze command
    51  // WHEN I call cmd.Execute with a valid capture-dir and report-format set to "detailed"
    52  // THEN expect the command to provide the report containing all the details for one or more issues reported
    53  func TestAnalyzeCommandDetailedReport(t *testing.T) {
    54  	stdoutFile, stderrFile := createStdTempFiles(t)
    55  	defer func() {
    56  		os.Remove(stdoutFile.Name())
    57  		os.Remove(stderrFile.Name())
    58  	}()
    59  	rc := helpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: stdoutFile, ErrOut: stderrFile})
    60  	cmd := NewCmdAnalyze(rc)
    61  	assert.NotNil(t, cmd)
    62  	cmd.PersistentFlags().Set(constants.DirectoryFlagName, ingressIPNotFound)
    63  	cmd.PersistentFlags().Set(constants.ReportFormatFlagName, constants.DetailedReport)
    64  	err := cmd.Execute()
    65  	assert.Nil(t, err)
    66  	buf, err := os.ReadFile(stdoutFile.Name())
    67  	assert.NoError(t, err)
    68  	assert.Contains(t, string(buf), noIPFoundErr,
    69  		loadBalancerErr)
    70  	// Failures must be reported underreport file details-XXXXXX.out
    71  	if fileMatched, _ := filepath.Glob(constants.VzAnalysisReportTmpFile); len(fileMatched) == 1 {
    72  		os.Remove(fileMatched[0])
    73  		assert.NoFileExists(t, fileMatched[0])
    74  	}
    75  }
    76  
    77  // TestAnalyzeCommandSummaryReport
    78  // GIVEN a CLI analyze command
    79  // WHEN I call cmd.Execute with a valid capture-dir and report-format set to "summary"
    80  // THEN expect the command to provide the report containing only summary for one or more issues reported
    81  func TestAnalyzeCommandSummaryReport(t *testing.T) {
    82  	stdoutFile, stderrFile := createStdTempFiles(t)
    83  	defer func() {
    84  		os.Remove(stdoutFile.Name())
    85  		os.Remove(stderrFile.Name())
    86  	}()
    87  	rc := helpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: stdoutFile, ErrOut: stderrFile})
    88  	cmd := NewCmdAnalyze(rc)
    89  	assert.NotNil(t, cmd)
    90  	cmd.PersistentFlags().Set(constants.DirectoryFlagName, ingressIPNotFound)
    91  	cmd.PersistentFlags().Set(constants.ReportFormatFlagName, constants.SummaryReport)
    92  	err := cmd.Execute()
    93  	assert.Nil(t, err)
    94  	buf, err := os.ReadFile(stdoutFile.Name())
    95  	assert.NoError(t, err)
    96  	assert.NotContains(t, string(buf), loadBalancerErr)
    97  	assert.Contains(t, string(buf), noIPFoundErr)
    98  	// Failures must be reported underreport file details-XXXXXX.out
    99  	if fileMatched, _ := filepath.Glob(constants.VzAnalysisReportTmpFile); len(fileMatched) == 1 {
   100  		os.Remove(fileMatched[0])
   101  		assert.NoFileExists(t, fileMatched[0])
   102  	}
   103  }
   104  
   105  // TestAnalyzeCommandInvalidReportFormat
   106  // GIVEN a CLI analyze command
   107  // WHEN I call cmd.Execute with an invalid value for report-format
   108  // THEN expect the command to fail with an appropriate error message to indicate the issue
   109  func TestAnalyzeCommandInvalidReportFormat(t *testing.T) {
   110  	stdoutFile, stderrFile := createStdTempFiles(t)
   111  	defer func() {
   112  		os.Remove(stdoutFile.Name())
   113  		os.Remove(stderrFile.Name())
   114  	}()
   115  	rc := helpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: stdoutFile, ErrOut: stderrFile})
   116  	cmd := NewCmdAnalyze(rc)
   117  	assert.NotNil(t, cmd)
   118  	cmd.PersistentFlags().Set(constants.DirectoryFlagName, imagePullCase1)
   119  	cmd.PersistentFlags().Set(constants.ReportFormatFlagName, "invalid-report-format")
   120  	err := cmd.Execute()
   121  	assert.NotNil(t, err)
   122  	buf, err := os.ReadFile(stderrFile.Name())
   123  	assert.NoError(t, err)
   124  	assert.Contains(t, string(buf), "\"invalid-report-format\" is not valid for flag report-format, only \"summary\" and \"detailed\" are valid")
   125  }
   126  
   127  // TestAnalyzeWithDefaultReportFormat
   128  // GIVEN a CLI analyze command
   129  // WHEN I call cmd.Execute without report-format
   130  // THEN expect the command to take the default value of summary for report-format and perform the analysis
   131  func TestAnalyzeWithDefaultReportFormat(t *testing.T) {
   132  	stdoutFile, stderrFile := createStdTempFiles(t)
   133  	defer func() {
   134  		os.Remove(stdoutFile.Name())
   135  		os.Remove(stderrFile.Name())
   136  		if fileMatched, _ := filepath.Glob(constants.VzAnalysisReportTmpFile); len(fileMatched) == 1 {
   137  			os.Remove(fileMatched[0])
   138  			assert.NoFileExists(t, fileMatched[0])
   139  		}
   140  	}()
   141  	rc := helpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: stdoutFile, ErrOut: stderrFile})
   142  	cmd := NewCmdAnalyze(rc)
   143  	assert.NotNil(t, cmd)
   144  	cmd.PersistentFlags().Set(constants.DirectoryFlagName, ingressIPNotFound)
   145  	err := cmd.Execute()
   146  	assert.Nil(t, err)
   147  	buf, err := os.ReadFile(stdoutFile.Name())
   148  	assert.NoError(t, err)
   149  	assert.NotContains(t, string(buf), loadBalancerErr)
   150  	assert.Contains(t, string(buf), noIPFoundErr)
   151  }
   152  
   153  // TestAnalyzeWithNonPermissiveReportFile
   154  // GIVEN a CLI analyze command
   155  // WHEN I call cmd.Execute with report-file in read only file location
   156  // THEN expect the command to fail the analysis and do not create report file
   157  func TestAnalyzeWithNonPermissiveReportFile(t *testing.T) {
   158  	stdoutFile, stderrFile := createStdTempFiles(t)
   159  	defer func() {
   160  		os.Remove(stdoutFile.Name())
   161  		os.Remove(stderrFile.Name())
   162  	}()
   163  	rc := helpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: stdoutFile, ErrOut: stderrFile})
   164  	cmd := NewCmdAnalyze(rc)
   165  	assert.NotNil(t, cmd)
   166  	cmd.PersistentFlags().Set(constants.DirectoryFlagName, imagePullCase1)
   167  	cmd.PersistentFlags().Set(constants.ReportFormatFlagName, constants.DetailedReport)
   168  	cmd.PersistentFlags().Set(constants.ReportFileFlagName, "/TestAnalyzeCommandReportFileOutput")
   169  	err := cmd.Execute()
   170  	// Failures must not be reported as report file only has read permissions
   171  	assert.NotNil(t, err)
   172  	assert.NoFileExists(t, "/TestAnalyzeCommandReportFileOutput")
   173  }
   174  
   175  // TestAnalyzeCommandWithReportFile
   176  // GIVEN a CLI analyze command
   177  // WHEN I call cmd.Execute with a valid report-file
   178  // THEN expect the command to create the report file, containing the analysis report
   179  func TestAnalyzeCommandWithReportFile(t *testing.T) {
   180  	stdoutFile, stderrFile := createStdTempFiles(t)
   181  	defer func() {
   182  		os.Remove(stdoutFile.Name())
   183  		os.Remove(stderrFile.Name())
   184  		os.Remove("TestAnalyzeCommandReportFileOutput")
   185  	}()
   186  	rc := helpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: stdoutFile, ErrOut: stderrFile})
   187  	cmd := NewCmdAnalyze(rc)
   188  	assert.NotNil(t, cmd)
   189  	cmd.PersistentFlags().Set(constants.DirectoryFlagName, imagePullCase1)
   190  	cmd.PersistentFlags().Set(constants.ReportFormatFlagName, constants.DetailedReport)
   191  	cmd.PersistentFlags().Set(constants.ReportFileFlagName, "TestAnalyzeCommandReportFileOutput")
   192  	err := cmd.Execute()
   193  	assert.Nil(t, err)
   194  	assert.FileExists(t, "TestAnalyzeCommandReportFileOutput")
   195  }
   196  
   197  // TestAnalyzeCommandInvalidCapturedDir
   198  // GIVEN a CLI analyze command
   199  // WHEN I call cmd.Execute with capture-dir not containing the cluster snapshot
   200  // THEN expect the command to fail with an appropriate error message
   201  func TestAnalyzeCommandInvalidCapturedDir(t *testing.T) {
   202  	stdoutFile, stderrFile := createStdTempFiles(t)
   203  	defer func() {
   204  		os.Remove(stdoutFile.Name())
   205  		os.Remove(stderrFile.Name())
   206  	}()
   207  	rc := helpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: stdoutFile, ErrOut: stderrFile})
   208  	cmd := NewCmdAnalyze(rc)
   209  	assert.NotNil(t, cmd)
   210  	cmd.PersistentFlags().Set(constants.DirectoryFlagName, "../")
   211  	err := cmd.Execute()
   212  	assert.NotNil(t, err)
   213  	buf, err := os.ReadFile(stderrFile.Name())
   214  	assert.NoError(t, err)
   215  	assert.Contains(t, string(buf), "Cluster Analyzer runAnalysis didn't find any clusters")
   216  }
   217  
   218  // createStdTempFiles creates temporary files for stdout and stderr.
   219  func createStdTempFiles(t *testing.T) (*os.File, *os.File) {
   220  	stdoutFile, err := os.CreateTemp("", "tmpstdout")
   221  	assert.NoError(t, err)
   222  
   223  	stderrFile, err := os.CreateTemp("", "tmpstderr")
   224  	assert.NoError(t, err)
   225  
   226  	return stdoutFile, stderrFile
   227  }