github.com/quay/claircore@v1.5.28/test/integration/integration.go (about)

     1  // Package integration is a helper for running integration tests.
     2  package integration
     3  
     4  import (
     5  	"context"
     6  	"errors"
     7  	"io"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"sync"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  // Skip will skip the current test or benchmark if this package was built without
    17  // the "integration" build tag unless the "CI" environment variable is defined
    18  // and the "short" flag is not provided.
    19  //
    20  // This should be used as an annotation at the top of the function, like
    21  // (*testing.T).Parallel().
    22  //
    23  // See the example for usage.
    24  func Skip(t testing.TB) {
    25  	switch {
    26  	case testing.Short():
    27  		t.Skip(`skipping integration test: short tests`)
    28  	case inCI && integrationTag:
    29  		t.Log(`enabling integration test: environment variable "CI" is defined`)
    30  	case integrationTag:
    31  		t.Skip("skipping integration test: integration tag not provided")
    32  	}
    33  }
    34  
    35  // Skip is an internal variant of [Skip] that reports the decision and
    36  // doesn't log.
    37  //
    38  // Because this calls [testing.Short], it cannot be used in the [package block]
    39  // or an init function.
    40  //
    41  // [package block]: https://go.dev/ref/spec#Declarations_and_scope
    42  func skip() bool {
    43  	return testing.Short() || integrationTag && !inCI
    44  }
    45  
    46  var inCI, inGHA, externalDB bool
    47  
    48  func init() {
    49  	_, inCI = os.LookupEnv("CI")
    50  	_, inGHA = os.LookupEnv("GITHUB_ACTIONS")
    51  	_, externalDB = os.LookupEnv(EnvPGConnString)
    52  	_, actuallyAct := os.LookupEnv("ACT")
    53  
    54  	inGHA = inGHA && !actuallyAct
    55  }
    56  
    57  // CacheDir reports a directory for caching test data and creates it if
    58  // necessary.
    59  func CacheDir(t testing.TB) string {
    60  	cacheOnce.Do(func() {
    61  		d, err := os.UserCacheDir()
    62  		if err != nil {
    63  			t.Fatalf("unable to determine test cache dir: %v", err)
    64  		}
    65  		if err := os.MkdirAll(d, 0o755); err != nil {
    66  			t.Fatalf("unable to create test cache dir: %v", err)
    67  		}
    68  		d = filepath.Join(d, `clair-testing`)
    69  		switch err := os.Mkdir(d, 0o755); {
    70  		case errors.Is(err, nil): // Make cachedir tag
    71  			p := filepath.Join(d, `CACHEDIR.TAG`)
    72  			f, err := os.Create(p)
    73  			if err != nil {
    74  				// If we can't create this file, we're going to have a hell of a
    75  				// time creating other ones.
    76  				t.Fatalf("tried to create %q but failed: %v", p, err)
    77  			}
    78  			defer f.Close()
    79  			if _, err := io.WriteString(f, cachedirtag); err != nil {
    80  				t.Logf("error writing %q contents: %v", p, err)
    81  			}
    82  		case errors.Is(err, os.ErrExist): // Pre-existing
    83  		default:
    84  			t.Fatalf("unable to create test cache dir: %v", err)
    85  		}
    86  		cacheDir = d
    87  	})
    88  	if cacheDir == "" {
    89  		t.Fatal("test cache dir error, check previous tests")
    90  	}
    91  	return cacheDir
    92  }
    93  
    94  var (
    95  	cacheOnce sync.Once
    96  	cacheDir  string
    97  )
    98  
    99  const cachedirtag = `Signature: 8a477f597d28d172789f06886806bc55
   100  # This file is a cache directory tag created for "github.com/quay/claircore" test data.
   101  # For information about cache directory tags, see:
   102  #	http://www.brynosaurus.com/cachedir/
   103  `
   104  
   105  // PackageCacheDir reports a directory for caching per-package test data and
   106  // creates it if necessary.
   107  func PackageCacheDir(t testing.TB) string {
   108  	pkgCacheOnce.Do(func() {
   109  		ctx := context.Background()
   110  		done := func() {}
   111  		if d, ok := t.(deadliner); ok {
   112  			if dl, ok := d.Deadline(); ok {
   113  				ctx, done = context.WithDeadline(ctx, dl)
   114  			}
   115  			// If the above is false, then the test explicitly asked for no
   116  			// timeout.
   117  		} else {
   118  			// Absurdly high timeout. Even higher than the previous 5 seconds.
   119  			ctx, done = context.WithTimeout(ctx, 60*time.Second)
   120  		}
   121  		defer done()
   122  		// This exec'ing is needed be cause test binaries are not built with
   123  		// full debug.BuildInfo filled out.
   124  		out, err := exec.CommandContext(ctx, `go`, `list`, `-m`).Output()
   125  		if err != nil {
   126  			if exit := new(exec.ExitError); errors.As(err, &exit) {
   127  				t.Logf("exit code: %d", exit.ExitCode())
   128  				t.Logf("stderr:\n%s", string(exit.Stderr))
   129  			}
   130  			t.Fatal(err)
   131  		}
   132  		skip := len(out) - 1
   133  		out, err = exec.CommandContext(ctx, `go`, `list`, `.`).Output()
   134  		if err != nil {
   135  			if exit := new(exec.ExitError); errors.As(err, &exit) {
   136  				t.Logf("exit code: %d", exit.ExitCode())
   137  				t.Logf("stderr:\n%s", string(exit.Stderr))
   138  			}
   139  			t.Fatal(err)
   140  		}
   141  		// Swap separators, except for the one at the module/package boundary.
   142  		for i, b := range out {
   143  			if b == '/' && i != skip {
   144  				out[i] = '_'
   145  			}
   146  		}
   147  		// Join the resulting path (with the newline chomped) with the cache
   148  		// root.
   149  		d := CacheDir(t)
   150  		d = filepath.Join(d, string(out[:len(out)-1]))
   151  		if err := os.MkdirAll(d, 0o755); err != nil {
   152  			t.Fatalf("unable to create per-package test cache dir %q: %v", d, err)
   153  		}
   154  		pkgCacheDir = d
   155  	})
   156  	if pkgCacheDir == "" {
   157  		t.Fatal("test cache dir error, check previous tests")
   158  	}
   159  	return pkgCacheDir
   160  }
   161  
   162  // Deadliner is implemented by [testing.T] to report the test deadline.
   163  type deadliner interface {
   164  	Deadline() (deadline time.Time, ok bool)
   165  }
   166  
   167  var pkgCacheOnce sync.Once
   168  var pkgCacheDir string