github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/builtin/providers/test/resource_nested_set_test.go (about)

     1  package test
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"regexp"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/hashicorp/terraform/addrs"
    11  	"github.com/hashicorp/terraform/helper/resource"
    12  	"github.com/hashicorp/terraform/terraform"
    13  )
    14  
    15  func TestResourceNestedSet_basic(t *testing.T) {
    16  	resource.UnitTest(t, resource.TestCase{
    17  		Providers:    testAccProviders,
    18  		CheckDestroy: testAccCheckResourceDestroy,
    19  		Steps: []resource.TestStep{
    20  			resource.TestStep{
    21  				Config: strings.TrimSpace(`
    22  resource "test_resource_nested_set" "foo" {
    23  	single {
    24  		value = "bar"
    25  	}
    26  }
    27  				`),
    28  			},
    29  		},
    30  	})
    31  }
    32  
    33  func TestResourceNestedSet_basicImport(t *testing.T) {
    34  	resource.UnitTest(t, resource.TestCase{
    35  		Providers:    testAccProviders,
    36  		CheckDestroy: testAccCheckResourceDestroy,
    37  		Steps: []resource.TestStep{
    38  			resource.TestStep{
    39  				Config: strings.TrimSpace(`
    40  resource "test_resource_nested_set" "foo" {
    41  	single {
    42  		value = "bar"
    43  	}
    44  }
    45  				`),
    46  			},
    47  			resource.TestStep{
    48  				ImportState:  true,
    49  				ResourceName: "test_resource_nested_set.foo",
    50  				Config: strings.TrimSpace(`
    51  resource "test_resource_nested_set" "foo" {
    52  	single {
    53  		value = "bar"
    54  	}
    55  }
    56  				`),
    57  				ImportStateCheck: func(ss []*terraform.InstanceState) error {
    58  					for _, s := range ss {
    59  						if s.Attributes["multi.#"] != "0" ||
    60  							s.Attributes["single.#"] != "0" ||
    61  							s.Attributes["type_list.#"] != "0" ||
    62  							s.Attributes["with_list.#"] != "0" {
    63  							return fmt.Errorf("missing blocks in imported state:\n%s", s)
    64  						}
    65  					}
    66  					return nil
    67  				},
    68  			},
    69  		},
    70  	})
    71  }
    72  
    73  // The set should not be generated because of it's computed value
    74  func TestResourceNestedSet_noSet(t *testing.T) {
    75  	checkFunc := func(s *terraform.State) error {
    76  		root := s.ModuleByPath(addrs.RootModuleInstance)
    77  		res := root.Resources["test_resource_nested_set.foo"]
    78  		for k, v := range res.Primary.Attributes {
    79  			if strings.HasPrefix(k, "single") && k != "single.#" {
    80  				return fmt.Errorf("unexpected set value: %s:%s", k, v)
    81  			}
    82  		}
    83  		return nil
    84  	}
    85  	resource.UnitTest(t, resource.TestCase{
    86  		Providers:    testAccProviders,
    87  		CheckDestroy: testAccCheckResourceDestroy,
    88  		Steps: []resource.TestStep{
    89  			resource.TestStep{
    90  				Config: strings.TrimSpace(`
    91  resource "test_resource_nested_set" "foo" {
    92  }
    93  				`),
    94  				Check: checkFunc,
    95  			},
    96  		},
    97  	})
    98  }
    99  
   100  // the empty type_list must be passed to the provider with 1 nil element
   101  func TestResourceNestedSet_emptyBlock(t *testing.T) {
   102  	resource.UnitTest(t, resource.TestCase{
   103  		Providers:    testAccProviders,
   104  		CheckDestroy: testAccCheckResourceDestroy,
   105  		Steps: []resource.TestStep{
   106  			resource.TestStep{
   107  				Config: strings.TrimSpace(`
   108  resource "test_resource_nested_set" "foo" {
   109  	type_list {
   110  	}
   111  }
   112  				`),
   113  				Check: resource.ComposeTestCheckFunc(
   114  					resource.TestCheckResourceAttr("test_resource_nested_set.foo", "type_list.#", "1"),
   115  				),
   116  			},
   117  		},
   118  	})
   119  }
   120  
   121  func TestResourceNestedSet_emptyNestedListBlock(t *testing.T) {
   122  	checkFunc := func(s *terraform.State) error {
   123  		root := s.ModuleByPath(addrs.RootModuleInstance)
   124  		res := root.Resources["test_resource_nested_set.foo"]
   125  		found := false
   126  		for k := range res.Primary.Attributes {
   127  			if !regexp.MustCompile(`^with_list\.\d+\.list_block\.`).MatchString(k) {
   128  				continue
   129  			}
   130  			found = true
   131  		}
   132  		if !found {
   133  			return fmt.Errorf("with_list.X.list_block not found")
   134  		}
   135  		return nil
   136  	}
   137  	resource.UnitTest(t, resource.TestCase{
   138  		Providers:    testAccProviders,
   139  		CheckDestroy: testAccCheckResourceDestroy,
   140  		Steps: []resource.TestStep{
   141  			resource.TestStep{
   142  				Config: strings.TrimSpace(`
   143  resource "test_resource_nested_set" "foo" {
   144  	with_list {
   145  		required = "ok"
   146  		list_block {
   147  		}
   148  	}
   149  }
   150  				`),
   151  				Check: checkFunc,
   152  			},
   153  		},
   154  	})
   155  }
   156  func TestResourceNestedSet_emptyNestedList(t *testing.T) {
   157  	checkFunc := func(s *terraform.State) error {
   158  		root := s.ModuleByPath(addrs.RootModuleInstance)
   159  		res := root.Resources["test_resource_nested_set.foo"]
   160  		found := false
   161  		for k, v := range res.Primary.Attributes {
   162  			if regexp.MustCompile(`^with_list\.\d+\.list\.#$`).MatchString(k) {
   163  				found = true
   164  				if v != "0" {
   165  					return fmt.Errorf("expected empty list: %s, got %s", k, v)
   166  				}
   167  				break
   168  			}
   169  		}
   170  		if !found {
   171  			return fmt.Errorf("with_list.X.nested_list not found")
   172  		}
   173  		return nil
   174  	}
   175  	resource.UnitTest(t, resource.TestCase{
   176  		Providers:    testAccProviders,
   177  		CheckDestroy: testAccCheckResourceDestroy,
   178  		Steps: []resource.TestStep{
   179  			resource.TestStep{
   180  				Config: strings.TrimSpace(`
   181  resource "test_resource_nested_set" "foo" {
   182  	with_list {
   183  		required = "ok"
   184  		list = []
   185  	}
   186  }
   187  				`),
   188  				Check: checkFunc,
   189  			},
   190  		},
   191  	})
   192  }
   193  
   194  func TestResourceNestedSet_addRemove(t *testing.T) {
   195  	var id string
   196  	checkFunc := func(s *terraform.State) error {
   197  		root := s.ModuleByPath(addrs.RootModuleInstance)
   198  		res := root.Resources["test_resource_nested_set.foo"]
   199  		if res.Primary.ID == id {
   200  			return errors.New("expected new resource")
   201  		}
   202  		id = res.Primary.ID
   203  		return nil
   204  	}
   205  	resource.UnitTest(t, resource.TestCase{
   206  		Providers:    testAccProviders,
   207  		CheckDestroy: testAccCheckResourceDestroy,
   208  		Steps: []resource.TestStep{
   209  			resource.TestStep{
   210  				Config: strings.TrimSpace(`
   211  resource "test_resource_nested_set" "foo" {
   212  }
   213  				`),
   214  				Check: checkFunc,
   215  			},
   216  			resource.TestStep{
   217  				Config: strings.TrimSpace(`
   218  resource "test_resource_nested_set" "foo" {
   219  	single {
   220  		value = "bar"
   221  	}
   222  }
   223  				`),
   224  				Check: resource.ComposeTestCheckFunc(
   225  					checkFunc,
   226  					resource.TestCheckResourceAttr(
   227  						"test_resource_nested_set.foo", "single.#", "1",
   228  					),
   229  					// the hash of single seems to change here, so we're not
   230  					// going to test for "value" directly
   231  					// FIXME: figure out why the set hash changes
   232  				),
   233  			},
   234  			resource.TestStep{
   235  				Config: strings.TrimSpace(`
   236  resource "test_resource_nested_set" "foo" {
   237  }
   238  				`),
   239  				Check: resource.ComposeTestCheckFunc(
   240  					resource.TestCheckResourceAttr(
   241  						"test_resource_nested_set.foo", "single.#", "0",
   242  					),
   243  					checkFunc,
   244  				),
   245  			},
   246  			resource.TestStep{
   247  				Config: strings.TrimSpace(`
   248  resource "test_resource_nested_set" "foo" {
   249  	single {
   250  		value = "bar"
   251  	}
   252  }
   253  				`),
   254  				Check: checkFunc,
   255  			},
   256  			resource.TestStep{
   257  				Config: strings.TrimSpace(`
   258  resource "test_resource_nested_set" "foo" {
   259  	single {
   260  		value = "bar"
   261  		optional = "baz"
   262  	}
   263  }
   264  				`),
   265  				Check: checkFunc,
   266  			},
   267  
   268  			resource.TestStep{
   269  				Config: strings.TrimSpace(`
   270  resource "test_resource_nested_set" "foo" {
   271  }
   272  			   	`),
   273  				Check: checkFunc,
   274  			},
   275  		},
   276  	})
   277  }
   278  func TestResourceNestedSet_multiAddRemove(t *testing.T) {
   279  	checkFunc := func(s *terraform.State) error {
   280  		return nil
   281  	}
   282  	resource.UnitTest(t, resource.TestCase{
   283  		Providers:    testAccProviders,
   284  		CheckDestroy: testAccCheckResourceDestroy,
   285  		Steps: []resource.TestStep{
   286  			resource.TestStep{
   287  				Config: strings.TrimSpace(`
   288  resource "test_resource_nested_set" "foo" {
   289  }
   290  				`),
   291  				Check: checkFunc,
   292  			},
   293  			resource.TestStep{
   294  				Config: strings.TrimSpace(`
   295  resource "test_resource_nested_set" "foo" {
   296  	multi {
   297  		optional = "bar"
   298  	}
   299  }
   300  				`),
   301  				Check: checkFunc,
   302  			},
   303  
   304  			resource.TestStep{
   305  				Config: strings.TrimSpace(`
   306  resource "test_resource_nested_set" "foo" {
   307  }
   308  								`),
   309  				Check: checkFunc,
   310  			},
   311  
   312  			resource.TestStep{
   313  				Config: strings.TrimSpace(`
   314  resource "test_resource_nested_set" "foo" {
   315  	multi {
   316  		set {
   317  			required = "val"
   318  		}
   319  	}
   320  }
   321  				`),
   322  				Check: checkFunc,
   323  			},
   324  
   325  			resource.TestStep{
   326  				Config: strings.TrimSpace(`
   327  resource "test_resource_nested_set" "foo" {
   328  	multi {
   329  		set {
   330  			required = "new"
   331  		}
   332  	}
   333  }
   334  				`),
   335  				Check: checkFunc,
   336  			},
   337  
   338  			resource.TestStep{
   339  				Config: strings.TrimSpace(`
   340  resource "test_resource_nested_set" "foo" {
   341  	multi {
   342  		set {
   343  			required = "new"
   344  			optional_int = 3
   345  		}
   346  	}
   347  }
   348  				`),
   349  				Check: checkFunc,
   350  			},
   351  
   352  			resource.TestStep{
   353  				Config: strings.TrimSpace(`
   354  resource "test_resource_nested_set" "foo" {
   355  	single {
   356  		value = "bar"
   357  		optional = "baz"
   358  	}
   359  	multi {
   360  		set {
   361  			required = "new"
   362  			optional_int = 3
   363  		}
   364  	}
   365  }
   366  			`),
   367  				Check: checkFunc,
   368  			},
   369  
   370  			resource.TestStep{
   371  				Config: strings.TrimSpace(`
   372  resource "test_resource_nested_set" "foo" {
   373  	optional = true
   374  	single {
   375  		value = "bar"
   376  		optional = "baz"
   377  	}
   378  	multi {
   379  		set {
   380  			required = "new"
   381  			optional_int = 3
   382  		}
   383  	}
   384  }
   385  			`),
   386  				Check: checkFunc,
   387  			},
   388  		},
   389  	})
   390  }
   391  
   392  func TestResourceNestedSet_forceNewEmptyString(t *testing.T) {
   393  	var id string
   394  	step := 0
   395  	checkFunc := func(s *terraform.State) error {
   396  		root := s.ModuleByPath(addrs.RootModuleInstance)
   397  		res := root.Resources["test_resource_nested_set.foo"]
   398  		defer func() {
   399  			step++
   400  			id = res.Primary.ID
   401  		}()
   402  
   403  		if step == 2 && res.Primary.ID == id {
   404  			// setting an empty string currently does not trigger ForceNew, but
   405  			// it should in the future.
   406  			return nil
   407  		}
   408  
   409  		if res.Primary.ID == id {
   410  			return errors.New("expected new resource")
   411  		}
   412  
   413  		return nil
   414  	}
   415  	resource.UnitTest(t, resource.TestCase{
   416  		Providers:    testAccProviders,
   417  		CheckDestroy: testAccCheckResourceDestroy,
   418  		Steps: []resource.TestStep{
   419  			resource.TestStep{
   420  				Config: strings.TrimSpace(`
   421  resource "test_resource_nested_set" "foo" {
   422  	multi {
   423  		set {
   424  			required = "val"
   425  		}
   426  	}
   427  }
   428  				`),
   429  				Check: checkFunc,
   430  			},
   431  
   432  			resource.TestStep{
   433  				Config: strings.TrimSpace(`
   434  resource "test_resource_nested_set" "foo" {
   435  	multi {
   436  		set {
   437  			required = ""
   438  		}
   439  	}
   440  }
   441  				`),
   442  				Check: checkFunc,
   443  			},
   444  
   445  			resource.TestStep{
   446  				Config: strings.TrimSpace(`
   447  resource "test_resource_nested_set" "foo" {
   448  	force_new = ""
   449  }
   450  				`),
   451  				Check: checkFunc,
   452  			},
   453  		},
   454  	})
   455  }
   456  
   457  func TestResourceNestedSet_setWithList(t *testing.T) {
   458  	checkFunc := func(s *terraform.State) error {
   459  		return nil
   460  	}
   461  	resource.UnitTest(t, resource.TestCase{
   462  		Providers:    testAccProviders,
   463  		CheckDestroy: testAccCheckResourceDestroy,
   464  		Steps: []resource.TestStep{
   465  			resource.TestStep{
   466  				Config: strings.TrimSpace(`
   467  resource "test_resource_nested_set" "foo" {
   468  	with_list {
   469  		required = "bar"
   470  		list = ["initial value"]
   471  	}
   472  }
   473  				`),
   474  				Check: checkFunc,
   475  			},
   476  			resource.TestStep{
   477  				Config: strings.TrimSpace(`
   478  resource "test_resource_nested_set" "foo" {
   479  	with_list {
   480  		required = "bar"
   481  		list = ["second value"]
   482  	}
   483  }
   484  				`),
   485  				Check: checkFunc,
   486  			},
   487  		},
   488  	})
   489  }
   490  
   491  // This is the same as forceNewEmptyString, but we start with the empty value,
   492  // instead of changing it.
   493  func TestResourceNestedSet_nestedSetEmptyString(t *testing.T) {
   494  	resource.UnitTest(t, resource.TestCase{
   495  		Providers:    testAccProviders,
   496  		CheckDestroy: testAccCheckResourceDestroy,
   497  		Steps: []resource.TestStep{
   498  			resource.TestStep{
   499  				Config: strings.TrimSpace(`
   500  resource "test_resource_nested_set" "foo" {
   501  	multi {
   502  		set {
   503  			required = ""
   504  		}
   505  	}
   506  }
   507  				`),
   508  				Check: resource.ComposeTestCheckFunc(
   509  					resource.TestCheckResourceAttr(
   510  						"test_resource_nested_set.foo", "multi.529860700.set.4196279896.required", "",
   511  					),
   512  				),
   513  			},
   514  		},
   515  	})
   516  }
   517  
   518  func TestResourceNestedSet_emptySet(t *testing.T) {
   519  	resource.UnitTest(t, resource.TestCase{
   520  		Providers:    testAccProviders,
   521  		CheckDestroy: testAccCheckResourceDestroy,
   522  		Steps: []resource.TestStep{
   523  			resource.TestStep{
   524  				Config: strings.TrimSpace(`
   525  resource "test_resource_nested_set" "foo" {
   526  	multi {
   527  	}
   528  }
   529  				`),
   530  				Check: resource.ComposeTestCheckFunc(
   531  					resource.TestCheckResourceAttr(
   532  						"test_resource_nested_set.foo", "multi.#", "1",
   533  					),
   534  				),
   535  			},
   536  		},
   537  	})
   538  }
   539  
   540  func TestResourceNestedSet_multipleUnknownSetElements(t *testing.T) {
   541  	checkFunc := func(s *terraform.State) error {
   542  		return nil
   543  	}
   544  	resource.UnitTest(t, resource.TestCase{
   545  		Providers:    testAccProviders,
   546  		CheckDestroy: testAccCheckResourceDestroy,
   547  		Steps: []resource.TestStep{
   548  			resource.TestStep{
   549  				Config: strings.TrimSpace(`
   550  resource "test_resource_nested_set" "a" {
   551  }
   552  
   553  resource "test_resource_nested_set" "b" {
   554  }
   555  
   556  resource "test_resource_nested_set" "c" {
   557  	multi {
   558  		optional = test_resource_nested_set.a.id
   559  	}
   560  	multi {
   561  		optional = test_resource_nested_set.b.id
   562  	}
   563  }
   564  				`),
   565  				Check: checkFunc,
   566  			},
   567  		},
   568  	})
   569  }
   570  
   571  func TestResourceNestedSet_interpolationChanges(t *testing.T) {
   572  	resource.UnitTest(t, resource.TestCase{
   573  		Providers:    testAccProviders,
   574  		CheckDestroy: testAccCheckResourceDestroy,
   575  		Steps: []resource.TestStep{
   576  			resource.TestStep{
   577  				Config: strings.TrimSpace(`
   578  resource "test_resource_nested_set" "foo" {
   579  	single {
   580  		value = "x"
   581  	}
   582  }
   583  resource "test_resource_nested_set" "bar" {
   584  	single {
   585  		value = test_resource_nested_set.foo.id
   586  	}
   587  }
   588  				`),
   589  				Check: resource.ComposeTestCheckFunc(
   590  					resource.TestCheckResourceAttr(
   591  						"test_resource_nested_set.foo", "single.#", "1",
   592  					),
   593  					resource.TestCheckResourceAttr(
   594  						"test_resource_nested_set.bar", "single.#", "1",
   595  					),
   596  				),
   597  			},
   598  			resource.TestStep{
   599  				Config: strings.TrimSpace(`
   600  resource "test_resource_nested_set" "baz" {
   601  	single {
   602  		value = "x"
   603  	}
   604  }
   605  resource "test_resource_nested_set" "bar" {
   606  	single {
   607  		value = test_resource_nested_set.baz.id
   608  	}
   609  }
   610  				`),
   611  				Check: resource.ComposeTestCheckFunc(
   612  					resource.TestCheckResourceAttr(
   613  						"test_resource_nested_set.baz", "single.#", "1",
   614  					),
   615  					resource.TestCheckResourceAttr(
   616  						"test_resource_nested_set.bar", "single.#", "1",
   617  					),
   618  				),
   619  			},
   620  		},
   621  	})
   622  }
   623  
   624  func TestResourceNestedSet_dynamicSetBlock(t *testing.T) {
   625  	resource.UnitTest(t, resource.TestCase{
   626  		Providers:    testAccProviders,
   627  		CheckDestroy: testAccCheckResourceDestroy,
   628  		Steps: []resource.TestStep{
   629  			resource.TestStep{
   630  				Config: strings.TrimSpace(`
   631  resource "test_resource" "a" {
   632  	required = "ok"
   633  	required_map = {
   634  		a = "b"
   635  	}
   636  }
   637  
   638  resource "test_resource_nested_set" "foo" {
   639    dynamic "with_list" {
   640      iterator = thing
   641  	for_each = test_resource.a.computed_list
   642      content {
   643        required = thing.value
   644  	  list = [thing.key]
   645      }
   646    }
   647  }
   648  				`),
   649  				Check: resource.ComposeTestCheckFunc(),
   650  			},
   651  		},
   652  	})
   653  }