github.com/leowmjw/otto@v0.2.1-0.20160126165905-6400716cf085/otto/testing_acceptance.go (about)

     1  package otto
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"testing"
     8  	"time"
     9  )
    10  
    11  // TestEnvVar must be set to a non-empty value for acceptance tests to run.
    12  const TestEnvVar = "OTTO_ACC"
    13  
    14  // TestCase is a single set of tests to run for an app to test the dev
    15  // experience. See Test for more details on how this operates.
    16  type TestCase struct {
    17  	// Precheck, if non-nil, will be called once before the test case
    18  	// runs at all. This can be used for some validation prior to the
    19  	// test running.
    20  	PreCheck func()
    21  
    22  	// Core is the core to use for testing. The Test* methods such
    23  	// as TestCoreConfig should be used to create the test core.
    24  	Core *Core
    25  
    26  	// Unit, if set to true, won't require the OTTO_ACC variable to be
    27  	// set and will run as a normal unit test.
    28  	Unit bool
    29  
    30  	// Steps are the set of operations that are run for this test case.
    31  	Steps []TestStep
    32  
    33  	// Teardown will be called before the test case is over regardless
    34  	// of if the test succeeded or failed. This should return an error
    35  	// in the case that the test can't guarantee all resources were
    36  	// properly cleaned up.
    37  	Teardown TestTeardownFunc
    38  }
    39  
    40  // TestStep is a single step within a TestCase.
    41  type TestStep interface {
    42  	// Run is used to run the TestStep. It should return an error if
    43  	// the step failed. If the step fails, then no further steps are
    44  	// called. The Teardown will be called on the TestCase.
    45  	Run(*Core) error
    46  }
    47  
    48  // TestTeardownFunc is the callback used for Teardown in TestCase.
    49  type TestTeardownFunc func(*Core) error
    50  
    51  // Test performs an acceptance test on a backend with the given test case.
    52  //
    53  // Tests are not run unless an environmental variable "TF_ACC" is
    54  // set to some non-empty value. This is to avoid test cases surprising
    55  // a user by creating real resources.
    56  //
    57  // Tests will fail unless the verbose flag (`go test -v`, or explicitly
    58  // the "-test.v" flag) is set. Because some acceptance tests take quite
    59  // long, we require the verbose flag so users are able to see progress
    60  // output.
    61  func Test(t TestT, c TestCase) {
    62  	// We only run acceptance tests if an env var is set because they're
    63  	// slow and generally require some outside configuration.
    64  	if !c.Unit && os.Getenv(TestEnvVar) == "" {
    65  		t.Skip(fmt.Sprintf(
    66  			"Acceptance tests skipped unless env '%s' set",
    67  			TestEnvVar))
    68  		return
    69  	}
    70  
    71  	// We require verbose mode so that the user knows what is going on.
    72  	if !c.Unit && !testTesting && !testing.Verbose() {
    73  		t.Fatal("Acceptance tests must be run with the -v flag on tests")
    74  		return
    75  	}
    76  
    77  	// Run the PreCheck if we have it
    78  	if c.PreCheck != nil {
    79  		c.PreCheck()
    80  	}
    81  
    82  	// Check that the core is provided
    83  	if c.Core == nil {
    84  		t.Fatal("Must provide a core")
    85  	}
    86  
    87  	// Compile the app
    88  	log.Printf("[WARN] test: compiling appfile...")
    89  	if err := c.Core.Compile(); err != nil {
    90  		t.Fatal("error compiling: ", err)
    91  	}
    92  
    93  	// Run the steps
    94  	for i, s := range c.Steps {
    95  		log.Printf("[WARN] Executing test step %d", i+1)
    96  		if err := s.Run(c.Core); err != nil {
    97  			t.Error(fmt.Sprintf("Failed step %d: %s", i+1, err))
    98  			break
    99  		}
   100  	}
   101  
   102  	// Cleanup
   103  	if c.Teardown != nil {
   104  		if err := c.Teardown(c.Core); err != nil {
   105  			t.Error(fmt.Sprintf(
   106  				"Teardown failed! Dangling resources may exist. Error:\n\n%s",
   107  				err))
   108  		}
   109  	}
   110  }
   111  
   112  // TestStepSleep is a debugging test step that inserts a sleep.
   113  // This is useful for debugging a failing acceptance test.
   114  type TestStepSleep struct{ Duration time.Duration }
   115  
   116  func (t *TestStepSleep) Run(*Core) error {
   117  	time.Sleep(t.Duration)
   118  	return nil
   119  }
   120  
   121  // TestT is the interface used to handle the test lifecycle of a test.
   122  //
   123  // Users should just use a *testing.T object, which implements this.
   124  type TestT interface {
   125  	Error(args ...interface{})
   126  	Fatal(args ...interface{})
   127  	Skip(args ...interface{})
   128  }
   129  
   130  var testTesting = false