github.com/splunk/dan1-qbec@v0.7.3/internal/commands/show_test.go (about)

     1  /*
     2     Copyright 2019 Splunk Inc.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package commands
    18  
    19  import (
    20  	"encoding/base64"
    21  	"regexp"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/stretchr/testify/assert"
    26  	"github.com/stretchr/testify/require"
    27  )
    28  
    29  func TestShowBasic(t *testing.T) {
    30  	s := newScaffold(t)
    31  	defer s.reset()
    32  	err := s.executeCommand("show", "dev")
    33  	require.Nil(t, err)
    34  	out, err := s.yamlOutput()
    35  	require.Nil(t, err)
    36  	a := assert.New(t)
    37  	a.True(len(out) > 0)
    38  	s.assertOutputLineMatch(regexp.MustCompile(`^\s+name: svc2`))
    39  	s.assertOutputLineMatch(regexp.MustCompile(`^\s+qbec\.io/application: example1`))
    40  	s.assertOutputLineMatch(regexp.MustCompile(`^\s+qbec\.io/component: service2`))
    41  	s.assertOutputLineMatch(regexp.MustCompile(`^\s+qbec\.io/environment: dev`))
    42  	pos1 := strings.Index(s.stdout(), "name: foo-system")
    43  	a.True(pos1 > 0)
    44  	pos2 := strings.Index(s.stdout(), "name: 100-default")
    45  	a.True(pos2 > 0)
    46  	a.True(pos1 < pos2) // namespace before psp in std sort
    47  }
    48  
    49  func TestShowBasicClean(t *testing.T) {
    50  	s := newScaffold(t)
    51  	defer s.reset()
    52  	err := s.executeCommand("show", "dev", "--clean")
    53  	require.Nil(t, err)
    54  	out, err := s.yamlOutput()
    55  	require.Nil(t, err)
    56  	a := assert.New(t)
    57  	a.True(len(out) > 0)
    58  	s.assertOutputLineMatch(regexp.MustCompile(`\s+name: svc2`))
    59  	s.assertOutputLineNoMatch(regexp.MustCompile(`qbec\.io/application`))
    60  	s.assertOutputLineNoMatch(regexp.MustCompile(`qbec\.io/component`))
    61  	s.assertOutputLineNoMatch(regexp.MustCompile(`qbec\.io/environment`))
    62  	pos1 := strings.Index(s.stdout(), "name: foo-system")
    63  	a.True(pos1 > 0)
    64  	pos2 := strings.Index(s.stdout(), "name: 100-default")
    65  	a.True(pos2 > 0)
    66  	a.True(pos1 < pos2) // namespace before psp in std sort
    67  }
    68  
    69  func TestShowApplySort(t *testing.T) {
    70  	s := newScaffold(t)
    71  	defer s.reset()
    72  	err := s.executeCommand("show", "dev", "--sort-apply")
    73  	require.Nil(t, err)
    74  	out, err := s.yamlOutput()
    75  	require.Nil(t, err)
    76  	assert.True(t, len(out) > 0)
    77  	pos1 := strings.Index(s.stdout(), "name: foo-system")
    78  	pos2 := strings.Index(s.stdout(), "name: 100-default")
    79  	assert.True(t, pos1 > pos2) // namespace after psp in apply sort
    80  }
    81  
    82  func TestShowApplySortBaseline(t *testing.T) {
    83  	s := newScaffold(t)
    84  	defer s.reset()
    85  	err := s.executeCommand("show", "_", "--sort-apply")
    86  	require.Nil(t, err)
    87  	out, err := s.yamlOutput()
    88  	require.Nil(t, err)
    89  	a := assert.New(t)
    90  	a.True(len(out) > 0)
    91  	pos1 := strings.Index(s.stdout(), "name: foo-system")
    92  	pos2 := strings.Index(s.stdout(), "name: 100-default")
    93  	a.True(pos2 > pos1) // no apply sort
    94  	a.Contains(s.stderr(), "[warn] cannot sort in apply order for baseline environment")
    95  }
    96  
    97  func TestShowBasicJSON(t *testing.T) {
    98  	s := newScaffold(t)
    99  	defer s.reset()
   100  	err := s.executeCommand("show", "dev", "-o", "json")
   101  	require.Nil(t, err)
   102  	var data interface{}
   103  	err = s.jsonOutput(&data)
   104  	require.Nil(t, err)
   105  	s.assertOutputLineMatch(regexp.MustCompile(`\s+"name": "svc2-cm"`))
   106  }
   107  
   108  func TestShowObjects(t *testing.T) {
   109  	s := newScaffold(t)
   110  	defer s.reset()
   111  	err := s.executeCommand("show", "dev", "-O")
   112  	require.Nil(t, err)
   113  	s.assertOutputLineMatch(regexp.MustCompile(`service2\s+ConfigMap\s+svc2-cm\s+bar-system`))
   114  	s.assertOutputLineMatch(regexp.MustCompile(`cluster-objects\s+Namespace\s+bar-system`))
   115  }
   116  
   117  func TestShowObjectsAsYAML(t *testing.T) {
   118  	s := newScaffold(t)
   119  	defer s.reset()
   120  	err := s.executeCommand("show", "dev", "-O", "-o", "yaml")
   121  	require.Nil(t, err)
   122  	out, err := s.yamlOutput()
   123  	require.Nil(t, err)
   124  	assert.True(t, len(out) > 0)
   125  	s.assertOutputLineMatch(regexp.MustCompile(`\s+name: svc2`))
   126  }
   127  
   128  func TestShowObjectsAsJSON(t *testing.T) {
   129  	s := newScaffold(t)
   130  	defer s.reset()
   131  	err := s.executeCommand("show", "dev", "-O", "-o", "json")
   132  	require.Nil(t, err)
   133  	var data interface{}
   134  	err = s.jsonOutput(&data)
   135  	require.Nil(t, err)
   136  	s.assertOutputLineMatch(regexp.MustCompile(`\s+"name": "svc2-cm"`))
   137  }
   138  
   139  func TestShowObjectsComponentFilter(t *testing.T) {
   140  	s := newScaffold(t)
   141  	defer s.reset()
   142  	err := s.executeCommand("show", "dev", "-c", "cluster-objects")
   143  	require.Nil(t, err)
   144  	out, err := s.yamlOutput()
   145  	require.Nil(t, err)
   146  	assert.True(t, len(out) > 0)
   147  	s.assertOutputLineMatch(regexp.MustCompile(`\s+name: bar-system`))
   148  	s.assertOutputLineNoMatch(regexp.MustCompile(`\s+name: svc2`))
   149  }
   150  
   151  func TestShowObjectsComponentFilter2(t *testing.T) {
   152  	s := newScaffold(t)
   153  	defer s.reset()
   154  	err := s.executeCommand("show", "dev", "-C", "cluster-objects")
   155  	require.Nil(t, err)
   156  	out, err := s.yamlOutput()
   157  	require.Nil(t, err)
   158  	assert.True(t, len(out) > 0)
   159  	s.assertOutputLineNoMatch(regexp.MustCompile(`\s+name: bar-system`))
   160  	s.assertOutputLineMatch(regexp.MustCompile(`\s+name: svc2`))
   161  }
   162  
   163  func TestShowObjectsKindFilter(t *testing.T) {
   164  	s := newScaffold(t)
   165  	defer s.reset()
   166  	err := s.executeCommand("show", "dev", "-k", "secret")
   167  	require.Nil(t, err)
   168  	out, err := s.yamlOutput()
   169  	require.Nil(t, err)
   170  	assert.True(t, len(out) > 0)
   171  	s.assertOutputLineNoMatch(regexp.MustCompile(`\s+name: bar-system`))
   172  	s.assertOutputLineMatch(regexp.MustCompile(`\s+name: svc2-secret`))
   173  }
   174  
   175  func TestShowObjectsKindFilter2(t *testing.T) {
   176  	s := newScaffold(t)
   177  	defer s.reset()
   178  	err := s.executeCommand("show", "dev", "-K", "secret")
   179  	require.Nil(t, err)
   180  	out, err := s.yamlOutput()
   181  	require.Nil(t, err)
   182  	assert.True(t, len(out) > 0)
   183  	s.assertOutputLineNoMatch(regexp.MustCompile(`\s+name: svc2-secret`))
   184  	s.assertOutputLineMatch(regexp.MustCompile(`\s+name: bar-system`))
   185  }
   186  
   187  func TestShowObjectsKindFilter3(t *testing.T) {
   188  	s := newScaffold(t)
   189  	defer s.reset()
   190  	err := s.executeCommand("show", "dev", "-k", "garbage")
   191  	require.Nil(t, err)
   192  	out, err := s.yamlOutput()
   193  	require.Nil(t, err)
   194  	assert.True(t, len(out) == 0)
   195  	assert.Contains(t, s.stderr(), "matches for kind filter, check for typos and abbreviations")
   196  }
   197  
   198  func TestShowHiddenSecrets(t *testing.T) {
   199  	s := newScaffold(t)
   200  	defer s.reset()
   201  	secretValue := base64.StdEncoding.EncodeToString([]byte("bar"))
   202  	redactedValue := base64.RawStdEncoding.EncodeToString([]byte("redacted."))
   203  	err := s.executeCommand("show", "dev", "-k", "secret")
   204  	require.Nil(t, err)
   205  	s.assertOutputLineMatch(regexp.MustCompile(redactedValue))
   206  	s.assertOutputLineNoMatch(regexp.MustCompile(secretValue))
   207  }
   208  
   209  func TestShowOpenSecrets(t *testing.T) {
   210  	s := newScaffold(t)
   211  	defer s.reset()
   212  	secretValue := base64.StdEncoding.EncodeToString([]byte("bar"))
   213  	redactedValue := base64.RawStdEncoding.EncodeToString([]byte("redacted."))
   214  	err := s.executeCommand("show", "dev", "-k", "secret", "-S")
   215  	require.Nil(t, err)
   216  	s.assertOutputLineNoMatch(regexp.MustCompile(redactedValue))
   217  	s.assertOutputLineMatch(regexp.MustCompile(secretValue))
   218  }
   219  
   220  func TestShowNegative(t *testing.T) {
   221  	tests := []struct {
   222  		name     string
   223  		args     []string
   224  		asserter func(s *scaffold, err error)
   225  		dir      string
   226  	}{
   227  		{
   228  			name: "no env",
   229  			args: []string{"show"},
   230  			asserter: func(s *scaffold, err error) {
   231  				a := assert.New(s.t)
   232  				a.True(isUsageError(err))
   233  				a.Equal("exactly one environment required", err.Error())
   234  			},
   235  		},
   236  		{
   237  			name: "2 envs",
   238  			args: []string{"show", "dev", "prod"},
   239  			asserter: func(s *scaffold, err error) {
   240  				a := assert.New(s.t)
   241  				a.True(isUsageError(err))
   242  				a.Equal("exactly one environment required", err.Error())
   243  			},
   244  		},
   245  		{
   246  			name: "bad env",
   247  			args: []string{"show", "foo"},
   248  			asserter: func(s *scaffold, err error) {
   249  				a := assert.New(s.t)
   250  				a.False(isUsageError(err))
   251  				a.Equal("invalid environment \"foo\"", err.Error())
   252  			},
   253  		},
   254  		{
   255  			name: "bad format",
   256  			args: []string{"show", "dev", "-o", "table"},
   257  			asserter: func(s *scaffold, err error) {
   258  				a := assert.New(s.t)
   259  				a.True(isUsageError(err))
   260  				a.Equal(`invalid output format: "table"`, err.Error())
   261  			},
   262  		},
   263  		{
   264  			name: "c and C",
   265  			args: []string{"show", "dev", "-c", "cluster-objects", "-C", "service2"},
   266  			asserter: func(s *scaffold, err error) {
   267  				a := assert.New(s.t)
   268  				a.True(isUsageError(err))
   269  				a.Equal(`cannot include as well as exclude components, specify one or the other`, err.Error())
   270  			},
   271  		},
   272  		{
   273  			name: "k and K",
   274  			args: []string{"show", "dev", "-k", "namespace", "-K", "secret"},
   275  			asserter: func(s *scaffold, err error) {
   276  				a := assert.New(s.t)
   277  				a.True(isUsageError(err))
   278  				a.Equal(`cannot include as well as exclude kinds, specify one or the other`, err.Error())
   279  			},
   280  		},
   281  		{
   282  			name: "duplicate objects",
   283  			args: []string{"show", "dev"},
   284  			asserter: func(s *scaffold, err error) {
   285  				a := assert.New(s.t)
   286  				a.True(IsRuntimeError(err))
   287  				a.Equal(`duplicate objects ConfigMap cm1 (component: x) and ConfigMap cm1 (component: y)`, err.Error())
   288  			},
   289  			dir: "testdata/dups",
   290  		},
   291  	}
   292  	for _, test := range tests {
   293  		t.Run(test.name, func(t *testing.T) {
   294  			s := newCustomScaffold(t, test.dir)
   295  			defer s.reset()
   296  			err := s.executeCommand(test.args...)
   297  			require.NotNil(t, err)
   298  			test.asserter(s, err)
   299  		})
   300  	}
   301  }