github.com/Beeketing/helm@v2.12.1+incompatible/pkg/releasetesting/test_suite_test.go (about) 1 /* 2 Copyright The Helm 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 releasetesting 18 19 import ( 20 "io" 21 "io/ioutil" 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/api/core/v1" 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 failure, 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: ioutil.Discard}, 324 } 325 } 326 327 func (p *podSucceededKubeClient) WaitAndGetCompletedPodPhase(ns string, r io.Reader, timeout time.Duration) (v1.PodPhase, error) { 328 return v1.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: ioutil.Discard}, 338 } 339 } 340 341 func (p *podFailedKubeClient) WaitAndGetCompletedPodPhase(ns string, r io.Reader, timeout time.Duration) (v1.PodPhase, error) { 342 return v1.PodFailed, nil 343 }