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  }