github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/build/builder_mux_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 build
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"io"
    23  	"testing"
    24  
    25  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/platform"
    26  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
    27  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
    28  	"github.com/GoogleContainerTools/skaffold/testutil"
    29  )
    30  
    31  func TestNewBuilderMux(t *testing.T) {
    32  	tests := []struct {
    33  		description         string
    34  		pipelines           []latest.Pipeline
    35  		pipeBuilder         func(latest.Pipeline) (PipelineBuilder, error)
    36  		shouldErr           bool
    37  		expectedBuilders    []string
    38  		expectedConcurrency int
    39  	}{
    40  		{
    41  			description: "only local builder",
    42  			pipelines: []latest.Pipeline{
    43  				{Build: latest.BuildConfig{BuildType: latest.BuildType{LocalBuild: &latest.LocalBuild{Concurrency: util.IntPtr(1)}}}},
    44  			},
    45  			pipeBuilder:         newMockPipelineBuilder,
    46  			expectedBuilders:    []string{"local"},
    47  			expectedConcurrency: 1,
    48  		},
    49  		{
    50  			description: "only cluster builder",
    51  			pipelines: []latest.Pipeline{
    52  				{Build: latest.BuildConfig{BuildType: latest.BuildType{Cluster: &latest.ClusterDetails{}}}},
    53  			},
    54  			pipeBuilder:      newMockPipelineBuilder,
    55  			expectedBuilders: []string{"cluster"},
    56  		},
    57  		{
    58  			description: "only gcb builder",
    59  			pipelines: []latest.Pipeline{
    60  				{Build: latest.BuildConfig{BuildType: latest.BuildType{GoogleCloudBuild: &latest.GoogleCloudBuild{}}}},
    61  			},
    62  			pipeBuilder:      newMockPipelineBuilder,
    63  			expectedBuilders: []string{"gcb"},
    64  		},
    65  		{
    66  			description: "min non-zero concurrency",
    67  			pipelines: []latest.Pipeline{
    68  				{Build: latest.BuildConfig{BuildType: latest.BuildType{LocalBuild: &latest.LocalBuild{Concurrency: util.IntPtr(0)}}}},
    69  				{Build: latest.BuildConfig{BuildType: latest.BuildType{LocalBuild: &latest.LocalBuild{Concurrency: util.IntPtr(3)}}}},
    70  				{Build: latest.BuildConfig{BuildType: latest.BuildType{Cluster: &latest.ClusterDetails{Concurrency: 2}}}},
    71  			},
    72  			pipeBuilder:         newMockPipelineBuilder,
    73  			expectedBuilders:    []string{"local", "local", "cluster"},
    74  			expectedConcurrency: 2,
    75  		},
    76  	}
    77  	for _, test := range tests {
    78  		testutil.Run(t, test.description, func(t *testutil.T) {
    79  			cfg := &mockConfig{pipelines: test.pipelines}
    80  
    81  			b, err := NewBuilderMux(cfg, nil, test.pipeBuilder)
    82  			t.CheckError(test.shouldErr, err)
    83  			if test.shouldErr {
    84  				return
    85  			}
    86  			t.CheckTrue(len(b.builders) == len(test.expectedBuilders))
    87  			for i := range b.builders {
    88  				t.CheckDeepEqual(test.expectedBuilders[i], b.builders[i].(*mockPipelineBuilder).builderType)
    89  			}
    90  			t.CheckDeepEqual(test.expectedConcurrency, b.concurrency)
    91  		})
    92  	}
    93  }
    94  
    95  func TestGetConcurrency(t *testing.T) {
    96  	tests := []struct {
    97  		description         string
    98  		pbs                 []PipelineBuilder
    99  		cliConcurrency      int
   100  		expectedConcurrency int
   101  	}{
   102  		{
   103  			description: "default concurrency - builder and cli concurrency unset.",
   104  			pbs: []PipelineBuilder{
   105  				&mockPipelineBuilder{concurrency: nil, builderType: "local"},
   106  				&mockPipelineBuilder{concurrency: nil, builderType: "gcb"},
   107  			},
   108  			cliConcurrency:      -1,
   109  			expectedConcurrency: 1,
   110  		},
   111  		{
   112  			description: "builder concurrency set to less than cli concurrency",
   113  			pbs: []PipelineBuilder{
   114  				&mockPipelineBuilder{concurrency: util.IntPtr(1), builderType: "local"},
   115  				&mockPipelineBuilder{concurrency: util.IntPtr(1), builderType: "local"},
   116  				&mockPipelineBuilder{concurrency: nil, builderType: "gcb"},
   117  			},
   118  			cliConcurrency:      2,
   119  			expectedConcurrency: 2,
   120  		},
   121  		{
   122  			description: "builder concurrency set",
   123  			pbs: []PipelineBuilder{
   124  				&mockPipelineBuilder{concurrency: util.IntPtr(2), builderType: "local"},
   125  				&mockPipelineBuilder{concurrency: util.IntPtr(2), builderType: "local"},
   126  				// As per docs https://github.com/GoogleContainerTools/skaffold/blob/dbd18994955f5805e80c6354ed0fd424ec4d987b/pkg/skaffold/schema/v2beta26/config.go#L287
   127  				// nil concurrency defaults to 1
   128  				&mockPipelineBuilder{concurrency: nil, builderType: "local"},
   129  			},
   130  			cliConcurrency:      -1,
   131  			expectedConcurrency: 1,
   132  		},
   133  		{
   134  			description: "builder concurrency set to 0 and cli concurrency set to 1",
   135  			pbs: []PipelineBuilder{
   136  				// build all in parallel
   137  				&mockPipelineBuilder{concurrency: util.IntPtr(0), builderType: "local"},
   138  				&mockPipelineBuilder{concurrency: util.IntPtr(0), builderType: "gcb"},
   139  			},
   140  			cliConcurrency:      1,
   141  			expectedConcurrency: 1,
   142  		},
   143  		{
   144  			description: "builder concurrency set to 0 and cli concurrency unset",
   145  			pbs: []PipelineBuilder{
   146  				// build all in parallel
   147  				&mockPipelineBuilder{concurrency: util.IntPtr(0), builderType: "local"},
   148  				&mockPipelineBuilder{concurrency: util.IntPtr(0), builderType: "gcb"},
   149  			},
   150  			cliConcurrency:      -1,
   151  			expectedConcurrency: 0,
   152  		},
   153  		{
   154  			description: "builder concurrency set to default 0 for gcb",
   155  			pbs: []PipelineBuilder{
   156  				// build all in parallel
   157  				&mockPipelineBuilder{concurrency: util.IntPtr(0), builderType: "gcb"},
   158  				&mockPipelineBuilder{concurrency: util.IntPtr(0), builderType: "gcb"},
   159  			},
   160  			cliConcurrency:      -1,
   161  			expectedConcurrency: 0,
   162  		},
   163  		{
   164  			description: "min non-zero concurrency",
   165  			pbs: []PipelineBuilder{
   166  				&mockPipelineBuilder{concurrency: util.IntPtr(0), builderType: "local"},
   167  				&mockPipelineBuilder{concurrency: util.IntPtr(3), builderType: "gcb"},
   168  				&mockPipelineBuilder{concurrency: util.IntPtr(2), builderType: "gcb"},
   169  			},
   170  			cliConcurrency:      -1,
   171  			expectedConcurrency: 2,
   172  		},
   173  	}
   174  	for _, test := range tests {
   175  		testutil.Run(t, test.description, func(t *testutil.T) {
   176  			actual := getConcurrency(test.pbs, test.cliConcurrency)
   177  			t.CheckDeepEqual(test.expectedConcurrency, actual)
   178  		})
   179  	}
   180  }
   181  
   182  type mockConfig struct {
   183  	pipelines []latest.Pipeline
   184  	optRepo   string
   185  }
   186  
   187  func (m *mockConfig) GetPipelines() []latest.Pipeline { return m.pipelines }
   188  func (m *mockConfig) GlobalConfig() string            { return "" }
   189  func (m *mockConfig) DefaultRepo() *string {
   190  	if m.optRepo != "" {
   191  		return &m.optRepo
   192  	}
   193  	return nil
   194  }
   195  func (m *mockConfig) MultiLevelRepo() *bool { return nil }
   196  func (m *mockConfig) BuildConcurrency() int { return -1 }
   197  
   198  type mockPipelineBuilder struct {
   199  	concurrency *int
   200  	builderType string
   201  }
   202  
   203  func (m *mockPipelineBuilder) PreBuild(ctx context.Context, out io.Writer) error { return nil }
   204  
   205  func (m *mockPipelineBuilder) Build(ctx context.Context, out io.Writer, artifact *latest.Artifact) ArtifactBuilder {
   206  	return nil
   207  }
   208  
   209  func (m *mockPipelineBuilder) PostBuild(ctx context.Context, out io.Writer) error { return nil }
   210  
   211  func (m *mockPipelineBuilder) Concurrency() *int { return m.concurrency }
   212  
   213  func (m *mockPipelineBuilder) Prune(context.Context, io.Writer) error { return nil }
   214  
   215  func (m *mockPipelineBuilder) PushImages() bool { return false }
   216  
   217  func (m *mockPipelineBuilder) SupportedPlatforms() platform.Matcher { return platform.All }
   218  
   219  func newMockPipelineBuilder(p latest.Pipeline) (PipelineBuilder, error) {
   220  	switch {
   221  	case p.Build.BuildType.LocalBuild != nil:
   222  		return &mockPipelineBuilder{builderType: "local", concurrency: p.Build.LocalBuild.Concurrency}, nil
   223  	case p.Build.BuildType.Cluster != nil:
   224  		return &mockPipelineBuilder{builderType: "cluster", concurrency: util.IntPtr(p.Build.Cluster.Concurrency)}, nil
   225  	case p.Build.BuildType.GoogleCloudBuild != nil:
   226  		return &mockPipelineBuilder{builderType: "gcb", concurrency: util.IntPtr(p.Build.GoogleCloudBuild.Concurrency)}, nil
   227  	default:
   228  		return nil, errors.New("invalid config")
   229  	}
   230  }