github.com/buildtool/build-tools@v0.2.29-0.20240322150259-6a1d0a553c23/pkg/config/config_test.go (about)

     1  // MIT License
     2  //
     3  // Copyright (c) 2018 buildtool
     4  //
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy
     6  // of this software and associated documentation files (the "Software"), to deal
     7  // in the Software without restriction, including without limitation the rights
     8  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9  // copies of the Software, and to permit persons to whom the Software is
    10  // furnished to do so, subject to the following conditions:
    11  //
    12  // The above copyright notice and this permission notice shall be included in all
    13  // copies or substantial portions of the Software.
    14  //
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    17  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    18  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    19  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    20  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    21  // SOFTWARE.
    22  
    23  package config
    24  
    25  import (
    26  	"encoding/base64"
    27  	"errors"
    28  	"fmt"
    29  	"os"
    30  	"path/filepath"
    31  	"testing"
    32  
    33  	"github.com/apex/log"
    34  	"github.com/stretchr/testify/assert"
    35  	mocks "gitlab.com/unboundsoftware/apex-mocks"
    36  
    37  	"github.com/buildtool/build-tools/pkg"
    38  	"github.com/buildtool/build-tools/pkg/ci"
    39  	"github.com/buildtool/build-tools/pkg/registry"
    40  )
    41  
    42  var name string
    43  
    44  func TestMain(m *testing.M) {
    45  	tempDir := setup()
    46  	code := m.Run()
    47  	teardown(tempDir)
    48  	os.Exit(code)
    49  }
    50  
    51  func setup() string {
    52  	name, _ = os.MkdirTemp(os.TempDir(), "build-tools")
    53  
    54  	return name
    55  }
    56  
    57  func teardown(tempDir string) {
    58  	_ = os.RemoveAll(tempDir)
    59  }
    60  
    61  func TestLoad_AbsFail(t *testing.T) {
    62  	os.Clearenv()
    63  
    64  	abs = func(path string) (s string, e error) {
    65  		return "", errors.New("abs-error")
    66  	}
    67  
    68  	logMock := mocks.New()
    69  	log.SetHandler(logMock)
    70  	log.SetLevel(log.DebugLevel)
    71  	_, err := Load("test")
    72  	assert.EqualError(t, err, "abs-error")
    73  	logMock.Check(t, []string{})
    74  	abs = filepath.Abs
    75  }
    76  
    77  func TestLoad_Empty(t *testing.T) {
    78  	os.Clearenv()
    79  	name, _ := os.MkdirTemp(os.TempDir(), "build-tools")
    80  	defer func() { _ = os.RemoveAll(name) }()
    81  
    82  	logMock := mocks.New()
    83  	log.SetHandler(logMock)
    84  	log.SetLevel(log.DebugLevel)
    85  	cfg, err := Load(name)
    86  	assert.NoError(t, err)
    87  	assert.NotNil(t, cfg)
    88  	assert.NotNil(t, cfg.CI)
    89  	assert.Equal(t, ci.No{}.Name(), cfg.CurrentCI().Name())
    90  	assert.NotNil(t, cfg.Registry)
    91  	logMock.Check(t, []string{})
    92  }
    93  
    94  func TestLoad_BrokenYAML(t *testing.T) {
    95  	name, _ := os.MkdirTemp(os.TempDir(), "build-tools")
    96  	defer func() { _ = os.RemoveAll(name) }()
    97  	yaml := `ci: []
    98  `
    99  	_ = os.WriteFile(filepath.Join(name, ".buildtools.yaml"), []byte(yaml), 0777)
   100  
   101  	logMock := mocks.New()
   102  	log.SetHandler(logMock)
   103  	log.SetLevel(log.DebugLevel)
   104  	cfg, err := Load(name)
   105  	assert.EqualError(t, err, "yaml: unmarshal errors:\n  line 1: cannot unmarshal !!seq into config.CIConfig")
   106  	assert.NotNil(t, cfg)
   107  	assert.NotNil(t, cfg.CI)
   108  	assert.Equal(t, ci.No{}.Name(), cfg.CurrentCI().Name())
   109  	assert.NotNil(t, cfg.Registry)
   110  	logMock.Check(t, []string{fmt.Sprintf("debug: Parsing config from file: <green>'%s/.buildtools.yaml'</green>\n", name)})
   111  }
   112  
   113  func TestLoad_UnreadableFile(t *testing.T) {
   114  	name, _ := os.MkdirTemp(os.TempDir(), "build-tools")
   115  	defer func() { _ = os.RemoveAll(name) }()
   116  	filename := filepath.Join(name, ".buildtools.yaml")
   117  	_ = os.Mkdir(filename, 0777)
   118  
   119  	logMock := mocks.New()
   120  	log.SetHandler(logMock)
   121  	log.SetLevel(log.DebugLevel)
   122  	cfg, err := Load(name)
   123  	assert.EqualError(t, err, fmt.Sprintf("read %s: is a directory", filename))
   124  	assert.NotNil(t, cfg)
   125  	assert.NotNil(t, cfg.CI)
   126  	assert.Equal(t, ci.No{}.Name(), cfg.CurrentCI().Name())
   127  	assert.NotNil(t, cfg.Registry)
   128  	logMock.Check(t, []string{fmt.Sprintf("debug: Parsing config from file: <green>'%s/.buildtools.yaml'</green>\n", name)})
   129  }
   130  
   131  func TestLoad_YAML(t *testing.T) {
   132  	name, _ := os.MkdirTemp(os.TempDir(), "build-tools")
   133  	defer func() { _ = os.RemoveAll(name) }()
   134  	yaml := `
   135  registry:
   136    ecr:
   137      url: 1234.dkr.ecr.eu-west-1.amazonaws.com
   138      region: eu-west-1
   139  targets:
   140    local:
   141      context: docker-desktop
   142    dev:
   143      context: docker-desktop
   144      namespace: dev
   145  `
   146  	_ = os.WriteFile(filepath.Join(name, ".buildtools.yaml"), []byte(yaml), 0777)
   147  
   148  	logMock := mocks.New()
   149  	log.SetHandler(logMock)
   150  	log.SetLevel(log.DebugLevel)
   151  	cfg, err := Load(name)
   152  	assert.NoError(t, err)
   153  	assert.NotNil(t, cfg)
   154  	assert.NotNil(t, cfg.CI)
   155  	assert.Equal(t, ci.No{}.Name(), cfg.CurrentCI().Name())
   156  
   157  	assert.NotNil(t, cfg.Registry)
   158  	assert.Equal(t, "eu-west-1", cfg.CurrentRegistry().(*registry.ECR).Region)
   159  	assert.Equal(t, "1234.dkr.ecr.eu-west-1.amazonaws.com", cfg.CurrentRegistry().(*registry.ECR).Url)
   160  	assert.Equal(t, 2, len(cfg.Targets))
   161  	assert.Equal(t, Target{Context: "docker-desktop"}, cfg.Targets["local"])
   162  	devEnv := Target{Context: "docker-desktop", Namespace: "dev"}
   163  	assert.Equal(t, devEnv, cfg.Targets["dev"])
   164  
   165  	currentEnv, err := cfg.CurrentTarget("dev")
   166  	assert.NoError(t, err)
   167  	assert.Equal(t, &devEnv, currentEnv)
   168  	_, err = cfg.CurrentTarget("missing")
   169  	assert.EqualError(t, err, "no target matching missing found")
   170  	logMock.Check(t, []string{fmt.Sprintf("debug: Parsing config from file: <green>'%s/.buildtools.yaml'</green>\n", name)})
   171  }
   172  
   173  func TestLoad_BrokenYAML_From_Env(t *testing.T) {
   174  	name, _ := os.MkdirTemp(os.TempDir(), "build-tools")
   175  	defer func() { _ = os.RemoveAll(name) }()
   176  	yaml := `ci: []
   177  `
   178  	defer pkg.SetEnv(envBuildtoolsContent, base64.StdEncoding.EncodeToString([]byte(yaml)))()
   179  
   180  	logMock := mocks.New()
   181  	log.SetHandler(logMock)
   182  	log.SetLevel(log.DebugLevel)
   183  	cfg, err := Load(name)
   184  	assert.EqualError(t, err, "yaml: unmarshal errors:\n  line 1: cannot unmarshal !!seq into config.CIConfig")
   185  	assert.NotNil(t, cfg)
   186  	assert.NotNil(t, cfg.CI)
   187  	assert.Equal(t, ci.No{}.Name(), cfg.CurrentCI().Name())
   188  	assert.NotNil(t, cfg.Registry)
   189  	logMock.Check(t, []string{"debug: Parsing config from env: BUILDTOOLS_CONTENT\n"})
   190  }
   191  
   192  func TestLoad_YAML_From_Env_Plain(t *testing.T) {
   193  	name, _ := os.MkdirTemp(os.TempDir(), "build-tools")
   194  	defer func() { _ = os.RemoveAll(name) }()
   195  	yaml := `
   196  targets:
   197    local:
   198      context: docker-desktop
   199  `
   200  	defer pkg.SetEnv(envBuildtoolsContent, yaml)()
   201  
   202  	logMock := mocks.New()
   203  	log.SetHandler(logMock)
   204  	log.SetLevel(log.DebugLevel)
   205  	cfg, err := Load(name)
   206  	assert.NoError(t, err)
   207  	logMock.Check(t, []string{"debug: Parsing config from env: BUILDTOOLS_CONTENT\n",
   208  		"debug: Failed to decode BASE64, falling back to plaintext\n"})
   209  	assert.Equal(t, len(cfg.Targets), 1)
   210  	assert.Equal(t, cfg.Targets["local"].Context, "docker-desktop")
   211  }
   212  
   213  func TestLoad_Broken_YAML_From_Env_Plain(t *testing.T) {
   214  	name, _ := os.MkdirTemp(os.TempDir(), "build-tools")
   215  	defer func() { _ = os.RemoveAll(name) }()
   216  	yaml := `
   217  target:
   218    local:
   219      context: docker-desktop
   220  `
   221  	defer pkg.SetEnv(envBuildtoolsContent, yaml)()
   222  
   223  	_, err := Load(name)
   224  	assert.Error(t, err)
   225  	assert.EqualError(t, err, "yaml: unmarshal errors:\n  line 2: field target not found in type config.Config")
   226  }
   227  
   228  func TestLoad_YAML_From_Env(t *testing.T) {
   229  	name, _ := os.MkdirTemp(os.TempDir(), "build-tools")
   230  	defer func() { _ = os.RemoveAll(name) }()
   231  	yaml := `
   232  targets:
   233    local:
   234      context: docker-desktop
   235    dev:
   236      context: docker-desktop
   237      namespace: dev
   238  `
   239  	defer pkg.SetEnv(envBuildtoolsContent, base64.StdEncoding.EncodeToString([]byte(yaml)))()
   240  
   241  	logMock := mocks.New()
   242  	log.SetHandler(logMock)
   243  	log.SetLevel(log.DebugLevel)
   244  	cfg, err := Load(name)
   245  	assert.NoError(t, err)
   246  	assert.NotNil(t, cfg)
   247  	assert.Equal(t, 2, len(cfg.Targets))
   248  	assert.Equal(t, Target{Context: "docker-desktop"}, cfg.Targets["local"])
   249  	devEnv := Target{Context: "docker-desktop", Namespace: "dev"}
   250  	assert.Equal(t, devEnv, cfg.Targets["dev"])
   251  
   252  	currentEnv, err := cfg.CurrentTarget("dev")
   253  	assert.NoError(t, err)
   254  	assert.Equal(t, &devEnv, currentEnv)
   255  	_, err = cfg.CurrentTarget("missing")
   256  	assert.EqualError(t, err, "no target matching missing found")
   257  	logMock.Check(t, []string{"debug: Parsing config from env: BUILDTOOLS_CONTENT\n"})
   258  }
   259  
   260  func TestLoad_YAML_DirStructure(t *testing.T) {
   261  	os.Clearenv()
   262  	name, _ := os.MkdirTemp(os.TempDir(), "build-tools")
   263  	defer func() { _ = os.RemoveAll(name) }()
   264  	yaml := `
   265  registry:
   266    dockerhub:
   267      namespace: test
   268  targets:
   269    test:
   270      context: abc
   271    local:
   272      context: def
   273  `
   274  	_ = os.WriteFile(filepath.Join(name, ".buildtools.yaml"), []byte(yaml), 0777)
   275  	subdir := "sub"
   276  	_ = os.Mkdir(filepath.Join(name, subdir), 0777)
   277  	yaml2 := `
   278  targets:
   279    test:
   280      context: ghi
   281  `
   282  	_ = os.WriteFile(filepath.Join(name, subdir, ".buildtools.yaml"), []byte(yaml2), 0777)
   283  
   284  	logMock := mocks.New()
   285  	log.SetHandler(logMock)
   286  	log.SetLevel(log.DebugLevel)
   287  	cfg, err := Load(filepath.Join(name, subdir))
   288  	assert.NoError(t, err)
   289  	assert.NotNil(t, cfg)
   290  	assert.NotNil(t, cfg.CI)
   291  	assert.Equal(t, ci.No{}.Name(), cfg.CurrentCI().Name())
   292  	assert.NotNil(t, cfg.Registry)
   293  	currentRegistry := cfg.CurrentRegistry()
   294  	assert.NotNil(t, currentRegistry)
   295  	assert.Equal(t, 2, len(cfg.Targets))
   296  	assert.Equal(t, "ghi", cfg.Targets["test"].Context)
   297  	assert.Equal(t, "def", cfg.Targets["local"].Context)
   298  	logMock.Check(t, []string{fmt.Sprintf("debug: Parsing config from file: <green>'%s/sub/.buildtools.yaml'</green>\n", name),
   299  		fmt.Sprintf("debug: Merging with config from file: <green>'%s/.buildtools.yaml'</green>\n", name)})
   300  }
   301  
   302  func TestLoad_YAML_Multiple_Registry(t *testing.T) {
   303  	name, _ := os.MkdirTemp(os.TempDir(), "build-tools")
   304  	defer func() { _ = os.RemoveAll(name) }()
   305  	yaml := `
   306  registry:
   307    ecr:
   308      url: 1234.dkr.ecr.eu-west-1.amazonaws.com
   309      region: eu-west-1
   310    dockerhub:
   311      namespace: dockerhub
   312  targets:
   313    local:
   314      context: docker-desktop
   315    dev:
   316      context: docker-desktop
   317      namespace: dev
   318  `
   319  	_ = os.WriteFile(filepath.Join(name, ".buildtools.yaml"), []byte(yaml), 0777)
   320  
   321  	logMock := mocks.New()
   322  	log.SetHandler(logMock)
   323  	log.SetLevel(log.DebugLevel)
   324  	_, err := Load(name)
   325  	assert.EqualError(t, err, "registry already defined, please check configuration")
   326  	logMock.Check(t, []string{fmt.Sprintf("debug: Parsing config from file: <green>'%s/.buildtools.yaml'</green>\n", name)})
   327  }