github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/initializer/analyze/analyze_test.go (about)

     1  /*
     2  Copyright 2020 The Skaffold Authors
     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 analyze
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/jib"
    26  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
    27  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
    28  	initconfig "github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/config"
    29  	"github.com/GoogleContainerTools/skaffold/testutil"
    30  )
    31  
    32  type builder struct {
    33  	name string
    34  	path string
    35  }
    36  
    37  func TestAnalyze(t *testing.T) {
    38  	emptyFile := ""
    39  	largeFile := ""
    40  	for i := 1; i < 1000; i++ {
    41  		largeFile = fmt.Sprintf("%s0", largeFile)
    42  	}
    43  	validK8sManifest := "apiVersion: v1\nkind: Service\nmetadata:\n  name: test\n"
    44  
    45  	tests := []struct {
    46  		description       string
    47  		filesWithContents map[string]string
    48  		expectedConfigs   []string
    49  		expectedBuilders  []builder
    50  		config            initconfig.Config
    51  		shouldErr         bool
    52  	}{
    53  		{
    54  			description: "should return correct k8 configs and build files (backwards compatibility)",
    55  			filesWithContents: map[string]string{
    56  				"config/test.yaml":       validK8sManifest,
    57  				"config/invalid.yaml":    emptyFile,
    58  				"k8pod.yml":              validK8sManifest,
    59  				"README":                 emptyFile,
    60  				"deploy/Dockerfile":      emptyFile,
    61  				"deploy/Dockerfile.dev":  emptyFile,
    62  				"deploy/dev.Dockerfile":  emptyFile,
    63  				"deploy/test.dockerfile": emptyFile,
    64  				"gradle/build.gradle":    emptyFile,
    65  				"maven/pom.xml":          emptyFile,
    66  				"Dockerfile":             emptyFile,
    67  			},
    68  			config: initconfig.Config{
    69  				Force:                false,
    70  				EnableBuildpacksInit: false,
    71  				EnableJibInit:        false,
    72  			},
    73  			expectedConfigs: []string{
    74  				"k8pod.yml",
    75  				"config/test.yaml",
    76  			},
    77  			expectedBuilders: []builder{
    78  				{name: "Docker", path: "Dockerfile"},
    79  				{name: "Docker", path: "deploy/Dockerfile"},
    80  				{name: "Docker", path: "deploy/Dockerfile.dev"},
    81  				{name: "Docker", path: "deploy/dev.Dockerfile"},
    82  				{name: "Docker", path: "deploy/test.dockerfile"},
    83  			},
    84  			shouldErr: false,
    85  		},
    86  		{
    87  			description: "--skip-build should return no builders in analysis",
    88  			filesWithContents: map[string]string{
    89  				"config/test.yaml":       validK8sManifest,
    90  				"config/invalid.yaml":    emptyFile,
    91  				"k8pod.yml":              validK8sManifest,
    92  				"README":                 emptyFile,
    93  				"deploy/Dockerfile":      emptyFile,
    94  				"deploy/Dockerfile.dev":  emptyFile,
    95  				"deploy/dev.Dockerfile":  emptyFile,
    96  				"deploy/test.dockerfile": emptyFile,
    97  				"gradle/build.gradle":    emptyFile,
    98  				"maven/pom.xml":          emptyFile,
    99  				"Dockerfile":             emptyFile,
   100  			},
   101  			config: initconfig.Config{
   102  				Force:                false,
   103  				EnableBuildpacksInit: false,
   104  				EnableJibInit:        false,
   105  				SkipBuild:            true,
   106  			},
   107  			expectedConfigs: []string{
   108  				"k8pod.yml",
   109  				"config/test.yaml",
   110  			},
   111  			expectedBuilders: nil,
   112  			shouldErr:        false,
   113  		},
   114  		{
   115  			description: "should return correct k8 configs and build files",
   116  			filesWithContents: map[string]string{
   117  				"config/test.yaml":    validK8sManifest,
   118  				"config/invalid.yaml": emptyFile,
   119  				"k8pod.yml":           validK8sManifest,
   120  				"README":              emptyFile,
   121  				"deploy/Dockerfile":   emptyFile,
   122  				"gradle/build.gradle": emptyFile,
   123  				"maven/pom.xml":       emptyFile,
   124  				"Dockerfile":          emptyFile,
   125  				"node/package.json":   emptyFile,
   126  			},
   127  			config: initconfig.Config{
   128  				Force:                false,
   129  				EnableBuildpacksInit: true,
   130  				EnableJibInit:        true,
   131  				EnableJibGradleInit:  true,
   132  			},
   133  			expectedConfigs: []string{
   134  				"k8pod.yml",
   135  				"config/test.yaml",
   136  			},
   137  			expectedBuilders: []builder{
   138  				{name: "Docker", path: "Dockerfile"},
   139  				{name: "Docker", path: "deploy/Dockerfile"},
   140  				{name: "Jib Gradle Plugin", path: "gradle/build.gradle"},
   141  				{name: "Buildpacks", path: "gradle/build.gradle"},
   142  				{name: "Jib Maven Plugin", path: "maven/pom.xml"},
   143  				{name: "Buildpacks", path: "maven/pom.xml"},
   144  				{name: "Buildpacks", path: "node/package.json"},
   145  			},
   146  			shouldErr: false,
   147  		},
   148  		{
   149  			description: "skip validating nested jib configs",
   150  			filesWithContents: map[string]string{
   151  				"config/test.yaml":               validK8sManifest,
   152  				"k8pod.yml":                      validK8sManifest,
   153  				"gradle/build.gradle":            emptyFile,
   154  				"gradle/subproject/build.gradle": emptyFile,
   155  				"gradle/subproject/Dockerfile":   emptyFile,
   156  				"maven/asubproject/pom.xml":      emptyFile,
   157  				"maven/asubproject/Dockerfile":   emptyFile,
   158  				"maven/pom.xml":                  emptyFile,
   159  			},
   160  			config: initconfig.Config{
   161  				Force:                false,
   162  				EnableBuildpacksInit: false,
   163  				EnableJibInit:        true,
   164  				EnableJibGradleInit:  true,
   165  			},
   166  			expectedConfigs: []string{
   167  				"k8pod.yml",
   168  				"config/test.yaml",
   169  			},
   170  			expectedBuilders: []builder{
   171  				{name: "Jib Gradle Plugin", path: "gradle/build.gradle"},
   172  				{name: "Docker", path: "gradle/subproject/Dockerfile"},
   173  				{name: "Jib Maven Plugin", path: "maven/pom.xml"},
   174  				{name: "Docker", path: "maven/asubproject/Dockerfile"},
   175  			},
   176  			shouldErr: false,
   177  		},
   178  		{
   179  			description: "multiple builders in same directory",
   180  			filesWithContents: map[string]string{
   181  				"build.gradle":                 emptyFile,
   182  				"ignored-builder/build.gradle": emptyFile,
   183  				"not-ignored-config/test.yaml": validK8sManifest,
   184  				"Dockerfile":                   emptyFile,
   185  				"k8pod.yml":                    validK8sManifest,
   186  				"pom.xml":                      emptyFile,
   187  			},
   188  			config: initconfig.Config{
   189  				Force:                false,
   190  				EnableBuildpacksInit: false,
   191  				EnableJibInit:        true,
   192  				EnableJibGradleInit:  true,
   193  			},
   194  			expectedConfigs: []string{
   195  				"k8pod.yml",
   196  				"not-ignored-config/test.yaml",
   197  			},
   198  			expectedBuilders: []builder{
   199  				{name: "Docker", path: "Dockerfile"},
   200  				{name: "Jib Gradle Plugin", path: "build.gradle"},
   201  				{name: "Jib Maven Plugin", path: "pom.xml"},
   202  			},
   203  			shouldErr: false,
   204  		},
   205  		{
   206  			description: "should skip jib gradle",
   207  			filesWithContents: map[string]string{
   208  				"build.gradle": emptyFile,
   209  				"pom.xml":      emptyFile,
   210  			},
   211  			config: initconfig.Config{
   212  				Force:                false,
   213  				EnableBuildpacksInit: false,
   214  				EnableJibInit:        true,
   215  				EnableJibGradleInit:  false,
   216  			},
   217  			expectedConfigs: nil,
   218  			expectedBuilders: []builder{
   219  				{name: "Jib Maven Plugin", path: "pom.xml"},
   220  			},
   221  			shouldErr: false,
   222  		},
   223  		{
   224  			description: "should skip hidden dir",
   225  			filesWithContents: map[string]string{
   226  				".hidden/test.yaml":  validK8sManifest,
   227  				"k8pod.yml":          validK8sManifest,
   228  				"README":             emptyFile,
   229  				".hidden/Dockerfile": emptyFile,
   230  				"Dockerfile":         emptyFile,
   231  			},
   232  			config: initconfig.Config{
   233  				Force:                false,
   234  				EnableBuildpacksInit: false,
   235  				EnableJibInit:        true,
   236  			},
   237  			expectedConfigs: []string{
   238  				"k8pod.yml",
   239  			},
   240  			expectedBuilders: []builder{
   241  				{name: "Docker", path: "Dockerfile"},
   242  			},
   243  			shouldErr: false,
   244  		},
   245  		{
   246  			description: "should skip vendor folder",
   247  			filesWithContents: map[string]string{
   248  				"Dockerfile":            emptyFile,
   249  				"vendor/Dockerfile":     emptyFile,
   250  				"vendor/pom.xml":        emptyFile,
   251  				"vendor/package.json":   emptyFile,
   252  				"sub/vendor/Dockerfile": emptyFile,
   253  			},
   254  			config: initconfig.Config{
   255  				Force:                false,
   256  				EnableBuildpacksInit: true,
   257  				EnableJibInit:        true,
   258  			},
   259  			expectedBuilders: []builder{
   260  				{name: "Docker", path: "Dockerfile"},
   261  			},
   262  			shouldErr: false,
   263  		},
   264  		{
   265  			description: "should skip node_modules folder",
   266  			filesWithContents: map[string]string{
   267  				"Dockerfile":                  emptyFile,
   268  				"node_modules/Dockerfile":     emptyFile,
   269  				"node_modules/pom.xml":        emptyFile,
   270  				"node_modules/package.json":   emptyFile,
   271  				"sub/node_modules/Dockerfile": emptyFile,
   272  			},
   273  			config: initconfig.Config{
   274  				Force:                false,
   275  				EnableBuildpacksInit: true,
   276  				EnableJibInit:        true,
   277  			},
   278  			expectedBuilders: []builder{
   279  				{name: "Docker", path: "Dockerfile"},
   280  			},
   281  			shouldErr: false,
   282  		},
   283  		{
   284  			description: "should skip large files",
   285  			filesWithContents: map[string]string{
   286  				"k8pod.yml":               validK8sManifest,
   287  				"README":                  emptyFile,
   288  				"Dockerfile":              emptyFile,
   289  				"largeFileDir/Dockerfile": largeFile,
   290  			},
   291  			config: initconfig.Config{
   292  				Force:                false,
   293  				EnableBuildpacksInit: false,
   294  				EnableJibInit:        true,
   295  				MaxFileSize:          100,
   296  			},
   297  			expectedConfigs: []string{
   298  				"k8pod.yml",
   299  			},
   300  			expectedBuilders: []builder{
   301  				{name: "Docker", path: "Dockerfile"},
   302  			},
   303  			shouldErr: false,
   304  		},
   305  		{
   306  			description: "should not error when skaffold.config present and force = true",
   307  			filesWithContents: map[string]string{
   308  				"skaffold.yaml": `apiVersion: skaffold/v1beta6
   309  		kind: Config
   310  		deploy:
   311  		  kustomize: {}`,
   312  				"config/test.yaml":  validK8sManifest,
   313  				"k8pod.yml":         validK8sManifest,
   314  				"README":            emptyFile,
   315  				"deploy/Dockerfile": emptyFile,
   316  				"Dockerfile":        emptyFile,
   317  			},
   318  			config: initconfig.Config{
   319  				Force:                true,
   320  				EnableBuildpacksInit: false,
   321  				EnableJibInit:        true,
   322  			},
   323  			expectedConfigs: []string{
   324  				"k8pod.yml",
   325  				"config/test.yaml",
   326  			},
   327  			expectedBuilders: []builder{
   328  				{name: "Docker", path: "Dockerfile"},
   329  				{name: "Docker", path: "deploy/Dockerfile"},
   330  			},
   331  			shouldErr: false,
   332  		},
   333  		{
   334  			description: "should error when skaffold.config present and force = false",
   335  			filesWithContents: map[string]string{
   336  				"config/test.yaml":  validK8sManifest,
   337  				"k8pod.yml":         validK8sManifest,
   338  				"README":            emptyFile,
   339  				"deploy/Dockerfile": emptyFile,
   340  				"Dockerfile":        emptyFile,
   341  				"skaffold.yaml": `apiVersion: skaffold/v1beta6
   342  kind: Config
   343  deploy:
   344    kustomize: {}`,
   345  			},
   346  			config: initconfig.Config{
   347  				Force:                false,
   348  				EnableBuildpacksInit: false,
   349  				EnableJibInit:        true,
   350  				Opts: config.SkaffoldOptions{
   351  					ConfigurationFile: "skaffold.yaml",
   352  				},
   353  			},
   354  			expectedConfigs:  nil,
   355  			expectedBuilders: nil,
   356  			shouldErr:        true,
   357  		},
   358  		{
   359  			description: "should error when skaffold.config present with jib config",
   360  			filesWithContents: map[string]string{
   361  				"config/test.yaml": validK8sManifest,
   362  				"k8pod.yml":        validK8sManifest,
   363  				"README":           emptyFile,
   364  				"pom.xml":          emptyFile,
   365  				"skaffold.yaml": `apiVersion: skaffold/v1beta6
   366  kind: Config
   367  deploy:
   368    kustomize: {}`,
   369  			},
   370  			config: initconfig.Config{
   371  				Force:                false,
   372  				EnableBuildpacksInit: false,
   373  				EnableJibInit:        true,
   374  				Opts: config.SkaffoldOptions{
   375  					ConfigurationFile: "skaffold.yaml",
   376  				},
   377  			},
   378  			expectedConfigs:  nil,
   379  			expectedBuilders: nil,
   380  			shouldErr:        true,
   381  		},
   382  	}
   383  	for _, test := range tests {
   384  		testutil.Run(t, test.description, func(t *testutil.T) {
   385  			t.NewTempDir().WriteFiles(test.filesWithContents).Chdir()
   386  
   387  			t.Override(&docker.Validate, fakeValidateDockerfile)
   388  			t.Override(&jib.Validate, fakeValidateJibConfig)
   389  
   390  			a := NewAnalyzer(test.config)
   391  			err := a.Analyze(".")
   392  
   393  			t.CheckError(test.shouldErr, err)
   394  			if test.shouldErr {
   395  				return
   396  			}
   397  
   398  			t.CheckDeepEqual(test.expectedConfigs, a.Manifests())
   399  
   400  			if len(test.expectedBuilders) != len(a.Builders()) {
   401  				t.Fatalf("expected %d builders, got %d: %v",
   402  					len(test.expectedBuilders),
   403  					len(a.Builders()), a.Builders())
   404  			}
   405  			for i := range a.Builders() {
   406  				t.CheckDeepEqual(test.expectedBuilders[i].name, a.Builders()[i].Name())
   407  				t.CheckDeepEqual(test.expectedBuilders[i].path, a.Builders()[i].Path())
   408  			}
   409  		})
   410  	}
   411  }
   412  
   413  func fakeValidateDockerfile(path string) bool {
   414  	return strings.Contains(strings.ToLower(path), "dockerfile")
   415  }
   416  
   417  func fakeValidateJibConfig(_ context.Context, path string, enableGradle bool) []jib.ArtifactConfig {
   418  	if strings.HasSuffix(path, "build.gradle") && enableGradle {
   419  		return []jib.ArtifactConfig{{BuilderName: jib.PluginName(jib.JibGradle), File: path}}
   420  	}
   421  	if strings.HasSuffix(path, "pom.xml") {
   422  		return []jib.ArtifactConfig{{BuilderName: jib.PluginName(jib.JibMaven), File: path}}
   423  	}
   424  	return nil
   425  }