github.com/Hashicorp/terraform@v0.11.12-beta1/helper/schema/provisioner_test.go (about)

     1  package schema
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"reflect"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/hashicorp/terraform/config"
    11  	"github.com/hashicorp/terraform/terraform"
    12  )
    13  
    14  func TestProvisioner_impl(t *testing.T) {
    15  	var _ terraform.ResourceProvisioner = new(Provisioner)
    16  }
    17  
    18  func noopApply(ctx context.Context) error {
    19  	return nil
    20  }
    21  
    22  func TestProvisionerValidate(t *testing.T) {
    23  	cases := []struct {
    24  		Name   string
    25  		P      *Provisioner
    26  		Config map[string]interface{}
    27  		Err    bool
    28  		Warns  []string
    29  	}{
    30  		{
    31  			Name:   "No ApplyFunc",
    32  			P:      &Provisioner{},
    33  			Config: nil,
    34  			Err:    true,
    35  		},
    36  		{
    37  			Name: "Incorrect schema",
    38  			P: &Provisioner{
    39  				Schema: map[string]*Schema{
    40  					"foo": {},
    41  				},
    42  				ApplyFunc: noopApply,
    43  			},
    44  			Config: nil,
    45  			Err:    true,
    46  		},
    47  		{
    48  			"Basic required field",
    49  			&Provisioner{
    50  				Schema: map[string]*Schema{
    51  					"foo": &Schema{
    52  						Required: true,
    53  						Type:     TypeString,
    54  					},
    55  				},
    56  				ApplyFunc: noopApply,
    57  			},
    58  			nil,
    59  			true,
    60  			nil,
    61  		},
    62  
    63  		{
    64  			"Basic required field set",
    65  			&Provisioner{
    66  				Schema: map[string]*Schema{
    67  					"foo": &Schema{
    68  						Required: true,
    69  						Type:     TypeString,
    70  					},
    71  				},
    72  				ApplyFunc: noopApply,
    73  			},
    74  			map[string]interface{}{
    75  				"foo": "bar",
    76  			},
    77  			false,
    78  			nil,
    79  		},
    80  		{
    81  			Name: "Warning from property validation",
    82  			P: &Provisioner{
    83  				Schema: map[string]*Schema{
    84  					"foo": {
    85  						Type:     TypeString,
    86  						Optional: true,
    87  						ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
    88  							ws = append(ws, "Simple warning from property validation")
    89  							return
    90  						},
    91  					},
    92  				},
    93  				ApplyFunc: noopApply,
    94  			},
    95  			Config: map[string]interface{}{
    96  				"foo": "",
    97  			},
    98  			Err:   false,
    99  			Warns: []string{"Simple warning from property validation"},
   100  		},
   101  		{
   102  			Name: "No schema",
   103  			P: &Provisioner{
   104  				Schema:    nil,
   105  				ApplyFunc: noopApply,
   106  			},
   107  			Config: nil,
   108  			Err:    false,
   109  		},
   110  		{
   111  			Name: "Warning from provisioner ValidateFunc",
   112  			P: &Provisioner{
   113  				Schema:    nil,
   114  				ApplyFunc: noopApply,
   115  				ValidateFunc: func(*terraform.ResourceConfig) (ws []string, errors []error) {
   116  					ws = append(ws, "Simple warning from provisioner ValidateFunc")
   117  					return
   118  				},
   119  			},
   120  			Config: nil,
   121  			Err:    false,
   122  			Warns:  []string{"Simple warning from provisioner ValidateFunc"},
   123  		},
   124  	}
   125  
   126  	for i, tc := range cases {
   127  		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
   128  			c, err := config.NewRawConfig(tc.Config)
   129  			if err != nil {
   130  				t.Fatalf("err: %s", err)
   131  			}
   132  
   133  			ws, es := tc.P.Validate(terraform.NewResourceConfig(c))
   134  			if len(es) > 0 != tc.Err {
   135  				t.Fatalf("%d: %#v %s", i, es, es)
   136  			}
   137  			if (tc.Warns != nil || len(ws) != 0) && !reflect.DeepEqual(ws, tc.Warns) {
   138  				t.Fatalf("%d: warnings mismatch, actual: %#v", i, ws)
   139  			}
   140  		})
   141  	}
   142  }
   143  
   144  func TestProvisionerApply(t *testing.T) {
   145  	cases := []struct {
   146  		Name   string
   147  		P      *Provisioner
   148  		Conn   map[string]string
   149  		Config map[string]interface{}
   150  		Err    bool
   151  	}{
   152  		{
   153  			"Basic config",
   154  			&Provisioner{
   155  				ConnSchema: map[string]*Schema{
   156  					"foo": &Schema{
   157  						Type:     TypeString,
   158  						Optional: true,
   159  					},
   160  				},
   161  
   162  				Schema: map[string]*Schema{
   163  					"foo": &Schema{
   164  						Type:     TypeInt,
   165  						Optional: true,
   166  					},
   167  				},
   168  
   169  				ApplyFunc: func(ctx context.Context) error {
   170  					cd := ctx.Value(ProvConnDataKey).(*ResourceData)
   171  					d := ctx.Value(ProvConfigDataKey).(*ResourceData)
   172  					if d.Get("foo").(int) != 42 {
   173  						return fmt.Errorf("bad config data")
   174  					}
   175  					if cd.Get("foo").(string) != "bar" {
   176  						return fmt.Errorf("bad conn data")
   177  					}
   178  
   179  					return nil
   180  				},
   181  			},
   182  			map[string]string{
   183  				"foo": "bar",
   184  			},
   185  			map[string]interface{}{
   186  				"foo": 42,
   187  			},
   188  			false,
   189  		},
   190  	}
   191  
   192  	for i, tc := range cases {
   193  		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
   194  			c, err := config.NewRawConfig(tc.Config)
   195  			if err != nil {
   196  				t.Fatalf("err: %s", err)
   197  			}
   198  
   199  			state := &terraform.InstanceState{
   200  				Ephemeral: terraform.EphemeralState{
   201  					ConnInfo: tc.Conn,
   202  				},
   203  			}
   204  
   205  			err = tc.P.Apply(
   206  				nil, state, terraform.NewResourceConfig(c))
   207  			if err != nil != tc.Err {
   208  				t.Fatalf("%d: %s", i, err)
   209  			}
   210  		})
   211  	}
   212  }
   213  
   214  func TestProvisionerApply_nilState(t *testing.T) {
   215  	p := &Provisioner{
   216  		ConnSchema: map[string]*Schema{
   217  			"foo": &Schema{
   218  				Type:     TypeString,
   219  				Optional: true,
   220  			},
   221  		},
   222  
   223  		Schema: map[string]*Schema{
   224  			"foo": &Schema{
   225  				Type:     TypeInt,
   226  				Optional: true,
   227  			},
   228  		},
   229  
   230  		ApplyFunc: func(ctx context.Context) error {
   231  			return nil
   232  		},
   233  	}
   234  
   235  	conf := map[string]interface{}{
   236  		"foo": 42,
   237  	}
   238  
   239  	c, err := config.NewRawConfig(conf)
   240  	if err != nil {
   241  		t.Fatalf("err: %s", err)
   242  	}
   243  
   244  	err = p.Apply(nil, nil, terraform.NewResourceConfig(c))
   245  	if err != nil {
   246  		t.Fatalf("err: %s", err)
   247  	}
   248  }
   249  
   250  func TestProvisionerStop(t *testing.T) {
   251  	var p Provisioner
   252  
   253  	// Verify stopch blocks
   254  	ch := p.StopContext().Done()
   255  	select {
   256  	case <-ch:
   257  		t.Fatal("should not be stopped")
   258  	case <-time.After(10 * time.Millisecond):
   259  	}
   260  
   261  	// Stop it
   262  	if err := p.Stop(); err != nil {
   263  		t.Fatalf("err: %s", err)
   264  	}
   265  
   266  	select {
   267  	case <-ch:
   268  	case <-time.After(10 * time.Millisecond):
   269  		t.Fatal("should be stopped")
   270  	}
   271  }
   272  
   273  func TestProvisionerStop_apply(t *testing.T) {
   274  	p := &Provisioner{
   275  		ConnSchema: map[string]*Schema{
   276  			"foo": &Schema{
   277  				Type:     TypeString,
   278  				Optional: true,
   279  			},
   280  		},
   281  
   282  		Schema: map[string]*Schema{
   283  			"foo": &Schema{
   284  				Type:     TypeInt,
   285  				Optional: true,
   286  			},
   287  		},
   288  
   289  		ApplyFunc: func(ctx context.Context) error {
   290  			<-ctx.Done()
   291  			return nil
   292  		},
   293  	}
   294  
   295  	conn := map[string]string{
   296  		"foo": "bar",
   297  	}
   298  
   299  	conf := map[string]interface{}{
   300  		"foo": 42,
   301  	}
   302  
   303  	c, err := config.NewRawConfig(conf)
   304  	if err != nil {
   305  		t.Fatalf("err: %s", err)
   306  	}
   307  
   308  	state := &terraform.InstanceState{
   309  		Ephemeral: terraform.EphemeralState{
   310  			ConnInfo: conn,
   311  		},
   312  	}
   313  
   314  	// Run the apply in a goroutine
   315  	doneCh := make(chan struct{})
   316  	go func() {
   317  		p.Apply(nil, state, terraform.NewResourceConfig(c))
   318  		close(doneCh)
   319  	}()
   320  
   321  	// Should block
   322  	select {
   323  	case <-doneCh:
   324  		t.Fatal("should not be done")
   325  	case <-time.After(10 * time.Millisecond):
   326  	}
   327  
   328  	// Stop!
   329  	p.Stop()
   330  
   331  	select {
   332  	case <-doneCh:
   333  	case <-time.After(10 * time.Millisecond):
   334  		t.Fatal("should be done")
   335  	}
   336  }
   337  
   338  func TestProvisionerStop_stopFirst(t *testing.T) {
   339  	var p Provisioner
   340  
   341  	// Stop it
   342  	if err := p.Stop(); err != nil {
   343  		t.Fatalf("err: %s", err)
   344  	}
   345  
   346  	select {
   347  	case <-p.StopContext().Done():
   348  	case <-time.After(10 * time.Millisecond):
   349  		t.Fatal("should be stopped")
   350  	}
   351  }