...

Source file src/edge-infra.dev/pkg/f8n/warehouse/lift/config_test.go

Documentation: edge-infra.dev/pkg/f8n/warehouse/lift

     1  package lift
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"testing"
     7  
     8  	"github.com/bazelbuild/rules_go/go/tools/bazel"
     9  	"github.com/stretchr/testify/assert"
    10  	"gopkg.in/yaml.v3"
    11  
    12  	"edge-infra.dev/pkg/lib/cli/sh"
    13  )
    14  
    15  var (
    16  	dummyInfraCfg = CapabilityConfig{
    17  		"fake/infra-package",
    18  		ResourceMatcher{
    19  			APIGroups: []string{"fake.apigroup.u"},
    20  		},
    21  	}
    22  	dummyRuntimeCfg = CapabilityConfig{
    23  		"prometheus",
    24  		ResourceMatcher{
    25  			APIGroups: []string{"prometheus.real.apigroup.io"},
    26  		},
    27  	}
    28  	dummyRuntimeCfg2 = CapabilityConfig{
    29  		"linkerd",
    30  		ResourceMatcher{
    31  			APIGroups: []string{"linkerd.real.apigroup.io"},
    32  		},
    33  	}
    34  
    35  	infraOnlyCfg = Config{
    36  		Infrastructure: dummyInfraCfg,
    37  	}
    38  
    39  	dummyParameters1 = []Parameter{
    40  		{"special_thing_i_must_parameterize", 64, "simply got to have it"},
    41  		{"config_isnt_my_forte", 32, "at least im honest"},
    42  	}
    43  	dummyParameters2 = []Parameter{
    44  		{"foobie", 12, "foobie brothers"},
    45  		{"scooby", 48, "snacks"},
    46  	}
    47  )
    48  
    49  func TestConfig_New(t *testing.T) {
    50  	dir := bazel.TestTmpDir()
    51  	defer os.RemoveAll(dir)
    52  
    53  	cfg := &Config{Infrastructure: dummyInfraCfg}
    54  	cfgpath := filepath.Join(dir, "warehouse.yaml")
    55  	writeCfg(t, cfg, cfgpath)
    56  
    57  	t.Run("Environment variables", func(t *testing.T) {
    58  		whpath := "/test/path"
    59  		t.Setenv("WAREHOUSE_PATH", whpath)
    60  		cachepath := "test/cache"
    61  		t.Setenv("WAREHOUSE_CACHE", cachepath)
    62  		repo := "us-east1-docker.pkg.dev"
    63  		t.Setenv("WAREHOUSE_REPO", repo)
    64  
    65  		t.Setenv("WAREHOUSE_CONFIG", cfgpath)
    66  		actual, err := NewConfig()
    67  		assert.NoError(t, err)
    68  		assert.Equal(t, "/test/path", actual.WAREHOUSEPATH)
    69  		assert.Equal(t, "test/cache", actual.Cache)
    70  		assert.Equal(t, "us-east1-docker.pkg.dev", actual.Repo)
    71  
    72  		// Test that environment variables take precedence over config file values.
    73  		cfg := &Config{
    74  			WAREHOUSEPATH:  "/should/be/ignored",
    75  			Cache:          "should/be/ignored",
    76  			Repo:           "ignored.pkg.dev",
    77  			Infrastructure: dummyInfraCfg,
    78  		}
    79  		writeCfg(t, cfg, cfgpath)
    80  
    81  		actual, err = NewConfig()
    82  		assert.NoError(t, err)
    83  		assert.Equal(t, "/test/path", actual.WAREHOUSEPATH)
    84  		assert.Equal(t, "test/cache", actual.Cache)
    85  		assert.Equal(t, "us-east1-docker.pkg.dev", actual.Repo)
    86  	})
    87  
    88  	t.Run("Cache falls back to HOME", func(t *testing.T) {
    89  		writeCfg(t, &Config{
    90  			Infrastructure: dummyInfraCfg, WAREHOUSEPATH: "/empty",
    91  		}, cfgpath)
    92  		t.Setenv("WAREHOUSE_CONFIG", cfgpath)
    93  
    94  		t.Setenv("HOME", "fake/home/for/fake/user")
    95  
    96  		actual, err := NewConfig()
    97  		assert.NoError(t, err)
    98  		assert.Equal(t, "fake/home/for/fake/user/.cache/warehouse", actual.Cache)
    99  	})
   100  
   101  	t.Run("WAREHOUSE_PATH falls back to repo root", func(t *testing.T) {
   102  		repo := createTestGitRepo(t, dir)
   103  		assert.NoError(t, os.Chdir(repo))
   104  
   105  		writeCfg(t, &Config{Infrastructure: dummyInfraCfg, Cache: "empty"}, cfgpath)
   106  		t.Setenv("WAREHOUSE_CONFIG", cfgpath)
   107  
   108  		actual, err := NewConfig()
   109  		assert.NoError(t, err)
   110  		assert.Equal(t, repo, actual.WAREHOUSEPATH)
   111  	})
   112  
   113  	t.Run("Config file falls back to root of WAREHOUSE_PATH", func(t *testing.T) {
   114  		cfgpath := filepath.Join(dir, ConfigFile)
   115  		writeCfg(t, &Config{Cache: "empty", Infrastructure: dummyInfraCfg}, cfgpath)
   116  
   117  		t.Setenv("WAREHOUSE_PATH", dir)
   118  
   119  		_, err := NewConfig()
   120  		// If the config file isn't located, we will error due to missing
   121  		// infrastructure field
   122  		assert.NoError(t, err)
   123  	})
   124  
   125  	t.Run("Config file is loaded from inferred WAREHOUSE_PATH", func(t *testing.T) {
   126  		repo := createTestGitRepo(t, dir)
   127  		assert.NoError(t, os.Chdir(repo))
   128  
   129  		writeCfg(t, &Config{
   130  			WAREHOUSEPATH:  repo,
   131  			Infrastructure: dummyInfraCfg,
   132  			Cache:          "empty",
   133  		}, filepath.Join(repo, ConfigFile))
   134  
   135  		actual, err := NewConfig()
   136  		assert.NoError(t, err)
   137  		assert.Equal(t, "empty", actual.Cache)
   138  	})
   139  }
   140  
   141  func TestConfig_Validate(t *testing.T) {
   142  	tcs := map[string]struct {
   143  		cfg Config
   144  		err bool
   145  	}{
   146  		"minimal": {
   147  			cfg: Config{WAREHOUSEPATH: "/any", Infrastructure: dummyInfraCfg},
   148  			err: false,
   149  		},
   150  		"empty": {
   151  			cfg: Config{},
   152  			err: true,
   153  		},
   154  		"no path": {
   155  			cfg: Config{Infrastructure: dummyInfraCfg},
   156  			err: true,
   157  		},
   158  		"relative path": {
   159  			cfg: Config{WAREHOUSEPATH: "any", Infrastructure: dummyInfraCfg},
   160  			err: true,
   161  		},
   162  	}
   163  
   164  	for name, tc := range tcs {
   165  		t.Run(name, func(t *testing.T) {
   166  			actual := tc.cfg.Validate()
   167  			if tc.err && actual == nil {
   168  				t.Error("expected error")
   169  			}
   170  			if !tc.err && actual != nil {
   171  				t.Error("unexpected error", actual)
   172  			}
   173  		})
   174  	}
   175  }
   176  
   177  func TestConfig_WithRuntime(t *testing.T) {
   178  	tcs := map[string]struct {
   179  		src      Config
   180  		input    Runtime
   181  		expected Config
   182  		err      bool
   183  	}{
   184  		"empty input": {
   185  			infraOnlyCfg,
   186  			Runtime{},
   187  			infraOnlyCfg,
   188  			false,
   189  		},
   190  		"source is empty": {
   191  			Config{},
   192  			Runtime{Capabilities: []CapabilityConfig{dummyRuntimeCfg}},
   193  			Config{Runtime: Runtime{Capabilities: []CapabilityConfig{dummyRuntimeCfg}}},
   194  			false,
   195  		},
   196  		"source is not empty": {
   197  			Config{Runtime: Runtime{Capabilities: []CapabilityConfig{dummyRuntimeCfg2}}},
   198  			Runtime{Capabilities: []CapabilityConfig{dummyRuntimeCfg}},
   199  			Config{Runtime: Runtime{Capabilities: []CapabilityConfig{dummyRuntimeCfg2, dummyRuntimeCfg}}},
   200  			false,
   201  		},
   202  		"conflict": {
   203  			Config{Runtime: Runtime{Capabilities: []CapabilityConfig{dummyRuntimeCfg}}},
   204  			Runtime{Capabilities: []CapabilityConfig{dummyRuntimeCfg}},
   205  			Config{},
   206  			true,
   207  		},
   208  	}
   209  
   210  	for name, tc := range tcs {
   211  		t.Run(name, func(t *testing.T) {
   212  			actual, err := tc.src.WithRuntime(tc.input)
   213  			if err != nil && tc.err == false {
   214  				t.Error("unexpected error", err)
   215  			}
   216  			if err == nil && tc.err == true {
   217  				t.Error("expected error but got nil")
   218  			}
   219  			assert.Equal(t, tc.expected, actual)
   220  		})
   221  	}
   222  }
   223  
   224  func TestConfig_WithParameters(t *testing.T) {
   225  	tcs := map[string]struct {
   226  		src      Config
   227  		input    []Parameter
   228  		expected Config
   229  		err      bool
   230  	}{
   231  		"empty input": {
   232  			infraOnlyCfg,
   233  			nil,
   234  			infraOnlyCfg,
   235  			false,
   236  		},
   237  		"source is empty": {
   238  			Config{},
   239  			dummyParameters1,
   240  			Config{Parameters: dummyParameters1},
   241  			false,
   242  		},
   243  		"source is not empty": {
   244  			Config{Parameters: dummyParameters2},
   245  			dummyParameters1,
   246  			Config{Parameters: append(dummyParameters2, dummyParameters1...)},
   247  			false,
   248  		},
   249  		"conflict": {
   250  			Config{Parameters: dummyParameters1},
   251  			dummyParameters1,
   252  			Config{},
   253  			true,
   254  		},
   255  	}
   256  
   257  	for name, tc := range tcs {
   258  		t.Run(name, func(t *testing.T) {
   259  			actual, err := tc.src.WithParameters(tc.input)
   260  			if err != nil && tc.err == false {
   261  				t.Error("unexpected error", err)
   262  			}
   263  			if err == nil && tc.err == true {
   264  				t.Error("expected error but got nil")
   265  			}
   266  			assert.Equal(t, tc.expected, actual)
   267  		})
   268  	}
   269  }
   270  
   271  func writeCfg(t *testing.T, cfg *Config, path string) {
   272  	t.Helper()
   273  
   274  	data, err := yaml.Marshal(cfg)
   275  	assert.NoError(t, err)
   276  
   277  	assert.NoError(t, os.WriteFile(path, data, 0644))
   278  }
   279  
   280  func createTestGitRepo(t *testing.T, dir string) string {
   281  	t.Helper()
   282  
   283  	repo, err := os.MkdirTemp(dir, "git_test-*")
   284  	assert.NoError(t, err)
   285  	t.Log("test repo dir", repo)
   286  
   287  	shell := sh.NewInDir(repo)
   288  	for _, c := range []string{
   289  		"git init -q",
   290  		"git config user.name \"testbot\"",
   291  		"git config user.email \"testmail@testworld.com\"",
   292  		"git checkout -b test",
   293  	} {
   294  		assert.NoError(t, shell.RunE(c))
   295  	}
   296  
   297  	return repo
   298  }
   299  

View as plain text