github.com/dougneal/terraform@v0.6.15-0.20170330092735-b6a3840768a4/repl/session_test.go (about)

     1  package repl
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  
     7  	"github.com/hashicorp/terraform/config/module"
     8  	"github.com/hashicorp/terraform/terraform"
     9  )
    10  
    11  func TestSession_basicState(t *testing.T) {
    12  	state := &terraform.State{
    13  		Modules: []*terraform.ModuleState{
    14  			&terraform.ModuleState{
    15  				Path: []string{"root"},
    16  				Resources: map[string]*terraform.ResourceState{
    17  					"test_instance.foo": &terraform.ResourceState{
    18  						Type: "test_instance",
    19  						Primary: &terraform.InstanceState{
    20  							ID: "bar",
    21  							Attributes: map[string]string{
    22  								"id": "bar",
    23  							},
    24  						},
    25  					},
    26  				},
    27  			},
    28  
    29  			&terraform.ModuleState{
    30  				Path: []string{"root", "module"},
    31  				Resources: map[string]*terraform.ResourceState{
    32  					"test_instance.foo": &terraform.ResourceState{
    33  						Type: "test_instance",
    34  						Primary: &terraform.InstanceState{
    35  							ID: "bar",
    36  							Attributes: map[string]string{
    37  								"id": "bar",
    38  							},
    39  						},
    40  					},
    41  				},
    42  			},
    43  		},
    44  	}
    45  
    46  	t.Run("basic", func(t *testing.T) {
    47  		testSession(t, testSessionTest{
    48  			State: state,
    49  			Inputs: []testSessionInput{
    50  				{
    51  					Input:  "test_instance.foo.id",
    52  					Output: "bar",
    53  				},
    54  			},
    55  		})
    56  	})
    57  
    58  	t.Run("resource count", func(t *testing.T) {
    59  		testSession(t, testSessionTest{
    60  			State: state,
    61  			Inputs: []testSessionInput{
    62  				{
    63  					Input:  "test_instance.foo.count",
    64  					Output: "1",
    65  				},
    66  			},
    67  		})
    68  	})
    69  
    70  	t.Run("missing resource", func(t *testing.T) {
    71  		testSession(t, testSessionTest{
    72  			State: state,
    73  			Inputs: []testSessionInput{
    74  				{
    75  					Input:         "test_instance.bar.id",
    76  					Error:         true,
    77  					ErrorContains: "'test_instance.bar' not found",
    78  				},
    79  			},
    80  		})
    81  	})
    82  
    83  	t.Run("missing module", func(t *testing.T) {
    84  		testSession(t, testSessionTest{
    85  			State: state,
    86  			Inputs: []testSessionInput{
    87  				{
    88  					Input:         "module.child.foo",
    89  					Error:         true,
    90  					ErrorContains: "Couldn't find module \"child\"",
    91  				},
    92  			},
    93  		})
    94  	})
    95  
    96  	t.Run("missing module output", func(t *testing.T) {
    97  		testSession(t, testSessionTest{
    98  			State: state,
    99  			Inputs: []testSessionInput{
   100  				{
   101  					Input:         "module.module.foo",
   102  					Error:         true,
   103  					ErrorContains: "Couldn't find output \"foo\"",
   104  				},
   105  			},
   106  		})
   107  	})
   108  }
   109  
   110  func TestSession_stateless(t *testing.T) {
   111  	t.Run("exit", func(t *testing.T) {
   112  		testSession(t, testSessionTest{
   113  			Inputs: []testSessionInput{
   114  				{
   115  					Input:         "exit",
   116  					Error:         true,
   117  					ErrorContains: ErrSessionExit.Error(),
   118  				},
   119  			},
   120  		})
   121  	})
   122  
   123  	t.Run("help", func(t *testing.T) {
   124  		testSession(t, testSessionTest{
   125  			Inputs: []testSessionInput{
   126  				{
   127  					Input:          "help",
   128  					OutputContains: "allows you to",
   129  				},
   130  			},
   131  		})
   132  	})
   133  
   134  	t.Run("help with spaces", func(t *testing.T) {
   135  		testSession(t, testSessionTest{
   136  			Inputs: []testSessionInput{
   137  				{
   138  					Input:          "help   ",
   139  					OutputContains: "allows you to",
   140  				},
   141  			},
   142  		})
   143  	})
   144  
   145  	t.Run("basic math", func(t *testing.T) {
   146  		testSession(t, testSessionTest{
   147  			Inputs: []testSessionInput{
   148  				{
   149  					Input:  "1 + 5",
   150  					Output: "6",
   151  				},
   152  			},
   153  		})
   154  	})
   155  
   156  	t.Run("missing resource", func(t *testing.T) {
   157  		testSession(t, testSessionTest{
   158  			Inputs: []testSessionInput{
   159  				{
   160  					Input:         "test_instance.bar.id",
   161  					Error:         true,
   162  					ErrorContains: "'test_instance.bar' not found",
   163  				},
   164  			},
   165  		})
   166  	})
   167  }
   168  
   169  func testSession(t *testing.T, test testSessionTest) {
   170  	// Build the TF context
   171  	ctx, err := terraform.NewContext(&terraform.ContextOpts{
   172  		State:  test.State,
   173  		Module: module.NewEmptyTree(),
   174  	})
   175  	if err != nil {
   176  		t.Fatalf("err: %s", err)
   177  	}
   178  
   179  	// Build the session
   180  	s := &Session{
   181  		Interpolater: ctx.Interpolater(),
   182  	}
   183  
   184  	// Test the inputs. We purposely don't use subtests here because
   185  	// the inputs don't recognize subtests, but a sequence of stateful
   186  	// operations.
   187  	for _, input := range test.Inputs {
   188  		result, err := s.Handle(input.Input)
   189  		if (err != nil) != input.Error {
   190  			t.Fatalf("%q: err: %s", input.Input, err)
   191  		}
   192  		if err != nil {
   193  			if input.ErrorContains != "" {
   194  				if !strings.Contains(err.Error(), input.ErrorContains) {
   195  					t.Fatalf(
   196  						"%q: err should contain: %q\n\n%s",
   197  						input.Input, input.ErrorContains, err)
   198  				}
   199  			}
   200  
   201  			continue
   202  		}
   203  
   204  		if input.Output != "" && result != input.Output {
   205  			t.Fatalf(
   206  				"%q: expected:\n\n%s\n\ngot:\n\n%s",
   207  				input.Input, input.Output, result)
   208  		}
   209  
   210  		if input.OutputContains != "" && !strings.Contains(result, input.OutputContains) {
   211  			t.Fatalf(
   212  				"%q: expected contains:\n\n%s\n\ngot:\n\n%s",
   213  				input.Input, input.OutputContains, result)
   214  		}
   215  	}
   216  }
   217  
   218  type testSessionTest struct {
   219  	State  *terraform.State // State to use
   220  	Module string           // Module name in test-fixtures to load
   221  
   222  	// Inputs are the list of test inputs that are run in order.
   223  	// Each input can test the output of each step.
   224  	Inputs []testSessionInput
   225  }
   226  
   227  // testSessionInput is a single input to test for a session.
   228  type testSessionInput struct {
   229  	Input          string // Input string
   230  	Output         string // Exact output string to check
   231  	OutputContains string
   232  	Error          bool // Error is true if error is expected
   233  	ErrorContains  string
   234  }