github.com/canthefason/helm@v2.2.1-0.20170221172616-16b043b8d505+incompatible/pkg/releasetesting/test_suite.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 "fmt" 21 "strings" 22 23 "github.com/ghodss/yaml" 24 "github.com/golang/protobuf/ptypes/timestamp" 25 "k8s.io/kubernetes/pkg/api" 26 27 "k8s.io/helm/pkg/hooks" 28 "k8s.io/helm/pkg/proto/hapi/release" 29 util "k8s.io/helm/pkg/releaseutil" 30 "k8s.io/helm/pkg/timeconv" 31 ) 32 33 // TestSuite what tests are run, results, and metadata 34 type TestSuite struct { 35 StartedAt *timestamp.Timestamp 36 CompletedAt *timestamp.Timestamp 37 TestManifests []string 38 Results []*release.TestRun 39 } 40 41 type test struct { 42 manifest string 43 expectedSuccess bool 44 result *release.TestRun 45 } 46 47 // NewTestSuite takes a release object and returns a TestSuite object with test definitions 48 // extracted from the release 49 func NewTestSuite(rel *release.Release) (*TestSuite, error) { 50 testManifests, err := extractTestManifestsFromHooks(rel.Hooks) 51 if err != nil { 52 return nil, err 53 } 54 55 results := []*release.TestRun{} 56 57 return &TestSuite{ 58 TestManifests: testManifests, 59 Results: results, 60 }, nil 61 } 62 63 // Run executes tests in a test suite and stores a result within a given environment 64 func (ts *TestSuite) Run(env *Environment) error { 65 ts.StartedAt = timeconv.Now() 66 67 for _, testManifest := range ts.TestManifests { 68 test, err := newTest(testManifest) 69 if err != nil { 70 return err 71 } 72 73 test.result.StartedAt = timeconv.Now() 74 if err := env.streamRunning(test.result.Name); err != nil { 75 return err 76 } 77 78 resourceCreated := true 79 if err := env.createTestPod(test); err != nil { 80 resourceCreated = false 81 if streamErr := env.streamError(test.result.Info); streamErr != nil { 82 return err 83 } 84 } 85 86 resourceCleanExit := true 87 status := api.PodUnknown 88 if resourceCreated { 89 status, err = env.getTestPodStatus(test) 90 if err != nil { 91 resourceCleanExit = false 92 if streamErr := env.streamUnknown(test.result.Name, test.result.Info); streamErr != nil { 93 return streamErr 94 } 95 } 96 } 97 98 if resourceCreated && resourceCleanExit { 99 if err := test.assignTestResult(status); err != nil { 100 return err 101 } 102 103 if err := env.streamResult(test.result); err != nil { 104 return err 105 } 106 } 107 108 test.result.CompletedAt = timeconv.Now() 109 ts.Results = append(ts.Results, test.result) 110 } 111 112 ts.CompletedAt = timeconv.Now() 113 return nil 114 } 115 116 func (t *test) assignTestResult(podStatus api.PodPhase) error { 117 switch podStatus { 118 case api.PodSucceeded: 119 if t.expectedSuccess { 120 t.result.Status = release.TestRun_SUCCESS 121 } else { 122 t.result.Status = release.TestRun_FAILURE 123 } 124 case api.PodFailed: 125 if !t.expectedSuccess { 126 t.result.Status = release.TestRun_SUCCESS 127 } else { 128 t.result.Status = release.TestRun_FAILURE 129 } 130 default: 131 t.result.Status = release.TestRun_UNKNOWN 132 } 133 134 return nil 135 } 136 137 func expectedSuccess(hookTypes []string) (bool, error) { 138 for _, hookType := range hookTypes { 139 hookType = strings.ToLower(strings.TrimSpace(hookType)) 140 if hookType == hooks.ReleaseTestSuccess { 141 return true, nil 142 } else if hookType == hooks.ReleaseTestFailure { 143 return false, nil 144 } 145 } 146 return false, fmt.Errorf("No %s or %s hook found", hooks.ReleaseTestSuccess, hooks.ReleaseTestFailure) 147 } 148 149 func extractTestManifestsFromHooks(h []*release.Hook) ([]string, error) { 150 testHooks, err := hooks.FilterTestHooks(h) 151 if err != nil { 152 return nil, err 153 } 154 155 tests := []string{} 156 for _, h := range testHooks { 157 individualTests := util.SplitManifests(h.Manifest) 158 for _, t := range individualTests { 159 tests = append(tests, t) 160 } 161 } 162 return tests, nil 163 } 164 165 func newTest(testManifest string) (*test, error) { 166 var sh util.SimpleHead 167 err := yaml.Unmarshal([]byte(testManifest), &sh) 168 if err != nil { 169 return nil, err 170 } 171 172 if sh.Kind != "Pod" { 173 return nil, fmt.Errorf("%s is not a pod", sh.Metadata.Name) 174 } 175 176 hookTypes := sh.Metadata.Annotations[hooks.HookAnno] 177 expected, err := expectedSuccess(strings.Split(hookTypes, ",")) 178 if err != nil { 179 return nil, err 180 } 181 182 name := strings.TrimSuffix(sh.Metadata.Name, ",") 183 return &test{ 184 manifest: testManifest, 185 expectedSuccess: expected, 186 result: &release.TestRun{ 187 Name: name, 188 }, 189 }, nil 190 }