github.com/helmwave/helmwave@v0.36.4-0.20240509190856-b35563eba4c6/pkg/action/build_internal_test.go (about)

     1  package action
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/databus23/helm-diff/v3/diff"
    11  	"github.com/helmwave/helmwave/pkg/cache"
    12  	"github.com/helmwave/helmwave/pkg/helper"
    13  	"github.com/helmwave/helmwave/pkg/hooks"
    14  	"github.com/helmwave/helmwave/pkg/plan"
    15  	"github.com/helmwave/helmwave/pkg/release"
    16  	"github.com/helmwave/helmwave/pkg/release/uniqname"
    17  	"github.com/helmwave/helmwave/pkg/repo"
    18  	"github.com/helmwave/helmwave/pkg/template"
    19  	"github.com/helmwave/helmwave/tests"
    20  	log "github.com/sirupsen/logrus"
    21  	logTest "github.com/sirupsen/logrus/hooks/test"
    22  	"github.com/stretchr/testify/suite"
    23  	"github.com/urfave/cli/v2"
    24  )
    25  
    26  type BuildTestSuite struct {
    27  	suite.Suite
    28  
    29  	ctx context.Context
    30  }
    31  
    32  func TestBuildTestSuite(t *testing.T) {
    33  	t.Parallel()
    34  	suite.Run(t, new(BuildTestSuite))
    35  }
    36  
    37  func (ts *BuildTestSuite) SetupTest() {
    38  	ts.ctx = tests.GetContext(ts.T())
    39  }
    40  
    41  func (ts *BuildTestSuite) TestCmd() {
    42  	s := &Build{}
    43  	cmd := s.Cmd()
    44  
    45  	ts.Require().NotNil(cmd)
    46  	ts.Require().NotEmpty(cmd.Name)
    47  }
    48  
    49  func (ts *BuildTestSuite) TestYmlError() {
    50  	tmpDir := ts.T().TempDir()
    51  	y := &Yml{
    52  		file:      filepath.Join(tests.Root, "helmwave.yml"),
    53  		templater: template.TemplaterSprig,
    54  	}
    55  
    56  	s := &Build{
    57  		plandir: tmpDir,
    58  		yml:     y,
    59  		tags:    cli.StringSlice{},
    60  		options: plan.BuildOptions{
    61  			MatchAll: true,
    62  		},
    63  	}
    64  
    65  	ts.Require().Error(s.Run(ts.ctx))
    66  }
    67  
    68  func (ts *BuildTestSuite) TestManifest() {
    69  	tmpDir := ts.T().TempDir()
    70  	y := &Yml{
    71  		tpl:       filepath.Join(tests.Root, "01_helmwave.yml.tpl"),
    72  		file:      filepath.Join(tests.Root, "02_helmwave.yml"),
    73  		templater: template.TemplaterSprig,
    74  	}
    75  
    76  	s := &Build{
    77  		plandir: tmpDir,
    78  		yml:     y,
    79  		tags:    cli.StringSlice{},
    80  		options: plan.BuildOptions{
    81  			MatchAll: true,
    82  		},
    83  	}
    84  
    85  	ts.Require().NoError(s.Run(ts.ctx))
    86  	ts.Require().DirExists(filepath.Join(s.plandir, plan.Manifest))
    87  }
    88  
    89  // func (ts *BuildTestSuite) TestRepositories404() {
    90  //	s := &Build{
    91  //		plandir:  tmpDir,
    92  //		ymlFile:      filepath.Join(tests.Root, "04_helmwave.yml"),
    93  //		tags:     cli.StringSlice{},
    94  //		options: plan.BuildOptions{
    95  //				MatchAll: true,
    96  //			},
    97  //	}
    98  //
    99  //	err := s.Run()
   100  //	if !errors.Is(err, repo.ErrNotFound) && err != nil {
   101  //		t.Error("'bitnami' must be not found")
   102  //	}
   103  // }
   104  
   105  func (ts *BuildTestSuite) TestNonUniqueReleases() {
   106  	tmpDir := ts.T().TempDir()
   107  	y := &Yml{
   108  		tpl:       filepath.Join(tests.Root, "14_helmwave.yml"),
   109  		file:      filepath.Join(tmpDir, "14_helmwave.yml"),
   110  		templater: template.TemplaterSprig,
   111  	}
   112  
   113  	sfail := &Build{
   114  		plandir: tmpDir,
   115  		yml:     y,
   116  		tags:    cli.StringSlice{},
   117  		options: plan.BuildOptions{
   118  			MatchAll: true,
   119  		},
   120  		autoYml: true,
   121  	}
   122  
   123  	sfailByTag := &Build{
   124  		plandir: tmpDir,
   125  		yml:     y,
   126  		tags:    cli.StringSlice{},
   127  		options: plan.BuildOptions{
   128  			MatchAll: true,
   129  		},
   130  		autoYml: true,
   131  	}
   132  	err := sfailByTag.tags.Set("nginx")
   133  	ts.Require().NoError(err)
   134  
   135  	sa := &Build{
   136  		plandir: tmpDir,
   137  		yml:     y,
   138  		tags:    cli.StringSlice{},
   139  		options: plan.BuildOptions{
   140  			MatchAll: true,
   141  		},
   142  		autoYml: true,
   143  	}
   144  	err = sa.tags.Set("nginx-a")
   145  	ts.Require().NoError(err)
   146  
   147  	sb := &Build{
   148  		plandir: tmpDir,
   149  		yml:     y,
   150  		tags:    cli.StringSlice{},
   151  		options: plan.BuildOptions{
   152  			MatchAll: true,
   153  		},
   154  		autoYml: true,
   155  	}
   156  	err = sb.tags.Set("nginx-b")
   157  	ts.Require().NoError(err)
   158  
   159  	var e *release.DuplicateError
   160  	ts.Require().ErrorAs(sfail.Run(ts.ctx), &e)
   161  	ts.Equal(uniqname.UniqName("nginx@test"), e.Uniq)
   162  
   163  	ts.Require().ErrorAs(sfailByTag.Run(ts.ctx), &e)
   164  	ts.Equal(uniqname.UniqName("nginx@test"), e.Uniq)
   165  
   166  	ts.Require().NoError(sa.Run(ts.ctx))
   167  	ts.Require().NoError(sb.Run(ts.ctx))
   168  }
   169  
   170  func (ts *BuildTestSuite) TestRepositories() {
   171  	tmpDir := ts.T().TempDir()
   172  	y := &Yml{
   173  		tpl:       filepath.Join(tests.Root, "01_helmwave.yml.tpl"),
   174  		file:      filepath.Join(tests.Root, "02_helmwave.yml"),
   175  		templater: template.TemplaterSprig,
   176  	}
   177  
   178  	s := &Build{
   179  		plandir: tmpDir,
   180  		yml:     y,
   181  		tags:    cli.StringSlice{},
   182  		options: plan.BuildOptions{
   183  			MatchAll: true,
   184  		},
   185  	}
   186  
   187  	ts.Require().NoError(s.Run(ts.ctx))
   188  
   189  	const rep = "bitnami"
   190  	b, _ := plan.NewBody(ts.ctx, filepath.Join(s.plandir, plan.File), true)
   191  
   192  	if _, found := repo.IndexOfName(b.Repositories, rep); !found {
   193  		ts.Failf("%q not found", rep)
   194  	}
   195  }
   196  
   197  func (ts *BuildTestSuite) TestReleasesMatchGroup() {
   198  	tmpDir := ts.T().TempDir()
   199  	y := &Yml{
   200  		tpl:       filepath.Join(tests.Root, "01_helmwave.yml.tpl"),
   201  		file:      filepath.Join(tests.Root, "03_helmwave.yml"),
   202  		templater: template.TemplaterSprig,
   203  	}
   204  
   205  	cases := []struct {
   206  		tags  *cli.StringSlice
   207  		names []string
   208  	}{
   209  		{
   210  			tags:  cli.NewStringSlice("b"),
   211  			names: []string{"redis-b", "memcached-b"},
   212  		},
   213  		{
   214  			tags:  cli.NewStringSlice("b", "redis"),
   215  			names: []string{"redis-b"},
   216  		},
   217  	}
   218  
   219  	for i := range cases {
   220  		s := &Build{
   221  			plandir: tmpDir,
   222  			yml:     y,
   223  			tags:    *cases[i].tags,
   224  			options: plan.BuildOptions{
   225  				MatchAll: true,
   226  			},
   227  		}
   228  
   229  		ts.Require().NoError(s.Run(ts.ctx))
   230  
   231  		b, _ := plan.NewBody(ts.ctx, filepath.Join(s.plandir, plan.File), true)
   232  
   233  		names := helper.SlicesMap(b.Releases, func(rel release.Config) string {
   234  			return rel.Name()
   235  		})
   236  
   237  		ts.ElementsMatch(cases[i].names, names)
   238  	}
   239  }
   240  
   241  func (ts *BuildTestSuite) TestDiffLocal() {
   242  	tmpDir := ts.T().TempDir()
   243  	y := &Yml{
   244  		tpl:       filepath.Join(tests.Root, "07_helmwave.yml"),
   245  		file:      filepath.Join(tests.Root, "07_helmwave.yml"),
   246  		templater: template.TemplaterSprig,
   247  	}
   248  
   249  	s := &Build{
   250  		plandir: tmpDir,
   251  		tags:    cli.StringSlice{},
   252  		options: plan.BuildOptions{
   253  			MatchAll: true,
   254  		},
   255  		autoYml:  true,
   256  		yml:      y,
   257  		diff:     &Diff{Options: &diff.Options{}},
   258  		diffMode: DiffModeLocal,
   259  	}
   260  
   261  	ts.Require().NoError(s.Run(ts.ctx), "build should not fail without diffing")
   262  	ts.Require().NoError(s.Run(ts.ctx), "build should not fail with diffing with previous plan")
   263  }
   264  
   265  func (ts *BuildTestSuite) TestValuesDependency() {
   266  	tmpDir := ts.T().TempDir()
   267  	y := &Yml{
   268  		tpl:       filepath.Join(tests.Root, "19_helmwave.yml"),
   269  		file:      filepath.Join(tests.Root, "19_helmwave.yml"),
   270  		templater: template.TemplaterSprig,
   271  	}
   272  
   273  	s := &Build{
   274  		plandir: tmpDir,
   275  		tags:    cli.StringSlice{},
   276  		options: plan.BuildOptions{
   277  			MatchAll: true,
   278  		},
   279  		autoYml: true,
   280  		yml:     y,
   281  	}
   282  
   283  	ts.Require().NoError(s.Run(ts.ctx), "build should not fail")
   284  }
   285  
   286  type NonParallelBuildTestSuite struct {
   287  	suite.Suite
   288  
   289  	defaultHooks log.LevelHooks
   290  	logHook      *logTest.Hook
   291  
   292  	ctx context.Context
   293  }
   294  
   295  //nolint:paralleltest // can't parallel because of setenv and uses helm repository.yaml flock
   296  func TestNonParallelNonParallelBuildTestSuite(t *testing.T) {
   297  	// t.Parallel()
   298  	suite.Run(t, new(NonParallelBuildTestSuite))
   299  }
   300  
   301  func (ts *NonParallelBuildTestSuite) SetupTest() {
   302  	ts.ctx = tests.GetContext(ts.T())
   303  }
   304  
   305  func (ts *NonParallelBuildTestSuite) SetupSuite() {
   306  	ts.defaultHooks = log.StandardLogger().Hooks
   307  	ts.logHook = logTest.NewLocal(log.StandardLogger())
   308  }
   309  
   310  func (ts *NonParallelBuildTestSuite) TearDownTestSuite() {
   311  	ts.logHook.Reset()
   312  }
   313  
   314  func (ts *NonParallelBuildTestSuite) TearDownSuite() {
   315  	log.StandardLogger().ReplaceHooks(ts.defaultHooks)
   316  }
   317  
   318  func (ts *NonParallelBuildTestSuite) getLoggerMessages() []string {
   319  	return helper.SlicesMap(ts.logHook.AllEntries(), func(entry *log.Entry) string {
   320  		return entry.Message
   321  	})
   322  }
   323  
   324  func (ts *NonParallelBuildTestSuite) TestAutoYml() {
   325  	tmpDir := ts.T().TempDir()
   326  	y := &Yml{
   327  		tpl:       filepath.Join(tests.Root, "01_helmwave.yml.tpl"),
   328  		file:      filepath.Join(tmpDir, "01_auto_yaml_helmwave.yml"),
   329  		templater: template.TemplaterSprig,
   330  	}
   331  
   332  	s := &Build{
   333  		plandir: tmpDir,
   334  		tags:    cli.StringSlice{},
   335  		options: plan.BuildOptions{
   336  			MatchAll: true,
   337  		},
   338  		autoYml: true,
   339  		yml:     y,
   340  	}
   341  
   342  	value := strings.ToLower(strings.ReplaceAll(ts.T().Name(), "/", ""))
   343  	ts.T().Setenv("NAMESPACE", value)
   344  
   345  	ts.Require().NoError(s.Run(ts.ctx))
   346  	ts.Require().DirExists(filepath.Join(s.plandir, plan.Manifest))
   347  }
   348  
   349  func (ts *NonParallelBuildTestSuite) TestGomplate() {
   350  	tmpDir := ts.T().TempDir()
   351  	y := &Yml{
   352  		tpl:       filepath.Join(tests.Root, "08_helmwave.yml"),
   353  		file:      filepath.Join(tmpDir, "08_helmwave.yml"),
   354  		templater: template.TemplaterGomplate,
   355  	}
   356  
   357  	s := &Build{
   358  		plandir: tmpDir,
   359  		tags:    cli.StringSlice{},
   360  		options: plan.BuildOptions{
   361  			MatchAll: true,
   362  		},
   363  		autoYml: true,
   364  		yml:     y,
   365  	}
   366  
   367  	ts.Require().NoError(s.Run(ts.ctx))
   368  	ts.Require().DirExists(filepath.Join(s.plandir, plan.Manifest))
   369  }
   370  
   371  func (ts *NonParallelBuildTestSuite) TestLifecycle() {
   372  	tmpDir := ts.T().TempDir()
   373  	y := &Yml{
   374  		tpl:       filepath.Join(tests.Root, "13_helmwave.yml"),
   375  		file:      filepath.Join(tmpDir, "13_helmwave.yml"),
   376  		templater: template.TemplaterSprig,
   377  	}
   378  
   379  	s := &Build{
   380  		plandir: tmpDir,
   381  		tags:    cli.StringSlice{},
   382  		options: plan.BuildOptions{
   383  			MatchAll: true,
   384  		},
   385  		autoYml: true,
   386  		yml:     y,
   387  	}
   388  
   389  	ts.Require().NoError(s.Run(ts.ctx))
   390  	ts.Require().DirExists(filepath.Join(s.plandir, plan.Manifest))
   391  
   392  	logMessages := ts.getLoggerMessages()
   393  	ts.Require().Contains(logMessages, "running pre_build script for nginx")
   394  	ts.Require().Contains(logMessages, "run global pre_build script")
   395  	ts.Require().Contains(logMessages, "running post_build script for nginx")
   396  	ts.Require().Contains(logMessages, "run global post_build script")
   397  }
   398  
   399  func (ts *NonParallelBuildTestSuite) TestLifecyclePost() {
   400  	tmpDir := ts.T().TempDir()
   401  	y := &Yml{
   402  		tpl:       filepath.Join(tests.Root, "17_helmwave.yml"),
   403  		file:      filepath.Join(tmpDir, "17_helmwave.yml"),
   404  		templater: template.TemplaterSprig,
   405  	}
   406  
   407  	s := &Build{
   408  		plandir: tmpDir,
   409  		tags:    cli.StringSlice{},
   410  		options: plan.BuildOptions{
   411  			MatchAll: true,
   412  		},
   413  		autoYml: true,
   414  		yml:     y,
   415  	}
   416  
   417  	err := s.Run(ts.ctx)
   418  
   419  	var e *hooks.CommandRunError
   420  	ts.Require().ErrorAs(err, &e)
   421  }
   422  
   423  func (ts *NonParallelBuildTestSuite) TestRemoteSource() {
   424  	tmpDir := ts.T().TempDir()
   425  	d, err := os.Getwd()
   426  	ts.Require().NoError(err)
   427  
   428  	ts.Require().NoError(os.Chdir(tmpDir))
   429  	ts.T().Cleanup(func() {
   430  		ts.Require().NoError(os.Chdir(d))
   431  	})
   432  
   433  	y := &Yml{
   434  		tpl:       filepath.Join("tests", "02_helmwave.yml"),
   435  		file:      filepath.Join("tests", "02_helmwave.yml"),
   436  		templater: template.TemplaterSprig,
   437  	}
   438  
   439  	s := &Build{
   440  		plandir: plan.Dir,
   441  		tags:    cli.StringSlice{},
   442  		options: plan.BuildOptions{
   443  			MatchAll: true,
   444  		},
   445  		remoteSource: "github.com/helmwave/helmwave",
   446  		yml:          y,
   447  	}
   448  
   449  	cache.DefaultConfig.Home = ts.T().TempDir()
   450  
   451  	err = s.Run(ts.ctx)
   452  	ts.Require().NoError(err)
   453  
   454  	ts.DirExists(filepath.Join(tmpDir, s.plandir))
   455  	ts.FileExists(filepath.Join(tmpDir, s.plandir, plan.File))
   456  }