github.com/verrazzano/verrazzano@v1.7.1/tools/psr/psrctl/cmd/start/start_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 start
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/base64"
     9  	"fmt"
    10  	"os"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  	helmcli "github.com/verrazzano/verrazzano/pkg/helm"
    15  	"github.com/verrazzano/verrazzano/pkg/k8sutil"
    16  	"github.com/verrazzano/verrazzano/pkg/log/vzlog"
    17  	"github.com/verrazzano/verrazzano/tools/psr/psrctl/cmd/constants"
    18  	"github.com/verrazzano/verrazzano/tools/psr/psrctl/pkg/manifest"
    19  	"github.com/verrazzano/verrazzano/tools/psr/psrctl/pkg/scenario"
    20  	"github.com/verrazzano/verrazzano/tools/vz/test/helpers"
    21  	"helm.sh/helm/v3/pkg/release"
    22  	corev1 "k8s.io/api/core/v1"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	"k8s.io/cli-runtime/pkg/genericclioptions"
    25  	k8sfake "k8s.io/client-go/kubernetes/fake"
    26  	corev1cli "k8s.io/client-go/kubernetes/typed/core/v1"
    27  )
    28  
    29  const psrRoot = "../../.."
    30  
    31  var ID = "ops-s1"
    32  
    33  // TestStartCmd tests the NewCmdStart and RunCmdStart functions
    34  //
    35  //	WHEN 'psrctl start -s ops-s1 -n psr' is called
    36  //	THEN ensure the new scenario gets started
    37  func TestStartCmd(t *testing.T) {
    38  	manifest.Manifests = &manifest.PsrManifests{
    39  		RootTmpDir:        psrRoot,
    40  		WorkerChartAbsDir: psrRoot + "/manifests/charts/worker",
    41  		UseCasesAbsDir:    psrRoot + "/manifests/usecases",
    42  		ScenarioAbsDir:    psrRoot + "/manifests/scenarios",
    43  	}
    44  
    45  	defer manifest.ResetManifests()
    46  
    47  	defer func() { k8sutil.GetCoreV1Func = k8sutil.GetCoreV1Client }()
    48  	k8sutil.GetCoreV1Func = func(log ...vzlog.VerrazzanoLogger) (corev1cli.CoreV1Interface, error) {
    49  		return k8sfake.NewSimpleClientset().CoreV1(), nil
    50  	}
    51  
    52  	defer func() { scenario.StartUpgradeFunc = helmcli.Upgrade }()
    53  	scenario.StartUpgradeFunc = func(log vzlog.VerrazzanoLogger, releaseName string, namespace string, chartDir string, wait bool, dryRun bool, overrides []helmcli.HelmOverrides) (*release.Release, error) {
    54  		assert.Equal(t, 4, len(overrides))
    55  		assert.Equal(t, "psr-ops-s1-ops-writelogs-0", releaseName)
    56  		assert.Equal(t, "psr", namespace)
    57  		assert.Contains(t, chartDir, "manifests/charts/worker")
    58  
    59  		return nil, nil
    60  	}
    61  
    62  	// Send the command output to a byte buffer
    63  	buf := new(bytes.Buffer)
    64  	errBuf := new(bytes.Buffer)
    65  	rc := helpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
    66  
    67  	cmd := NewCmdStart(rc)
    68  	cmd.PersistentFlags().Set(constants.FlagScenario, "ops-s1")
    69  	cmd.PersistentFlags().Set(constants.FlagNamespace, "psr")
    70  	assert.NotNil(t, cmd)
    71  
    72  	// Run start command, check for the expected status results to be displayed
    73  	err := cmd.Execute()
    74  	assert.NoError(t, err)
    75  	result := buf.String()
    76  
    77  	assert.Contains(t, result, fmt.Sprintf("Starting scenario %s", ID))
    78  	assert.Contains(t, result, fmt.Sprintf("Scenario %s successfully started", ID))
    79  }
    80  
    81  // TestStartExisting tests the NewCmdStart and RunCmdStart functions
    82  //
    83  //	WHEN 'psrctl start -s ops-s1 -n psr' is called when the scenario is already running
    84  //	THEN ensure the output correctly tells the user their operation is invalid
    85  func TestStartExisting(t *testing.T) {
    86  	manifest.Manifests = &manifest.PsrManifests{
    87  		RootTmpDir:        psrRoot,
    88  		WorkerChartAbsDir: psrRoot + "/manifests/charts/worker",
    89  		UseCasesAbsDir:    psrRoot + "/manifests/usecases",
    90  		ScenarioAbsDir:    psrRoot + "/manifests/scenarios",
    91  	}
    92  
    93  	// create scenario ConfigMap
    94  	cm := &corev1.ConfigMap{
    95  		ObjectMeta: metav1.ObjectMeta{
    96  			Name:      "psr-ops-s1",
    97  			Namespace: "psr",
    98  			Labels: map[string]string{
    99  				"psr.verrazzano.io/scenario":    "true",
   100  				"psr.verrazzano.io/scenario-id": "ops-s1",
   101  			},
   102  		},
   103  		Data: map[string]string{
   104  			"scenario": base64.StdEncoding.EncodeToString([]byte(`Description: "This is a scenario that writes logs to STDOUT and gets logs from OpenSearch
   105    at a moderated rate. \nThe purpose of the scenario is to test a moderate load on
   106    both Fluend and OpenSearch by logging records.\n"
   107  HelmReleases:
   108  - Description: write logs to STDOUT 10 times a second
   109    Name: psr-ops-s1-writelogs-0
   110    Namespace: psr
   111    OverrideFile: writelogs.yaml
   112    UsecasePath: opensearch/writelogs.yaml
   113  ID: ops-s1
   114  Name: opensearch-s1
   115  Namespace: default
   116  ScenarioUsecaseOverridesAbsDir: temp-dir
   117  Usecases:
   118  - Description: write logs to STDOUT 10 times a second
   119    OverrideFile: writelogs.yaml
   120    UsecasePath: opensearch/writelogs.yaml
   121  `)),
   122  		},
   123  	}
   124  
   125  	defer func() { k8sutil.GetCoreV1Func = k8sutil.GetCoreV1Client }()
   126  	k8sutil.GetCoreV1Func = func(log ...vzlog.VerrazzanoLogger) (corev1cli.CoreV1Interface, error) {
   127  		return k8sfake.NewSimpleClientset(cm).CoreV1(), nil
   128  	}
   129  
   130  	// Send the command output to a byte buffer
   131  	buf := new(bytes.Buffer)
   132  	errBuf := new(bytes.Buffer)
   133  	rc := helpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   134  
   135  	cmd := NewCmdStart(rc)
   136  	cmd.PersistentFlags().Set(constants.FlagScenario, "ops-s1")
   137  	cmd.PersistentFlags().Set(constants.FlagNamespace, "psr")
   138  	assert.NotNil(t, cmd)
   139  
   140  	// Run start command, check for the expected error to be thrown
   141  	err := cmd.Execute()
   142  	assert.Error(t, err)
   143  	assert.Contains(t, err.Error(), fmt.Sprintf("Scenario %s already running in namespace psr", ID))
   144  
   145  	result := buf.String()
   146  	assert.Contains(t, result, fmt.Sprintf("Starting scenario %s", ID))
   147  }
   148  
   149  // TestStartInvalid tests the NewCmdStart and RunCmdStart functions
   150  //
   151  //	WHEN 'psrctl start -s bad-manifest -n psr' is called when the scenario does not exist
   152  //	THEN ensure the output correctly tells the user their operation is invalid
   153  func TestStartInvalid(t *testing.T) {
   154  
   155  	manifest.Manifests = &manifest.PsrManifests{
   156  		RootTmpDir:        psrRoot,
   157  		WorkerChartAbsDir: psrRoot + "/manifests/charts/worker",
   158  		UseCasesAbsDir:    psrRoot + "/manifests/usecases",
   159  		ScenarioAbsDir:    psrRoot + "/manifests/scenarios",
   160  	}
   161  
   162  	defer func() { k8sutil.GetCoreV1Func = k8sutil.GetCoreV1Client }()
   163  	k8sutil.GetCoreV1Func = func(log ...vzlog.VerrazzanoLogger) (corev1cli.CoreV1Interface, error) {
   164  		return k8sfake.NewSimpleClientset().CoreV1(), nil
   165  	}
   166  
   167  	// Send the command output to a byte buffer
   168  	buf := new(bytes.Buffer)
   169  	errBuf := new(bytes.Buffer)
   170  	rc := helpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   171  
   172  	cmd := NewCmdStart(rc)
   173  	cmd.PersistentFlags().Set(constants.FlagScenario, "bad-manifest")
   174  	cmd.PersistentFlags().Set(constants.FlagNamespace, "psr")
   175  	assert.NotNil(t, cmd)
   176  
   177  	// Run start command, check for the expected status results to be displayed
   178  	err := cmd.Execute()
   179  	assert.Error(t, err)
   180  	result := err.Error()
   181  
   182  	assert.Contains(t, result, "Failed to find scenario manifest with ID bad-manifest")
   183  }
   184  
   185  // TestStartDir tests the NewCmdStart and RunCmdStart functions
   186  //
   187  //	WHEN 'psrctl start -s ops-test -d psrctl/testdata/ops-test' is called
   188  //	THEN ensure the new scenario gets started
   189  func TestStartDir(t *testing.T) {
   190  	manifest.Manifests = &manifest.PsrManifests{
   191  		RootTmpDir:        psrRoot,
   192  		WorkerChartAbsDir: psrRoot + "/manifests/charts/worker",
   193  		UseCasesAbsDir:    psrRoot + "/manifests/usecases",
   194  		ScenarioAbsDir:    psrRoot + "/manifests/scenarios",
   195  	}
   196  
   197  	defer manifest.ResetManifests()
   198  
   199  	defer func() { k8sutil.GetCoreV1Func = k8sutil.GetCoreV1Client }()
   200  	k8sutil.GetCoreV1Func = func(log ...vzlog.VerrazzanoLogger) (corev1cli.CoreV1Interface, error) {
   201  		return k8sfake.NewSimpleClientset().CoreV1(), nil
   202  	}
   203  
   204  	defer func() { scenario.StartUpgradeFunc = helmcli.Upgrade }()
   205  	scenario.StartUpgradeFunc = func(log vzlog.VerrazzanoLogger, releaseName string, namespace string, chartDir string, wait bool, dryRun bool, overrides []helmcli.HelmOverrides) (*release.Release, error) {
   206  		assert.Equal(t, 4, len(overrides))
   207  		assert.Equal(t, "psr-ops-test-ops-writelogs-0", releaseName)
   208  		assert.Equal(t, "default", namespace)
   209  		assert.Contains(t, chartDir, "manifests/charts/worker")
   210  
   211  		return nil, nil
   212  	}
   213  
   214  	// Send the command output to a byte buffer
   215  	buf := new(bytes.Buffer)
   216  	errBuf := new(bytes.Buffer)
   217  	rc := helpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   218  
   219  	cmd := NewCmdStart(rc)
   220  	cmd.PersistentFlags().Set(constants.FlagScenario, "ops-test")
   221  	cmd.PersistentFlags().Set(constants.FlagScenarioDir, "../../testdata/ops-test")
   222  	assert.NotNil(t, cmd)
   223  
   224  	// Run start command, check for the expected status results to be displayed
   225  	err := cmd.Execute()
   226  	assert.NoError(t, err)
   227  	result := buf.String()
   228  
   229  	assert.Contains(t, result, "Starting scenario ops-test")
   230  	assert.Contains(t, result, "Scenario ops-test successfully started")
   231  }
   232  
   233  // TestStartDirError tests the NewCmdStart and RunCmdStart functions
   234  //
   235  //	WHEN 'psrctl start -d psrctl/testdata/ops-test' is called without the scenario name
   236  //	THEN ensure the output correctly tells the user their operation is invalid
   237  func TestStartDirError(t *testing.T) {
   238  	manifest.Manifests = &manifest.PsrManifests{
   239  		RootTmpDir:        psrRoot,
   240  		WorkerChartAbsDir: psrRoot + "/manifests/charts/worker",
   241  		UseCasesAbsDir:    psrRoot + "/manifests/usecases",
   242  		ScenarioAbsDir:    psrRoot + "/manifests/scenarios",
   243  	}
   244  
   245  	defer func() { k8sutil.GetCoreV1Func = k8sutil.GetCoreV1Client }()
   246  	k8sutil.GetCoreV1Func = func(log ...vzlog.VerrazzanoLogger) (corev1cli.CoreV1Interface, error) {
   247  		return k8sfake.NewSimpleClientset().CoreV1(), nil
   248  	}
   249  
   250  	// Send the command output to a byte buffer
   251  	buf := new(bytes.Buffer)
   252  	errBuf := new(bytes.Buffer)
   253  	rc := helpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   254  
   255  	cmd := NewCmdStart(rc)
   256  	cmd.PersistentFlags().Set(constants.FlagScenarioDir, "../../testdata/ops-test")
   257  	assert.NotNil(t, cmd)
   258  
   259  	// Run start command, check for the expected status results to be displayed
   260  	err := cmd.Execute()
   261  	assert.Error(t, err)
   262  	result := err.Error()
   263  
   264  	assert.Contains(t, result, "Failed to find scenario manifest with ID")
   265  }