Use t.Helper() in our test helpers

Go 1.9 adds this new function which, when called, marks the caller as
being a "helper function". Helper function stack frames are then skipped
when trying to find a line of test code to blame for a test failure, so
that the code in the main test function appears in the test failure output
rather than a line within the helper function itself.

This covers many -- but probaly not all -- of our test helpers across
various packages.
This commit is contained in:
Martin Atkins 2017-08-25 16:23:47 -07:00
parent 8cf6756ab7
commit c12d64f340
7 changed files with 72 additions and 0 deletions

View File

@ -13,6 +13,8 @@ import (
// TestBackendConfig validates and configures the backend with the // TestBackendConfig validates and configures the backend with the
// given configuration. // given configuration.
func TestBackendConfig(t *testing.T, b Backend, c map[string]interface{}) Backend { func TestBackendConfig(t *testing.T, b Backend, c map[string]interface{}) Backend {
t.Helper()
// Get the proper config structure // Get the proper config structure
rc, err := config.NewRawConfig(c) rc, err := config.NewRawConfig(c)
if err != nil { if err != nil {
@ -45,6 +47,8 @@ func TestBackendConfig(t *testing.T, b Backend, c map[string]interface{}) Backen
// If you want to test locking, two backends must be given. If b2 is nil, // If you want to test locking, two backends must be given. If b2 is nil,
// then state lockign won't be tested. // then state lockign won't be tested.
func TestBackend(t *testing.T, b1, b2 Backend) { func TestBackend(t *testing.T, b1, b2 Backend) {
t.Helper()
testBackendStates(t, b1) testBackendStates(t, b1)
if b2 != nil { if b2 != nil {
@ -53,6 +57,8 @@ func TestBackend(t *testing.T, b1, b2 Backend) {
} }
func testBackendStates(t *testing.T, b Backend) { func testBackendStates(t *testing.T, b Backend) {
t.Helper()
states, err := b.States() states, err := b.States()
if err == ErrNamedStatesNotSupported { if err == ErrNamedStatesNotSupported {
t.Logf("TestBackend: named states not supported in %T, skipping", b) t.Logf("TestBackend: named states not supported in %T, skipping", b)
@ -231,6 +237,8 @@ func testBackendStates(t *testing.T, b Backend) {
} }
func testBackendStateLock(t *testing.T, b1, b2 Backend) { func testBackendStateLock(t *testing.T, b1, b2 Backend) {
t.Helper()
// Get the default state for each // Get the default state for each
b1StateMgr, err := b1.State(DefaultStateName) b1StateMgr, err := b1.State(DefaultStateName)
if err != nil { if err != nil {

View File

@ -54,6 +54,8 @@ func TestMain(m *testing.M) {
} }
func tempDir(t *testing.T) string { func tempDir(t *testing.T) string {
t.Helper()
dir, err := ioutil.TempDir("", "tf") dir, err := ioutil.TempDir("", "tf")
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
@ -99,6 +101,8 @@ func metaOverridesForProviderAndProvisioner(p terraform.ResourceProvider, pr ter
} }
func testModule(t *testing.T, name string) *module.Tree { func testModule(t *testing.T, name string) *module.Tree {
t.Helper()
mod, err := module.NewTreeModule("", filepath.Join(fixtureDir, name)) mod, err := module.NewTreeModule("", filepath.Join(fixtureDir, name))
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
@ -114,6 +118,8 @@ func testModule(t *testing.T, name string) *module.Tree {
// testPlan returns a non-nil noop plan. // testPlan returns a non-nil noop plan.
func testPlan(t *testing.T) *terraform.Plan { func testPlan(t *testing.T) *terraform.Plan {
t.Helper()
state := terraform.NewState() state := terraform.NewState()
state.RootModule().Outputs["foo"] = &terraform.OutputState{ state.RootModule().Outputs["foo"] = &terraform.OutputState{
Type: "string", Type: "string",
@ -127,6 +133,8 @@ func testPlan(t *testing.T) *terraform.Plan {
} }
func testPlanFile(t *testing.T, plan *terraform.Plan) string { func testPlanFile(t *testing.T, plan *terraform.Plan) string {
t.Helper()
path := testTempFile(t) path := testTempFile(t)
f, err := os.Create(path) f, err := os.Create(path)
@ -143,6 +151,8 @@ func testPlanFile(t *testing.T, plan *terraform.Plan) string {
} }
func testReadPlan(t *testing.T, path string) *terraform.Plan { func testReadPlan(t *testing.T, path string) *terraform.Plan {
t.Helper()
f, err := os.Open(path) f, err := os.Open(path)
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
@ -180,6 +190,8 @@ func testState() *terraform.State {
} }
func testStateFile(t *testing.T, s *terraform.State) string { func testStateFile(t *testing.T, s *terraform.State) string {
t.Helper()
path := testTempFile(t) path := testTempFile(t)
f, err := os.Create(path) f, err := os.Create(path)
@ -198,6 +210,8 @@ func testStateFile(t *testing.T, s *terraform.State) string {
// testStateFileDefault writes the state out to the default statefile // testStateFileDefault writes the state out to the default statefile
// in the cwd. Use `testCwd` to change into a temp cwd. // in the cwd. Use `testCwd` to change into a temp cwd.
func testStateFileDefault(t *testing.T, s *terraform.State) string { func testStateFileDefault(t *testing.T, s *terraform.State) string {
t.Helper()
f, err := os.Create(DefaultStateFilename) f, err := os.Create(DefaultStateFilename)
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
@ -214,6 +228,8 @@ func testStateFileDefault(t *testing.T, s *terraform.State) string {
// testStateFileRemote writes the state out to the remote statefile // testStateFileRemote writes the state out to the remote statefile
// in the cwd. Use `testCwd` to change into a temp cwd. // in the cwd. Use `testCwd` to change into a temp cwd.
func testStateFileRemote(t *testing.T, s *terraform.State) string { func testStateFileRemote(t *testing.T, s *terraform.State) string {
t.Helper()
path := filepath.Join(DefaultDataDir, DefaultStateFilename) path := filepath.Join(DefaultDataDir, DefaultStateFilename)
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
@ -234,6 +250,8 @@ func testStateFileRemote(t *testing.T, s *terraform.State) string {
// testStateRead reads the state from a file // testStateRead reads the state from a file
func testStateRead(t *testing.T, path string) *terraform.State { func testStateRead(t *testing.T, path string) *terraform.State {
t.Helper()
f, err := os.Open(path) f, err := os.Open(path)
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
@ -251,6 +269,8 @@ func testStateRead(t *testing.T, path string) *terraform.State {
// testStateOutput tests that the state at the given path contains // testStateOutput tests that the state at the given path contains
// the expected state string. // the expected state string.
func testStateOutput(t *testing.T, path string, expected string) { func testStateOutput(t *testing.T, path string, expected string) {
t.Helper()
newState := testStateRead(t, path) newState := testStateRead(t, path)
actual := strings.TrimSpace(newState.String()) actual := strings.TrimSpace(newState.String())
expected = strings.TrimSpace(expected) expected = strings.TrimSpace(expected)
@ -277,10 +297,14 @@ func testProvider() *terraform.MockResourceProvider {
} }
func testTempFile(t *testing.T) string { func testTempFile(t *testing.T) string {
t.Helper()
return filepath.Join(testTempDir(t), "state.tfstate") return filepath.Join(testTempDir(t), "state.tfstate")
} }
func testTempDir(t *testing.T) string { func testTempDir(t *testing.T) string {
t.Helper()
d, err := ioutil.TempDir("", "tf") d, err := ioutil.TempDir("", "tf")
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
@ -292,6 +316,8 @@ func testTempDir(t *testing.T) string {
// testRename renames the path to new and returns a function to defer to // testRename renames the path to new and returns a function to defer to
// revert the rename. // revert the rename.
func testRename(t *testing.T, base, path, new string) func() { func testRename(t *testing.T, base, path, new string) func() {
t.Helper()
if base != "" { if base != "" {
path = filepath.Join(base, path) path = filepath.Join(base, path)
new = filepath.Join(base, new) new = filepath.Join(base, new)
@ -310,6 +336,8 @@ func testRename(t *testing.T, base, path, new string) func() {
// testChdir changes the directory and returns a function to defer to // testChdir changes the directory and returns a function to defer to
// revert the old cwd. // revert the old cwd.
func testChdir(t *testing.T, new string) func() { func testChdir(t *testing.T, new string) func() {
t.Helper()
old, err := os.Getwd() old, err := os.Getwd()
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
@ -328,6 +356,8 @@ func testChdir(t *testing.T, new string) func() {
// testCwd is used to change the current working directory // testCwd is used to change the current working directory
// into a test directory that should be remoted after // into a test directory that should be remoted after
func testCwd(t *testing.T) (string, string) { func testCwd(t *testing.T) (string, string) {
t.Helper()
tmp, err := ioutil.TempDir("", "tf") tmp, err := ioutil.TempDir("", "tf")
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
@ -347,6 +377,8 @@ func testCwd(t *testing.T) (string, string) {
// testFixCwd is used to as a defer to testDir // testFixCwd is used to as a defer to testDir
func testFixCwd(t *testing.T, tmp, cwd string) { func testFixCwd(t *testing.T, tmp, cwd string) {
t.Helper()
if err := os.Chdir(cwd); err != nil { if err := os.Chdir(cwd); err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
@ -362,6 +394,8 @@ func testFixCwd(t *testing.T, tmp, cwd string) {
// The returned function should be deferred to properly clean up and restore // The returned function should be deferred to properly clean up and restore
// the original stdin. // the original stdin.
func testStdinPipe(t *testing.T, src io.Reader) func() { func testStdinPipe(t *testing.T, src io.Reader) func() {
t.Helper()
r, w, err := os.Pipe() r, w, err := os.Pipe()
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
@ -390,6 +424,8 @@ func testStdinPipe(t *testing.T, src io.Reader) func() {
// not useful since the commands are configured to write to a cli.Ui, not // not useful since the commands are configured to write to a cli.Ui, not
// Stdout directly. Commands like `console` though use the raw stdout. // Stdout directly. Commands like `console` though use the raw stdout.
func testStdoutCapture(t *testing.T, dst io.Writer) func() { func testStdoutCapture(t *testing.T, dst io.Writer) func() {
t.Helper()
r, w, err := os.Pipe() r, w, err := os.Pipe()
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
@ -424,6 +460,8 @@ func testStdoutCapture(t *testing.T, dst io.Writer) func() {
// in order to interactive prompts. The returned function must be called // in order to interactive prompts. The returned function must be called
// in a defer to clean up. // in a defer to clean up.
func testInteractiveInput(t *testing.T, answers []string) func() { func testInteractiveInput(t *testing.T, answers []string) func() {
t.Helper()
// Disable test mode so input is called // Disable test mode so input is called
test = false test = false
@ -443,6 +481,8 @@ func testInteractiveInput(t *testing.T, answers []string) func() {
// for calls to Input when the right question is asked. The key is the // for calls to Input when the right question is asked. The key is the
// question "Id" that is used. // question "Id" that is used.
func testInputMap(t *testing.T, answers map[string]string) func() { func testInputMap(t *testing.T, answers map[string]string) func() {
t.Helper()
// Disable test mode so input is called // Disable test mode so input is called
test = false test = false
@ -465,6 +505,8 @@ func testInputMap(t *testing.T, answers map[string]string) func() {
// backend. This returns the complete state that can be saved. Use // backend. This returns the complete state that can be saved. Use
// `testStateFileRemote` to write the returned state. // `testStateFileRemote` to write the returned state.
func testBackendState(t *testing.T, s *terraform.State, c int) (*terraform.State, *httptest.Server) { func testBackendState(t *testing.T, s *terraform.State, c int) (*terraform.State, *httptest.Server) {
t.Helper()
var b64md5 string var b64md5 string
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
@ -507,6 +549,8 @@ func testBackendState(t *testing.T, s *terraform.State, c int) (*terraform.State
// testRemoteState is used to make a test HTTP server to return a given // testRemoteState is used to make a test HTTP server to return a given
// state file that can be used for testing legacy remote state. // state file that can be used for testing legacy remote state.
func testRemoteState(t *testing.T, s *terraform.State, c int) (*terraform.RemoteState, *httptest.Server) { func testRemoteState(t *testing.T, s *terraform.State, c int) (*terraform.RemoteState, *httptest.Server) {
t.Helper()
var b64md5 string var b64md5 string
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)

View File

@ -51,6 +51,8 @@ func canAccessNetwork() bool {
} }
func skipIfCannotAccessNetwork(t *testing.T) { func skipIfCannotAccessNetwork(t *testing.T) {
t.Helper()
if !canAccessNetwork() { if !canAccessNetwork() {
t.Skip("network access not allowed; use TF_ACC=1 to enable") t.Skip("network access not allowed; use TF_ACC=1 to enable")
} }

View File

@ -6,6 +6,8 @@ import (
// TestRawConfig is used to create a RawConfig for testing. // TestRawConfig is used to create a RawConfig for testing.
func TestRawConfig(t *testing.T, c map[string]interface{}) *RawConfig { func TestRawConfig(t *testing.T, c map[string]interface{}) *RawConfig {
t.Helper()
cfg, err := NewRawConfig(c) cfg, err := NewRawConfig(c)
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)

View File

@ -10,6 +10,8 @@ import (
// TestResourceDataRaw creates a ResourceData from a raw configuration map. // TestResourceDataRaw creates a ResourceData from a raw configuration map.
func TestResourceDataRaw( func TestResourceDataRaw(
t *testing.T, schema map[string]*Schema, raw map[string]interface{}) *ResourceData { t *testing.T, schema map[string]*Schema, raw map[string]interface{}) *ResourceData {
t.Helper()
c, err := config.NewRawConfig(raw) c, err := config.NewRawConfig(raw)
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)

View File

@ -11,6 +11,8 @@ import (
// that the given implementation is pre-loaded with the TestStateInitial // that the given implementation is pre-loaded with the TestStateInitial
// state. // state.
func TestState(t *testing.T, s State) { func TestState(t *testing.T, s State) {
t.Helper()
if err := s.RefreshState(); err != nil { if err := s.RefreshState(); err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }

View File

@ -48,6 +48,8 @@ func TestMain(m *testing.M) {
} }
func tempDir(t *testing.T) string { func tempDir(t *testing.T) string {
t.Helper()
dir, err := ioutil.TempDir("", "tf") dir, err := ioutil.TempDir("", "tf")
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
@ -63,6 +65,8 @@ func tempDir(t *testing.T) string {
// a function to defer to reset the old value. // a function to defer to reset the old value.
// the old value that should be set via a defer. // the old value that should be set via a defer.
func tempEnv(t *testing.T, k string, v string) func() { func tempEnv(t *testing.T, k string, v string) func() {
t.Helper()
old, oldOk := os.LookupEnv(k) old, oldOk := os.LookupEnv(k)
os.Setenv(k, v) os.Setenv(k, v)
return func() { return func() {
@ -75,6 +79,8 @@ func tempEnv(t *testing.T, k string, v string) func() {
} }
func testConfig(t *testing.T, name string) *config.Config { func testConfig(t *testing.T, name string) *config.Config {
t.Helper()
c, err := config.LoadFile(filepath.Join(fixtureDir, name, "main.tf")) c, err := config.LoadFile(filepath.Join(fixtureDir, name, "main.tf"))
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
@ -84,6 +90,8 @@ func testConfig(t *testing.T, name string) *config.Config {
} }
func testModule(t *testing.T, name string) *module.Tree { func testModule(t *testing.T, name string) *module.Tree {
t.Helper()
mod, err := module.NewTreeModule("", filepath.Join(fixtureDir, name)) mod, err := module.NewTreeModule("", filepath.Join(fixtureDir, name))
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
@ -100,6 +108,8 @@ func testModule(t *testing.T, name string) *module.Tree {
// testModuleInline takes a map of path -> config strings and yields a config // testModuleInline takes a map of path -> config strings and yields a config
// structure with those files loaded from disk // structure with those files loaded from disk
func testModuleInline(t *testing.T, config map[string]string) *module.Tree { func testModuleInline(t *testing.T, config map[string]string) *module.Tree {
t.Helper()
cfgPath, err := ioutil.TempDir("", "tf-test") cfgPath, err := ioutil.TempDir("", "tf-test")
if err != nil { if err != nil {
t.Errorf("Error creating temporary directory for config: %s", err) t.Errorf("Error creating temporary directory for config: %s", err)
@ -146,6 +156,8 @@ func testModuleInline(t *testing.T, config map[string]string) *module.Tree {
} }
func testStringMatch(t *testing.T, s fmt.Stringer, expected string) { func testStringMatch(t *testing.T, s fmt.Stringer, expected string) {
t.Helper()
actual := strings.TrimSpace(s.String()) actual := strings.TrimSpace(s.String())
expected = strings.TrimSpace(expected) expected = strings.TrimSpace(expected)
if actual != expected { if actual != expected {