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