github.com/apprenda/kismatic@v1.12.0/integration-tests/kismatic_platform_suite_test.go (about) 1 package integration_tests 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "net/http" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "runtime" 12 "strings" 13 "time" 14 15 "testing" 16 17 "github.com/aws/aws-sdk-go/aws" 18 "github.com/aws/aws-sdk-go/aws/credentials" 19 "github.com/aws/aws-sdk-go/aws/session" 20 "github.com/aws/aws-sdk-go/service/s3" 21 . "github.com/onsi/ginkgo" 22 "github.com/onsi/ginkgo/config" 23 "github.com/onsi/ginkgo/reporters" 24 . "github.com/onsi/gomega" 25 ) 26 27 func TestKismaticPlatform(t *testing.T) { 28 if !testing.Short() { 29 RegisterFailHandler(Fail) 30 junitResultsDir := createJUnitResultsDirectory(t) 31 filename := filepath.Join(junitResultsDir, fmt.Sprintf("junit_%d_%d.xml", config.GinkgoConfig.ParallelNode, time.Now().UnixNano())) 32 junitReporter := reporters.NewJUnitReporter(filename) 33 RunSpecsWithDefaultAndCustomReporters(t, "KET Suite", []Reporter{junitReporter}) 34 } 35 } 36 37 // Given that kismatic relies on local files, we create a temporary directory 38 // structure before running tests. The tarball for the kismatic build under test is copied 39 // to a known location. This location is then used to setup a working directory for each 40 // test, which will have a pristine copy of kismatic. 41 // This is what the temp directory structure looks like: 42 // - $TMP/kismatic/kismatic-${randomString} 43 // - current (contains the tarball for the kismatic build under test) 44 // - tests (contains the working directory for each test) 45 // - test-resources (contains the test resources that are defined in the suite) 46 // - releases (contains subdirectories, one for each downloaded version of kismatic) 47 // 48 49 var kismaticTempDir string 50 var currentKismaticDir string 51 var testWorkingDirs string 52 var testResourcesDir string 53 var releasesDir string 54 55 var _ = BeforeSuite(func() { 56 var err error 57 testsPath := filepath.Join(os.TempDir(), "kismatic") 58 err = os.MkdirAll(testsPath, 0777) 59 if err != nil { 60 Fail(fmt.Sprintf("Failed to make temp dir: %v", err)) 61 } 62 kismaticTempDir, err = ioutil.TempDir(testsPath, "kismatic-") 63 if err != nil { 64 Fail(fmt.Sprintf("Failed to make temp dir: %v", err)) 65 } 66 By(fmt.Sprintf("Created temp directory %s", kismaticTempDir)) 67 // Setup the directory structure 68 currentKismaticDir = filepath.Join(kismaticTempDir, "current") 69 if err = os.Mkdir(currentKismaticDir, 0700); err != nil { 70 Fail(fmt.Sprintf("Failed to make temp dir: %v", err)) 71 } 72 testWorkingDirs = filepath.Join(kismaticTempDir, "tests") 73 if err = os.Mkdir(testWorkingDirs, 0700); err != nil { 74 Fail(fmt.Sprintf("Failed to make temp dir: %v", err)) 75 } 76 releasesDir = filepath.Join(kismaticTempDir, "releases") 77 if err = os.Mkdir(releasesDir, 0700); err != nil { 78 Fail(fmt.Sprintf("Failed to make temp dir: %v", err)) 79 } 80 // Copy the current version of kismatic to known location 81 cmd := exec.Command("cp", fmt.Sprintf("../kismatic-%s.tar.gz", runtime.GOOS), currentKismaticDir) 82 cmd.Stderr = os.Stderr 83 cmd.Stdout = os.Stdout 84 if err = cmd.Run(); err != nil { 85 Fail("Failed to copy kismatic tarball") 86 } 87 // Copy test resources to known location. This copy creates the dir. 88 testResourcesDir = filepath.Join(kismaticTempDir, "test-resources") 89 err = CopyDir("test-resources/", testResourcesDir) 90 if err != nil { 91 Fail("Failed to copy test resources") 92 } 93 }) 94 95 var _ = AfterSuite(func() { 96 uploadTestLogs() 97 if !leaveIt() { 98 os.RemoveAll(kismaticTempDir) 99 } 100 }) 101 102 // sets up a working directory for a test by extracting the kismatic build under 103 // test to a temp directory. returns the path to the temp directory. 104 func setupTestWorkingDir() string { 105 tmp, err := ioutil.TempDir(testWorkingDirs, "test-") 106 if err != nil { 107 Fail(fmt.Sprintf("failed to create temp dir: %v", err)) 108 } 109 By("Test working directory is " + tmp) 110 err = extractCurrentKismatic(tmp) 111 if err != nil { 112 Fail(fmt.Sprintf("failed to extract kismatic to %s: %v", tmp, err)) 113 } 114 err = CopyDir(testResourcesDir, filepath.Join(tmp, "test-resources")) 115 if err != nil { 116 Fail(fmt.Sprintf("failed to copy test resources: %v", err)) 117 } 118 return tmp 119 } 120 121 // sets up a working directory for a test that requires a specific version of kismatic. 122 // the version of kismatic is extracted into the temp directory. 123 // returns the path to the temp directory. 124 func setupTestWorkingDirWithVersion(version string) string { 125 tmp, err := ioutil.TempDir(testWorkingDirs, "test-") 126 if err != nil { 127 Fail(fmt.Sprintf("failed to create temp dir: %v", err)) 128 } 129 By("Test working directory is " + tmp) 130 tarball, err := getKismaticReleaseTarball(version) 131 if err != nil { 132 Fail(fmt.Sprintf("failed to get kismatic tarball for version %s: %v", version, err)) 133 } 134 if err = extractTarball(tarball, tmp); err != nil { 135 Fail(fmt.Sprintf("failed to extract kismatic to %s: %v", tmp, err)) 136 } 137 err = CopyDir(testResourcesDir, filepath.Join(tmp, "test-resources")) 138 if err != nil { 139 Fail(fmt.Sprintf("failed to copy test resources: %v", err)) 140 } 141 return tmp 142 } 143 144 func extractTarball(src, dst string) error { 145 return exec.Command("tar", "-zxf", src, "-C", dst).Run() 146 } 147 148 // extracts the current build of kismatic (the one being tested) 149 func extractCurrentKismatic(dest string) error { 150 By(fmt.Sprintf("Extracting current kismatic to directory %q", dest)) 151 if err := extractTarball(filepath.Join(currentKismaticDir, fmt.Sprintf("kismatic-%s.tar.gz", runtime.GOOS)), dest); err != nil { 152 return fmt.Errorf("error extracting kismatic to %s: %v", dest, err) 153 } 154 return nil 155 } 156 157 // gets the given kismatic release tarball from the local filesystem if available. 158 // otherwise, it will attempt to download it from github. 159 func getKismaticReleaseTarball(version string) (string, error) { 160 tarFile := filepath.Join(releasesDir, version, "kismatic-"+runtime.GOOS+".tar.gz") 161 _, err := os.Stat(tarFile) 162 if err == nil { 163 // we have already downloaded this release 164 return tarFile, nil 165 } 166 if os.IsNotExist(err) { 167 // we haven't downloaded this release. download it. 168 if err = os.MkdirAll(filepath.Dir(tarFile), 0700); err != nil { 169 return "", fmt.Errorf("failed to create download directory: %v", err) 170 } 171 if err = downloadKismaticReleaseTarball(version, tarFile); err != nil { 172 return "", fmt.Errorf("failed to download ket tarball: %v", err) 173 } 174 return tarFile, nil 175 } 176 // some other error occurred 177 return "", fmt.Errorf("failed to stat dir: %v", err) 178 } 179 180 // downloads the specified kismatic version and stores it as file 181 func downloadKismaticReleaseTarball(version string, file string) error { 182 url := fmt.Sprintf("https://github.com/apprenda/kismatic/releases/download/%[1]s/kismatic-%[1]s-linux-amd64.tar.gz", version) 183 if runtime.GOOS == "darwin" { 184 url = fmt.Sprintf("https://github.com/apprenda/kismatic/releases/download/%[1]s/kismatic-%[1]s-darwin-amd64.tar.gz", version) 185 } 186 return exec.Command("wget", url, "-O", file).Run() 187 } 188 189 func uploadTestLogs() { 190 tests, err := ioutil.ReadDir(testWorkingDirs) 191 if err != nil { 192 return 193 } 194 for _, t := range tests { 195 if strings.Contains(t.Name(), "test-") { 196 uploadKismaticLogs(filepath.Join(testWorkingDirs, t.Name())) 197 } 198 } 199 } 200 201 // Upload the kismatic package to S3 202 func uploadKismaticLogs(path string) { 203 accessKeyID := os.Getenv("AWS_ACCESS_KEY_ID") 204 secretAccessKey := os.Getenv("AWS_SECRET_ACCESS_KEY") 205 if accessKeyID == "" || secretAccessKey == "" { 206 return 207 } 208 creds := credentials.NewStaticCredentials(accessKeyID, secretAccessKey, "") 209 _, err := creds.Get() 210 if err != nil { 211 fmt.Printf("bad credentials: %s", err) 212 } 213 cfg := aws.NewConfig().WithRegion("us-east-1").WithCredentials(creds) 214 svc := s3.New(session.New(), cfg) 215 216 // Tar the folder 217 archiveName := "/tmp/kismatic-integration-" 218 pullRequestNumber := os.Getenv("CIRCLE_PR_NUMBER") 219 if pullRequestNumber != "" { 220 archiveName = archiveName + "pr-#" + pullRequestNumber + "-" 221 } 222 buildNumber := os.Getenv("CIRCLE_BUILD_NUM") 223 if buildNumber != "" { 224 archiveName = archiveName + "build-#" + buildNumber + "-" 225 } 226 timestamp := time.Now().UTC().Format("2006-01-02T15:04:05-0700") 227 archiveName = archiveName + timestamp + ".tar.gz" 228 229 // upload runs directory 230 if _, err := os.Stat(filepath.Join(path, "runs")); os.IsNotExist(err) { 231 fmt.Printf("Runs directory not found in %s. Skipping upload of logs to S3.\n", path) 232 return 233 } 234 cmd := exec.Command("tar", "czf", archiveName, filepath.Join(path, "runs")) 235 // include the diagnostics directory if exists 236 if _, err := os.Stat(filepath.Join(path, "diagnostics")); err == nil { 237 fmt.Println("Including diagnostics directory") 238 cmd.Args = append(cmd.Args, filepath.Join(path, "diagnostics")) 239 } 240 cmd.Stdout = os.Stdout 241 cmd.Stderr = os.Stderr 242 if err := cmd.Run(); err != nil { 243 fmt.Println("failed to tar artifacts") 244 return 245 } 246 247 file, err := os.Open(archiveName) 248 if err != nil { 249 fmt.Printf("err opening file: %s", err) 250 } 251 defer file.Close() 252 fileInfo, _ := file.Stat() 253 size := fileInfo.Size() 254 buffer := make([]byte, size) // read file content to buffer 255 256 file.Read(buffer) 257 fileBytes := bytes.NewReader(buffer) 258 fileType := http.DetectContentType(buffer) 259 s3path := "/logs/" 260 if pullRequestNumber != "" { 261 s3path = s3path + "pull-requests/" + pullRequestNumber + "/" 262 } 263 if buildNumber != "" { 264 s3path = s3path + buildNumber + "/" 265 } 266 s3path = s3path + fileInfo.Name() 267 268 s3bucket := "kismatic-integration-tests" 269 downloadPath := fmt.Sprintf("https://console.aws.amazon.com/s3/buckets/%s%s", s3bucket, s3path) 270 fmt.Println("Uploading logs to S3. Get them at", downloadPath) 271 params := &s3.PutObjectInput{ 272 Bucket: aws.String(s3bucket), 273 Key: aws.String(s3path), 274 Body: fileBytes, 275 ContentLength: aws.Int64(size), 276 ContentType: aws.String(fileType), 277 } 278 _, err = svc.PutObject(params) 279 if err != nil { 280 fmt.Printf("Error uploading logs to S3: %v", err) 281 } 282 } 283 284 func createJUnitResultsDirectory(t *testing.T) string { 285 dir := "/tmp/ket-junit-results" 286 err := os.Mkdir(dir, 0755) 287 if os.IsExist(err) { 288 return dir 289 } 290 if err != nil { 291 t.Fatalf("error creating junit results directory: %v", err) 292 } 293 return dir 294 }