github.com/cloudposse/helm@v2.2.3+incompatible/pkg/releasetesting/test_suite_test.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     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 releasetesting
    18  
    19  import (
    20  	"io"
    21  	"os"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/golang/protobuf/ptypes/timestamp"
    26  	"golang.org/x/net/context"
    27  	grpc "google.golang.org/grpc"
    28  	"google.golang.org/grpc/metadata"
    29  	"k8s.io/kubernetes/pkg/api"
    30  
    31  	"k8s.io/helm/pkg/helm"
    32  	"k8s.io/helm/pkg/proto/hapi/chart"
    33  	"k8s.io/helm/pkg/proto/hapi/release"
    34  	"k8s.io/helm/pkg/proto/hapi/services"
    35  	"k8s.io/helm/pkg/storage"
    36  	"k8s.io/helm/pkg/storage/driver"
    37  	tillerEnv "k8s.io/helm/pkg/tiller/environment"
    38  )
    39  
    40  const manifestWithTestSuccessHook = `
    41  apiVersion: v1
    42  kind: Pod
    43  metadata:
    44    name: finding-nemo,
    45    annotations:
    46      "helm.sh/hook": test-success
    47  spec:
    48    containers:
    49    - name: nemo-test
    50      image: fake-image
    51      cmd: fake-command
    52  `
    53  
    54  const manifestWithTestFailureHook = `
    55  apiVersion: v1
    56  kind: Pod
    57  metadata:
    58    name: gold-rush,
    59    annotations:
    60      "helm.sh/hook": test-failure
    61  spec:
    62    containers:
    63    - name: gold-finding-test
    64      image: fake-gold-finding-image
    65      cmd: fake-gold-finding-command
    66  `
    67  const manifestWithInstallHooks = `apiVersion: v1
    68  kind: ConfigMap
    69  metadata:
    70    name: test-cm
    71    annotations:
    72      "helm.sh/hook": post-install,pre-delete
    73  data:
    74    name: value
    75  `
    76  
    77  func TestNewTestSuite(t *testing.T) {
    78  	rel := releaseStub()
    79  
    80  	_, err := NewTestSuite(rel)
    81  	if err != nil {
    82  		t.Errorf("%s", err)
    83  	}
    84  }
    85  
    86  func TestRun(t *testing.T) {
    87  
    88  	testManifests := []string{manifestWithTestSuccessHook, manifestWithTestFailureHook}
    89  	ts := testSuiteFixture(testManifests)
    90  	if err := ts.Run(testEnvFixture()); err != nil {
    91  		t.Errorf("%s", err)
    92  	}
    93  
    94  	if ts.StartedAt == nil {
    95  		t.Errorf("Expected StartedAt to not be nil. Got: %v", ts.StartedAt)
    96  	}
    97  
    98  	if ts.CompletedAt == nil {
    99  		t.Errorf("Expected CompletedAt to not be nil. Got: %v", ts.CompletedAt)
   100  	}
   101  
   102  	if len(ts.Results) != 2 {
   103  		t.Errorf("Expected 2 test result. Got %v", len(ts.Results))
   104  	}
   105  
   106  	result := ts.Results[0]
   107  	if result.StartedAt == nil {
   108  		t.Errorf("Expected test StartedAt to not be nil. Got: %v", result.StartedAt)
   109  	}
   110  
   111  	if result.CompletedAt == nil {
   112  		t.Errorf("Expected test CompletedAt to not be nil. Got: %v", result.CompletedAt)
   113  	}
   114  
   115  	if result.Name != "finding-nemo" {
   116  		t.Errorf("Expected test name to be finding-nemo. Got: %v", result.Name)
   117  	}
   118  
   119  	if result.Status != release.TestRun_SUCCESS {
   120  		t.Errorf("Expected test result to be successful, got: %v", result.Status)
   121  	}
   122  
   123  	result2 := ts.Results[1]
   124  	if result2.StartedAt == nil {
   125  		t.Errorf("Expected test StartedAt to not be nil. Got: %v", result2.StartedAt)
   126  	}
   127  
   128  	if result2.CompletedAt == nil {
   129  		t.Errorf("Expected test CompletedAt to not be nil. Got: %v", result2.CompletedAt)
   130  	}
   131  
   132  	if result2.Name != "gold-rush" {
   133  		t.Errorf("Expected test name to be gold-rush, Got: %v", result2.Name)
   134  	}
   135  
   136  	if result2.Status != release.TestRun_FAILURE {
   137  		t.Errorf("Expected test result to be successful, got: %v", result2.Status)
   138  	}
   139  
   140  }
   141  
   142  func TestRunEmptyTestSuite(t *testing.T) {
   143  	ts := testSuiteFixture([]string{})
   144  	mockTestEnv := testEnvFixture()
   145  	if err := ts.Run(mockTestEnv); err != nil {
   146  		t.Errorf("%s", err)
   147  	}
   148  
   149  	if ts.StartedAt == nil {
   150  		t.Errorf("Expected StartedAt to not be nil. Got: %v", ts.StartedAt)
   151  	}
   152  
   153  	if ts.CompletedAt == nil {
   154  		t.Errorf("Expected CompletedAt to not be nil. Got: %v", ts.CompletedAt)
   155  	}
   156  
   157  	if len(ts.Results) != 0 {
   158  		t.Errorf("Expected 0 test result. Got %v", len(ts.Results))
   159  	}
   160  
   161  	stream := mockTestEnv.Stream.(*mockStream)
   162  	if len(stream.messages) == 0 {
   163  		t.Errorf("Expected at least one message, Got: %v", len(stream.messages))
   164  	} else {
   165  		msg := stream.messages[0].Msg
   166  		if msg != "No Tests Found" {
   167  			t.Errorf("Expected message 'No Tests Found', Got: %v", msg)
   168  		}
   169  	}
   170  
   171  }
   172  
   173  func TestRunSuccessWithTestFailureHook(t *testing.T) {
   174  	ts := testSuiteFixture([]string{manifestWithTestFailureHook})
   175  	env := testEnvFixture()
   176  	env.KubeClient = newPodFailedKubeClient()
   177  	if err := ts.Run(env); err != nil {
   178  		t.Errorf("%s", err)
   179  	}
   180  
   181  	if ts.StartedAt == nil {
   182  		t.Errorf("Expected StartedAt to not be nil. Got: %v", ts.StartedAt)
   183  	}
   184  
   185  	if ts.CompletedAt == nil {
   186  		t.Errorf("Expected CompletedAt to not be nil. Got: %v", ts.CompletedAt)
   187  	}
   188  
   189  	if len(ts.Results) != 1 {
   190  		t.Errorf("Expected 1 test result. Got %v", len(ts.Results))
   191  	}
   192  
   193  	result := ts.Results[0]
   194  	if result.StartedAt == nil {
   195  		t.Errorf("Expected test StartedAt to not be nil. Got: %v", result.StartedAt)
   196  	}
   197  
   198  	if result.CompletedAt == nil {
   199  		t.Errorf("Expected test CompletedAt to not be nil. Got: %v", result.CompletedAt)
   200  	}
   201  
   202  	if result.Name != "gold-rush" {
   203  		t.Errorf("Expected test name to be gold-rush, Got: %v", result.Name)
   204  	}
   205  
   206  	if result.Status != release.TestRun_SUCCESS {
   207  		t.Errorf("Expected test result to be successful, got: %v", result.Status)
   208  	}
   209  }
   210  
   211  func TestExtractTestManifestsFromHooks(t *testing.T) {
   212  	rel := releaseStub()
   213  	testManifests, err := extractTestManifestsFromHooks(rel.Hooks)
   214  	if err != nil {
   215  		t.Errorf("Expected no error, Got: %s", err)
   216  	}
   217  
   218  	if len(testManifests) != 1 {
   219  		t.Errorf("Expected 1 test manifest, Got: %v", len(testManifests))
   220  	}
   221  }
   222  
   223  func chartStub() *chart.Chart {
   224  	return &chart.Chart{
   225  		Metadata: &chart.Metadata{
   226  			Name: "nemo",
   227  		},
   228  		Templates: []*chart.Template{
   229  			{Name: "templates/hello", Data: []byte("hello: world")},
   230  			{Name: "templates/hooks", Data: []byte(manifestWithTestSuccessHook)},
   231  		},
   232  	}
   233  }
   234  
   235  func releaseStub() *release.Release {
   236  	date := timestamp.Timestamp{Seconds: 242085845, Nanos: 0}
   237  	return &release.Release{
   238  		Name: "lost-fish",
   239  		Info: &release.Info{
   240  			FirstDeployed: &date,
   241  			LastDeployed:  &date,
   242  			Status:        &release.Status{Code: release.Status_DEPLOYED},
   243  			Description:   "a release stub",
   244  		},
   245  		Chart:   chartStub(),
   246  		Config:  &chart.Config{Raw: `name: value`},
   247  		Version: 1,
   248  		Hooks: []*release.Hook{
   249  			{
   250  				Name:     "finding-nemo",
   251  				Kind:     "Pod",
   252  				Path:     "finding-nemo",
   253  				Manifest: manifestWithTestSuccessHook,
   254  				Events: []release.Hook_Event{
   255  					release.Hook_RELEASE_TEST_SUCCESS,
   256  				},
   257  			},
   258  			{
   259  				Name:     "test-cm",
   260  				Kind:     "ConfigMap",
   261  				Path:     "test-cm",
   262  				Manifest: manifestWithInstallHooks,
   263  				Events: []release.Hook_Event{
   264  					release.Hook_POST_INSTALL,
   265  					release.Hook_PRE_DELETE,
   266  				},
   267  			},
   268  		},
   269  	}
   270  }
   271  
   272  func testFixture() *test {
   273  	return &test{
   274  		manifest: manifestWithTestSuccessHook,
   275  		result:   &release.TestRun{},
   276  	}
   277  }
   278  
   279  func testSuiteFixture(testManifests []string) *TestSuite {
   280  	testResults := []*release.TestRun{}
   281  	ts := &TestSuite{
   282  		TestManifests: testManifests,
   283  		Results:       testResults,
   284  	}
   285  
   286  	return ts
   287  }
   288  
   289  func testEnvFixture() *Environment {
   290  	return newMockTestingEnvironment().Environment
   291  }
   292  
   293  func mockTillerEnvironment() *tillerEnv.Environment {
   294  	e := tillerEnv.New()
   295  	e.Releases = storage.Init(driver.NewMemory())
   296  	e.KubeClient = newPodSucceededKubeClient()
   297  	return e
   298  }
   299  
   300  type mockStream struct {
   301  	stream   grpc.ServerStream
   302  	messages []*services.TestReleaseResponse
   303  }
   304  
   305  func (rs *mockStream) Send(m *services.TestReleaseResponse) error {
   306  	rs.messages = append(rs.messages, m)
   307  	return nil
   308  }
   309  
   310  func (rs mockStream) SetHeader(m metadata.MD) error  { return nil }
   311  func (rs mockStream) SendHeader(m metadata.MD) error { return nil }
   312  func (rs mockStream) SetTrailer(m metadata.MD)       {}
   313  func (rs mockStream) SendMsg(v interface{}) error    { return nil }
   314  func (rs mockStream) RecvMsg(v interface{}) error    { return nil }
   315  func (rs mockStream) Context() context.Context       { return helm.NewContext() }
   316  
   317  type podSucceededKubeClient struct {
   318  	tillerEnv.PrintingKubeClient
   319  }
   320  
   321  func newPodSucceededKubeClient() *podSucceededKubeClient {
   322  	return &podSucceededKubeClient{
   323  		PrintingKubeClient: tillerEnv.PrintingKubeClient{Out: os.Stdout},
   324  	}
   325  }
   326  
   327  func (p *podSucceededKubeClient) WaitAndGetCompletedPodPhase(ns string, r io.Reader, timeout time.Duration) (api.PodPhase, error) {
   328  	return api.PodSucceeded, nil
   329  }
   330  
   331  type podFailedKubeClient struct {
   332  	tillerEnv.PrintingKubeClient
   333  }
   334  
   335  func newPodFailedKubeClient() *podFailedKubeClient {
   336  	return &podFailedKubeClient{
   337  		PrintingKubeClient: tillerEnv.PrintingKubeClient{Out: os.Stdout},
   338  	}
   339  }
   340  
   341  func (p *podFailedKubeClient) WaitAndGetCompletedPodPhase(ns string, r io.Reader, timeout time.Duration) (api.PodPhase, error) {
   342  	return api.PodFailed, nil
   343  }