github.com/splunk/dan1-qbec@v0.7.3/internal/model/app_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 model
    18  
    19  import (
    20  	"bytes"
    21  	"os"
    22  	"path/filepath"
    23  	"testing"
    24  
    25  	"github.com/splunk/qbec/internal/sio"
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  )
    29  
    30  func setPwd(t *testing.T, dir string) func() {
    31  	wd, err := os.Getwd()
    32  	require.Nil(t, err)
    33  	p, err := filepath.Abs(dir)
    34  	require.Nil(t, err)
    35  	err = os.Chdir(p)
    36  	require.Nil(t, err)
    37  	return func() {
    38  		err = os.Chdir(wd)
    39  		require.Nil(t, err)
    40  	}
    41  }
    42  
    43  func TestAppSimple(t *testing.T) {
    44  	reset := setPwd(t, "../../examples/test-app")
    45  	defer reset()
    46  	app, err := NewApp("qbec.yaml", "")
    47  	require.Nil(t, err)
    48  	a := assert.New(t)
    49  	a.Equal("example1", app.Name())
    50  	a.Equal(2, len(app.inner.Spec.Environments))
    51  	a.Contains(app.inner.Spec.Environments, "dev")
    52  	a.Contains(app.inner.Spec.Environments, "prod")
    53  	a.Equal(4, len(app.allComponents))
    54  	a.Equal(3, len(app.defaultComponents))
    55  	a.Contains(app.allComponents, "service2")
    56  	a.NotContains(app.defaultComponents, "service2")
    57  
    58  	comps, err := app.ComponentsForEnvironment("_", nil, nil)
    59  	require.Nil(t, err)
    60  	require.Equal(t, 3, len(comps))
    61  	a.Equal("cluster-objects", comps[0].Name)
    62  	a.Equal("service1", comps[1].Name)
    63  	a.Equal("test-job", comps[2].Name)
    64  
    65  	comps, err = app.ComponentsForEnvironment("dev", nil, nil)
    66  	require.Nil(t, err)
    67  	require.Equal(t, 3, len(comps))
    68  	a.Equal("cluster-objects", comps[0].Name)
    69  	a.Equal("service2", comps[1].Name)
    70  	a.Equal("test-job", comps[2].Name)
    71  
    72  	comps, err = app.ComponentsForEnvironment("prod", nil, nil)
    73  	require.Nil(t, err)
    74  	require.Equal(t, 4, len(comps))
    75  	a.Equal("cluster-objects", comps[0].Name)
    76  	a.Equal("service1", comps[1].Name)
    77  	a.Equal("service2", comps[2].Name)
    78  	a.Equal("test-job", comps[3].Name)
    79  
    80  	comps, err = app.ComponentsForEnvironment("dev", nil, []string{"service2"})
    81  	require.Nil(t, err)
    82  	require.Equal(t, 2, len(comps))
    83  	a.Equal("cluster-objects", comps[0].Name)
    84  	a.Equal("test-job", comps[1].Name)
    85  
    86  	comps, err = app.ComponentsForEnvironment("dev", []string{"service2"}, nil)
    87  	require.Nil(t, err)
    88  	require.Equal(t, 1, len(comps))
    89  	a.Equal("service2", comps[0].Name)
    90  
    91  	comps, err = app.ComponentsForEnvironment("dev", []string{"service1"}, nil)
    92  	require.Nil(t, err)
    93  	require.Equal(t, 0, len(comps))
    94  
    95  	a.EqualValues(map[string]interface{}{
    96  		"externalFoo": "bar",
    97  	}, app.DeclaredVars())
    98  
    99  	a.EqualValues(map[string]interface{}{
   100  		"tlaFoo": true,
   101  	}, app.DeclaredTopLevelVars())
   102  
   103  	u, err := app.ServerURL("dev")
   104  	require.Nil(t, err)
   105  	a.Equal("https://dev-server", u)
   106  	a.Equal("default", app.DefaultNamespace("dev"))
   107  	a.Equal("", app.Tag())
   108  
   109  	_, err = app.ServerURL("devx")
   110  	require.NotNil(t, err)
   111  	a.Equal(`invalid environment "devx"`, err.Error())
   112  
   113  	a.Equal("params.libsonnet", app.ParamsFile())
   114  	a.Equal("pp.jsonnet", app.PostProcessor())
   115  	a.EqualValues([]string{"lib"}, app.LibPaths())
   116  }
   117  
   118  func TestAppWarnings(t *testing.T) {
   119  	o, c := sio.Output, sio.EnableColors
   120  	defer func() {
   121  		sio.Output = o
   122  		sio.EnableColors = c
   123  	}()
   124  	sio.EnableColors = false
   125  	reset := setPwd(t, "./testdata/bad-app")
   126  	defer reset()
   127  	app, err := NewApp("app-warn.yaml", "foobar")
   128  	require.Nil(t, err)
   129  
   130  	a := assert.New(t)
   131  	buf := bytes.NewBuffer(nil)
   132  	sio.Output = buf
   133  	comps, err := app.ComponentsForEnvironment("dev", nil, nil)
   134  	require.Nil(t, err)
   135  	a.Equal(2, len(comps))
   136  	a.Contains(buf.String(), "component b included from dev is already included by default")
   137  
   138  	buf = bytes.NewBuffer(nil)
   139  	sio.Output = buf
   140  	_, err = app.ComponentsForEnvironment("prod", nil, nil)
   141  	require.Nil(t, err)
   142  	a.Contains(buf.String(), "[warn] component a excluded from prod is already excluded by default")
   143  
   144  	a.Equal("foobar", app.Tag())
   145  	a.Equal("default-foobar", app.DefaultNamespace("dev"))
   146  }
   147  
   148  func TestAppComponentLoadNegative(t *testing.T) {
   149  	reset := setPwd(t, "../../examples/test-app")
   150  	defer reset()
   151  	app, err := NewApp("qbec.yaml", "")
   152  	require.Nil(t, err)
   153  	a := assert.New(t)
   154  
   155  	_, err = app.ComponentsForEnvironment("stage", nil, nil)
   156  	require.NotNil(t, err)
   157  	a.Equal(`invalid environment "stage"`, err.Error())
   158  
   159  	_, err = app.ComponentsForEnvironment("dev", []string{"d"}, nil)
   160  	require.NotNil(t, err)
   161  	a.Equal(`specified components: bad component reference(s): d`, err.Error())
   162  
   163  	_, err = app.ComponentsForEnvironment("dev", nil, []string{"d"})
   164  	require.NotNil(t, err)
   165  	a.Equal(`specified components: bad component reference(s): d`, err.Error())
   166  
   167  	_, err = app.ComponentsForEnvironment("dev", []string{"a"}, []string{"b"})
   168  	require.NotNil(t, err)
   169  	a.Equal(`cannot include as well as exclude components, specify one or the other`, err.Error())
   170  }
   171  
   172  func TestAppNegative(t *testing.T) {
   173  	reset := setPwd(t, "./testdata/bad-app")
   174  	defer reset()
   175  
   176  	tests := []struct {
   177  		tag      string
   178  		file     string
   179  		asserter func(t *testing.T, err error)
   180  	}{
   181  		{
   182  			file: "non-existent.yaml",
   183  			asserter: func(t *testing.T, err error) {
   184  				assert.Contains(t, err.Error(), "no such file or directory")
   185  			},
   186  		},
   187  		{
   188  			file: "bad-yaml.yaml",
   189  			asserter: func(t *testing.T, err error) {
   190  				assert.Contains(t, err.Error(), "converting YAML to JSON")
   191  			},
   192  		},
   193  		{
   194  			file: "bad-comp-exclude.yaml",
   195  			asserter: func(t *testing.T, err error) {
   196  				assert.Contains(t, err.Error(), "default exclusions: bad component reference(s): d")
   197  			},
   198  		},
   199  		{
   200  			file: "bad-env-exclude.yaml",
   201  			asserter: func(t *testing.T, err error) {
   202  				assert.Contains(t, err.Error(), "dev exclusions: bad component reference(s): d")
   203  			},
   204  		},
   205  		{
   206  			file: "bad-env-include.yaml",
   207  			asserter: func(t *testing.T, err error) {
   208  				assert.Contains(t, err.Error(), "dev inclusions: bad component reference(s): d")
   209  			},
   210  		},
   211  		{
   212  			file: "bad-env-include-exclude.yaml",
   213  			asserter: func(t *testing.T, err error) {
   214  				assert.Contains(t, err.Error(), "env dev: component c present in both include and exclude sections")
   215  			},
   216  		},
   217  		{
   218  			file: "bad-baseline-env.yaml",
   219  			asserter: func(t *testing.T, err error) {
   220  				assert.Contains(t, err.Error(), "cannot use _ as an environment name since it has a special meaning")
   221  			},
   222  		},
   223  		{
   224  			file: "bad-comps.yaml",
   225  			asserter: func(t *testing.T, err error) {
   226  				assert.Contains(t, err.Error(), "duplicate component a, found bad-comps/a.json and bad-comps/a.yaml")
   227  			},
   228  		},
   229  		{
   230  			file: "bad-app-name.yaml",
   231  			asserter: func(t *testing.T, err error) {
   232  				assert.Contains(t, err.Error(), "metadata.name in body should match")
   233  			},
   234  		},
   235  		{
   236  			file: "bad-env-name.yaml",
   237  			asserter: func(t *testing.T, err error) {
   238  				assert.Contains(t, err.Error(), "invalid environment foo/bar, must match")
   239  			},
   240  		},
   241  		{
   242  			file: "bad-dup-tla.yaml",
   243  			asserter: func(t *testing.T, err error) {
   244  				assert.Contains(t, err.Error(), "duplicate top-level variable foo")
   245  			},
   246  		},
   247  		{
   248  			file: "bad-dup-ext.yaml",
   249  			asserter: func(t *testing.T, err error) {
   250  				assert.Contains(t, err.Error(), "duplicate external variable foo")
   251  			},
   252  		},
   253  		{
   254  			file: "app-warn.yaml",
   255  			tag:  "-foobar",
   256  			asserter: func(t *testing.T, err error) {
   257  				assert.Contains(t, err.Error(), "invalid tag name '-foobar', must match")
   258  			},
   259  		},
   260  	}
   261  
   262  	for _, test := range tests {
   263  		t.Run(test.file, func(t *testing.T) {
   264  			_, err := NewApp(test.file, test.tag)
   265  			require.NotNil(t, err)
   266  			test.asserter(t, err)
   267  		})
   268  	}
   269  }