github.com/replicatedhq/ship@v0.55.0/pkg/lifecycle/render/googlegke/render_test.go (about)

     1  package googlegke
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"testing"
     9  
    10  	"github.com/go-kit/kit/log"
    11  	"github.com/golang/mock/gomock"
    12  	"github.com/pmezard/go-difflib/difflib"
    13  	"github.com/replicatedhq/libyaml"
    14  	"github.com/replicatedhq/ship/pkg/api"
    15  	"github.com/replicatedhq/ship/pkg/lifecycle/render/root"
    16  	"github.com/replicatedhq/ship/pkg/templates"
    17  	"github.com/replicatedhq/ship/pkg/test-mocks/inline"
    18  	"github.com/replicatedhq/ship/pkg/test-mocks/state"
    19  	"github.com/replicatedhq/ship/pkg/testing/logger"
    20  	"github.com/replicatedhq/ship/pkg/testing/matchers"
    21  	"github.com/spf13/afero"
    22  	"github.com/spf13/viper"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  func TestRenderer(t *testing.T) {
    27  	tests := []struct {
    28  		name       string
    29  		asset      api.GKEAsset
    30  		kubeconfig string
    31  	}{
    32  		{
    33  			name:       "empty",
    34  			asset:      api.GKEAsset{},
    35  			kubeconfig: "kubeconfig_",
    36  		},
    37  		{
    38  			name: "named",
    39  			asset: api.GKEAsset{
    40  				ClusterName: "aClusterName",
    41  			},
    42  			kubeconfig: "kubeconfig_aClusterName",
    43  		},
    44  		{
    45  			name: "named, custom path",
    46  			asset: api.GKEAsset{
    47  				ClusterName: "aClusterName",
    48  				AssetShared: api.AssetShared{
    49  					Dest: "gke.tf",
    50  				},
    51  			},
    52  			kubeconfig: "kubeconfig_aClusterName",
    53  		},
    54  		{
    55  			name: "named, in a directory",
    56  			asset: api.GKEAsset{
    57  				ClusterName: "aClusterName",
    58  				AssetShared: api.AssetShared{
    59  					Dest: "k8s/gke.tf",
    60  				},
    61  			},
    62  			kubeconfig: "k8s/kubeconfig_aClusterName",
    63  		},
    64  	}
    65  	for _, test := range tests {
    66  		t.Run(test.name, func(t *testing.T) {
    67  			req := require.New(t)
    68  			mc := gomock.NewController(t)
    69  			mockInline := inline.NewMockRenderer(mc)
    70  			testLogger := &logger.TestLogger{T: t}
    71  			v := viper.New()
    72  			bb := templates.NewBuilderBuilder(testLogger, v, &state.MockManager{})
    73  			renderer := &LocalRenderer{
    74  				Logger:         testLogger,
    75  				BuilderBuilder: bb,
    76  				Inline:         mockInline,
    77  			}
    78  
    79  			assetMatcher := &matchers.Is{
    80  				Describe: "inline asset",
    81  				Test: func(v interface{}) bool {
    82  					_, ok := v.(api.InlineAsset)
    83  					return ok
    84  				},
    85  			}
    86  
    87  			rootFs := root.Fs{
    88  				Afero:    afero.Afero{Fs: afero.NewMemMapFs()},
    89  				RootPath: "",
    90  			}
    91  			metadata := api.ReleaseMetadata{}
    92  			groups := []libyaml.ConfigGroup{}
    93  			templateContext := map[string]interface{}{}
    94  
    95  			mockInline.EXPECT().Execute(
    96  				rootFs,
    97  				assetMatcher,
    98  				metadata,
    99  				templateContext,
   100  				groups,
   101  			).Return(func(ctx context.Context) error { return nil })
   102  
   103  			err := renderer.Execute(
   104  				rootFs,
   105  				test.asset,
   106  				metadata,
   107  				templateContext,
   108  				groups,
   109  			)(context.Background())
   110  
   111  			req.NoError(err)
   112  
   113  			// test that the template function returns the correct kubeconfig path
   114  			builder := getBuilder()
   115  
   116  			gkeTemplateFunc := `{{repl GoogleGKE "%s" }}`
   117  			kubeconfig, err := builder.String(fmt.Sprintf(gkeTemplateFunc, test.asset.ClusterName))
   118  			req.NoError(err)
   119  
   120  			req.Equal(test.kubeconfig, kubeconfig, "Did not get expected kubeconfig path")
   121  
   122  			otherKubeconfig, err := builder.String(fmt.Sprintf(gkeTemplateFunc, "doesnotexist"))
   123  			req.NoError(err)
   124  			req.Empty(otherKubeconfig, "Expected path to nonexistent kubeconfig to be empty")
   125  		})
   126  	}
   127  }
   128  
   129  func getBuilder() templates.Builder {
   130  	builderBuilder := templates.NewBuilderBuilder(log.NewNopLogger(), viper.New(), &state.MockManager{})
   131  
   132  	builder := builderBuilder.NewBuilder(
   133  		&templates.ShipContext{},
   134  	)
   135  	return builder
   136  }
   137  
   138  func TestRenderTerraformContents(t *testing.T) {
   139  	tests := []struct {
   140  		name     string
   141  		asset    api.GKEAsset
   142  		expected string
   143  	}{
   144  		{
   145  			name: "simple",
   146  			asset: api.GKEAsset{
   147  				ClusterName: "simple-cluster",
   148  			},
   149  			expected: mustAsset("testassets/simple.tf"),
   150  		},
   151  		{
   152  			name: "complex",
   153  			asset: api.GKEAsset{
   154  				GCPProvider: api.GCPProvider{
   155  					Credentials: base64.StdEncoding.EncodeToString(
   156  						[]byte("{\n  \"type\": \"service_account\",\n  \"project_id\": \"my-project\",\n  ...\n}"),
   157  					),
   158  					Project: "my-project",
   159  					Region:  "us-east",
   160  				},
   161  				ClusterName:      "complex-cluster",
   162  				Zone:             "us-east1-b",
   163  				InitialNodeCount: "5",
   164  				MachineType:      "n1-standard-4",
   165  				AdditionalZones:  "us-east1-c,us-east1-d",
   166  				MinMasterVersion: "1.10.6-gke.1",
   167  			},
   168  			expected: mustAsset("testassets/complex.tf"),
   169  		},
   170  	}
   171  	for _, test := range tests {
   172  		t.Run(test.name, func(t *testing.T) {
   173  			req := require.New(t)
   174  			actual, err := renderTerraformContents(test.asset)
   175  			req.NoError(err)
   176  			if actual != test.expected {
   177  				diff := difflib.UnifiedDiff{
   178  					A:        difflib.SplitLines(test.expected),
   179  					B:        difflib.SplitLines(actual),
   180  					FromFile: "expected contents",
   181  					ToFile:   "actual contents",
   182  					Context:  3,
   183  				}
   184  
   185  				diffText, err := difflib.GetUnifiedDiffString(diff)
   186  				req.NoError(err)
   187  
   188  				t.Errorf("Test %s did not match, diff:\n%s", test.name, diffText)
   189  			}
   190  		})
   191  	}
   192  }
   193  
   194  func mustAsset(name string) string {
   195  	b, err := ioutil.ReadFile(name)
   196  	if err != nil {
   197  		panic(err)
   198  	}
   199  	return string(b)
   200  }
   201  
   202  func TestBuildAsset(t *testing.T) {
   203  	type args struct {
   204  		asset   api.GKEAsset
   205  		builder *templates.Builder
   206  	}
   207  	tests := []struct {
   208  		name    string
   209  		args    args
   210  		want    api.GKEAsset
   211  		wantErr bool
   212  	}{
   213  		{
   214  			name: "basic",
   215  			args: args{
   216  				asset: api.GKEAsset{
   217  					ClusterName:      `{{repl "cluster_name_built"}}`,
   218  					Zone:             `{{repl "zone_built"}}`,
   219  					InitialNodeCount: `{{repl "initial_node_count_built"}}`,
   220  					MachineType:      `{{repl "machine_type_built"}}`,
   221  					AdditionalZones:  `{{repl "additional_zones_built"}}`,
   222  					MinMasterVersion: `{{repl "min_master_version_built"}}`, // not built
   223  				},
   224  				builder: &templates.Builder{},
   225  			},
   226  			want: api.GKEAsset{
   227  				ClusterName:      "cluster_name_built",
   228  				Zone:             "zone_built",
   229  				InitialNodeCount: "initial_node_count_built",
   230  				MachineType:      "machine_type_built",
   231  				AdditionalZones:  "additional_zones_built",
   232  				MinMasterVersion: `{{repl "min_master_version_built"}}`, // not built
   233  			},
   234  		},
   235  	}
   236  	for _, tt := range tests {
   237  		t.Run(tt.name, func(t *testing.T) {
   238  			req := require.New(t)
   239  
   240  			got, err := buildAsset(tt.args.asset, tt.args.builder)
   241  			if !tt.wantErr {
   242  				req.NoErrorf(err, "buildAsset() error = %v", err)
   243  			} else {
   244  				req.Error(err)
   245  			}
   246  
   247  			req.Equal(tt.want, got)
   248  		})
   249  	}
   250  }