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 }