github.com/fafucoder/cilium@v1.6.11/test/test_suite_test.go (about) 1 // Copyright 2017-2019 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package ciliumTest 16 17 import ( 18 "fmt" 19 "os" 20 "os/exec" 21 "path/filepath" 22 "strconv" 23 "testing" 24 "time" 25 26 "github.com/cilium/cilium/pkg/logging" 27 "github.com/cilium/cilium/test/config" 28 . "github.com/cilium/cilium/test/ginkgo-ext" 29 ginkgoext "github.com/cilium/cilium/test/ginkgo-ext" 30 "github.com/cilium/cilium/test/helpers" 31 gops "github.com/google/gops/agent" 32 "github.com/onsi/ginkgo" 33 ginkgoconfig "github.com/onsi/ginkgo/config" 34 . "github.com/onsi/gomega" 35 "github.com/onsi/gomega/format" 36 "github.com/sirupsen/logrus" 37 ) 38 39 var ( 40 log = logging.DefaultLogger 41 DefaultSettings = map[string]string{ 42 "K8S_VERSION": "1.16", 43 } 44 k8sNodesEnv = "K8S_NODES" 45 commandsLogFileName = "cmds.log" 46 ) 47 48 func init() { 49 50 // Open socket for using gops to get stacktraces in case the tests deadlock. 51 if err := gops.Listen(gops.Options{ShutdownCleanup: true}); err != nil { 52 errorString := fmt.Sprintf("unable to start gops: %s", err) 53 fmt.Println(errorString) 54 os.Exit(-1) 55 } 56 57 for k, v := range DefaultSettings { 58 getOrSetEnvVar(k, v) 59 } 60 config.CiliumTestConfig.ParseFlags() 61 62 os.RemoveAll(helpers.TestResultsPath) 63 64 format.UseStringerRepresentation = true 65 } 66 67 func configLogsOutput() { 68 log.SetLevel(logrus.DebugLevel) 69 log.Out = &config.TestLogWriter 70 logrus.SetFormatter(&config.Formatter) 71 log.Formatter = &config.Formatter 72 log.Hooks.Add(&config.LogHook{}) 73 74 ginkgoext.GinkgoWriter = NewWriter(log.Out) 75 } 76 77 func ShowCommands() { 78 if !config.CiliumTestConfig.ShowCommands { 79 return 80 } 81 82 helpers.SSHMetaLogs = ginkgoext.NewWriter(os.Stdout) 83 } 84 85 func TestTest(t *testing.T) { 86 if config.CiliumTestConfig.TestScope != "" { 87 helpers.UserDefinedScope = config.CiliumTestConfig.TestScope 88 fmt.Printf("User specified the scope: %q\n", config.CiliumTestConfig.TestScope) 89 } 90 91 configLogsOutput() 92 ShowCommands() 93 94 if config.CiliumTestConfig.HoldEnvironment { 95 RegisterFailHandler(helpers.Fail) 96 } else { 97 RegisterFailHandler(Fail) 98 } 99 junitReporter := ginkgoext.NewJUnitReporter(fmt.Sprintf( 100 "%s.xml", helpers.GetScopeWithVersion())) 101 RunSpecsWithDefaultAndCustomReporters( 102 t, fmt.Sprintf("Suite-%s", helpers.GetScopeWithVersion()), 103 []ginkgo.Reporter{junitReporter}) 104 } 105 106 func goReportVagrantStatus() chan bool { 107 if ginkgoconfig.DefaultReporterConfig.Verbose || 108 ginkgoconfig.DefaultReporterConfig.Succinct { 109 // Dev told us they want more/less information than default. Skip. 110 return nil 111 } 112 113 exit := make(chan bool) 114 go func() { 115 done := false 116 iter := 0 117 for { 118 var out string 119 select { 120 case ok := <-exit: 121 if ok { 122 out = "●\n" 123 } else { 124 out = "◌\n" 125 } 126 done = true 127 default: 128 out = string(rune(int('◜') + iter%4)) 129 } 130 fmt.Printf("\rSpinning up vagrant VMs... %s", out) 131 if done { 132 return 133 } 134 time.Sleep(250 * time.Millisecond) 135 iter++ 136 } 137 }() 138 return exit 139 } 140 141 func reportCreateVMFailure(vm string, err error) { 142 failmsg := fmt.Sprintf(` 143 ===================== ERROR - VM PROVISION FAILED ===================== 144 145 Unable to provision and start VM %q: %s", vm, err 146 147 ======================================================================= 148 `, vm, err) 149 ginkgoext.GinkgoPrint(failmsg) 150 Fail(failmsg) 151 } 152 153 var _ = BeforeAll(func() { 154 go func() { 155 defer GinkgoRecover() 156 time.Sleep(config.CiliumTestConfig.Timeout) 157 msg := fmt.Sprintf("Test suite timed out after %s", config.CiliumTestConfig.Timeout) 158 By(msg) 159 Fail(msg) 160 }() 161 162 var err error 163 164 logger := log.WithFields(logrus.Fields{"testName": "BeforeAll"}) 165 scope, err := helpers.GetScope() 166 if err != nil { 167 Fail(fmt.Sprintf( 168 "Cannot get the scope for running test, please use --cilium.testScope option: %s", 169 err)) 170 } 171 172 switch helpers.GetCurrentIntegration() { 173 case helpers.CIIntegrationFlannel: 174 switch helpers.GetCurrentK8SEnv() { 175 case "1.8": 176 log.Infof("Cilium in %q mode is not supported in Kubernets 1.8 due CNI < 0.6.0", helpers.CIIntegrationFlannel) 177 os.Exit(0) 178 return 179 } 180 } 181 182 if config.CiliumTestConfig.SSHConfig != "" { 183 // If we set a different VM that it's not in our test environment 184 // ginkgo cannot provision it, so skip setup below. 185 return 186 } 187 188 if progressChan := goReportVagrantStatus(); progressChan != nil { 189 defer func() { progressChan <- err == nil }() 190 } 191 192 switch scope { 193 case helpers.Runtime: 194 var err error 195 196 // Boot / provision VMs if specified by configuration. 197 if config.CiliumTestConfig.Reprovision { 198 err = helpers.CreateVM(helpers.Runtime) 199 if err != nil { 200 log.WithError(err).Error("Error starting VM") 201 reportCreateVMFailure(helpers.Runtime, err) 202 } 203 } 204 205 vm := helpers.InitRuntimeHelper(helpers.Runtime, logger) 206 err = vm.SetUpCilium() 207 208 if err != nil { 209 // AfterFailed function is not defined in this scope, fired the 210 // ReportFailed manually for this assert to gather cilium logs Fix 211 // #3428 212 vm.ReportFailed() 213 log.WithError(err).Error("Cilium was unable to be set up correctly") 214 reportCreateVMFailure(helpers.Runtime, err) 215 } 216 go vm.PprofReport() 217 218 case helpers.K8s: 219 //FIXME: This should be: 220 // Start k8s1 and provision kubernetes. 221 // When finish, start to build cilium in background 222 // Start k8s2 223 // Wait until compilation finished, and pull cilium image on k8s2 224 225 // Name for K8s VMs depends on K8s version that is running. 226 227 // Boot / provision VMs if specified by configuration. 228 if config.CiliumTestConfig.Reprovision { 229 err = helpers.CreateVM(helpers.K8s1VMName()) 230 if err != nil { 231 reportCreateVMFailure(helpers.K8s1VMName(), err) 232 } 233 234 err = helpers.CreateVM(helpers.K8s2VMName()) 235 if err != nil { 236 reportCreateVMFailure(helpers.K8s2VMName(), err) 237 } 238 239 // For Nightly test we need to have more than two kubernetes nodes. If 240 // the env variable K8S_NODES is present, more nodes will be created. 241 if nodes := os.Getenv(k8sNodesEnv); nodes != "" { 242 nodesInt, err := strconv.Atoi(nodes) 243 if err != nil { 244 Fail(fmt.Sprintf("%s value is not a number %q", k8sNodesEnv, nodes)) 245 } 246 for i := 3; i <= nodesInt; i++ { 247 vmName := fmt.Sprintf("%s%d-%s", helpers.K8s, i, helpers.GetCurrentK8SEnv()) 248 err = helpers.CreateVM(vmName) 249 if err != nil { 250 reportCreateVMFailure(vmName, err) 251 } 252 } 253 } 254 } 255 kubectl := helpers.CreateKubectl(helpers.K8s1VMName(), logger) 256 257 kubectl.ApplyDefault(helpers.GetFilePath("../examples/kubernetes/addons/prometheus/prometheus.yaml")) 258 259 go kubectl.PprofReport() 260 } 261 return 262 }) 263 264 var _ = AfterSuite(func() { 265 if !helpers.IsRunningOnJenkins() { 266 GinkgoPrint("AfterSuite: not running on Jenkins; leaving VMs running for debugging") 267 return 268 } 269 // Errors are not checked here because it should fail on BeforeAll 270 scope, _ := helpers.GetScope() 271 GinkgoPrint("cleaning up VMs started for %s tests", scope) 272 switch scope { 273 case helpers.Runtime: 274 helpers.DestroyVM(helpers.Runtime) 275 case helpers.K8s: 276 helpers.DestroyVM(helpers.K8s1VMName()) 277 helpers.DestroyVM(helpers.K8s2VMName()) 278 } 279 return 280 }) 281 282 func getOrSetEnvVar(key, value string) { 283 if val := os.Getenv(key); val == "" { 284 log.Infof("environment variable %q was not set; setting to default value %q", key, value) 285 os.Setenv(key, value) 286 } 287 } 288 289 var _ = AfterEach(func() { 290 291 // Send the Checks output to Junit report to be render on Jenkins. 292 defer helpers.CheckLogs.Reset() 293 GinkgoPrint("<Checks>\n%s\n</Checks>\n", helpers.CheckLogs.Buffer.String()) 294 295 defer config.TestLogWriterReset() 296 err := helpers.CreateLogFile(config.TestLogFileName, config.TestLogWriter.Bytes()) 297 if err != nil { 298 log.WithError(err).Errorf("cannot create log file '%s'", config.TestLogFileName) 299 return 300 } 301 302 defer helpers.SSHMetaLogs.Reset() 303 err = helpers.CreateLogFile(commandsLogFileName, helpers.SSHMetaLogs.Bytes()) 304 if err != nil { 305 log.WithError(err).Errorf("cannot create log file '%s'", commandsLogFileName) 306 return 307 } 308 309 // This piece of code is to enable zip attachments on Junit Output. 310 if ginkgo.CurrentGinkgoTestDescription().Failed && helpers.IsRunningOnJenkins() { 311 // ReportDirectory is already created. No check the error 312 path, _ := helpers.CreateReportDirectory() 313 zipFileName := fmt.Sprintf("%s_%s.zip", helpers.MakeUID(), ginkgoext.GetTestName()) 314 zipFilePath := filepath.Join(helpers.TestResultsPath, zipFileName) 315 316 _, err := exec.Command( 317 "/bin/bash", "-c", 318 fmt.Sprintf("zip -qr %s %s", zipFilePath, path)).CombinedOutput() 319 if err != nil { 320 log.WithError(err).Errorf("cannot create zip file '%s'", zipFilePath) 321 } 322 323 ginkgoext.GinkgoPrint("[[ATTACHMENT|%s]]", zipFileName) 324 } 325 326 if !ginkgo.CurrentGinkgoTestDescription().Failed && helpers.IsRunningOnJenkins() { 327 // If the test success delete the monitor.log filename to not store all 328 // the data in Jenkins 329 testPath, err := helpers.CreateReportDirectory() 330 if err != nil { 331 log.WithError(err).Error("cannot retrieve test result path") 332 return 333 } 334 _ = os.Remove(filepath.Join(testPath, helpers.MonitorLogFileName)) 335 } 336 })