]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/terraform/provider_mock.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / provider_mock.go
1 package terraform
2
3 import (
4 "encoding/json"
5 "fmt"
6 "sync"
7
8 "github.com/zclconf/go-cty/cty"
9 ctyjson "github.com/zclconf/go-cty/cty/json"
10
11 "github.com/hashicorp/terraform/config"
12 "github.com/hashicorp/terraform/config/hcl2shim"
13 "github.com/hashicorp/terraform/providers"
14 "github.com/hashicorp/terraform/tfdiags"
15 )
16
17 var _ providers.Interface = (*MockProvider)(nil)
18
19 // MockProvider implements providers.Interface but mocks out all the
20 // calls for testing purposes.
21 type MockProvider struct {
22 sync.Mutex
23
24 // Anything you want, in case you need to store extra data with the mock.
25 Meta interface{}
26
27 GetSchemaCalled bool
28 GetSchemaReturn *ProviderSchema // This is using ProviderSchema directly rather than providers.GetSchemaResponse for compatibility with old tests
29
30 PrepareProviderConfigCalled bool
31 PrepareProviderConfigResponse providers.PrepareProviderConfigResponse
32 PrepareProviderConfigRequest providers.PrepareProviderConfigRequest
33 PrepareProviderConfigFn func(providers.PrepareProviderConfigRequest) providers.PrepareProviderConfigResponse
34
35 ValidateResourceTypeConfigCalled bool
36 ValidateResourceTypeConfigTypeName string
37 ValidateResourceTypeConfigResponse providers.ValidateResourceTypeConfigResponse
38 ValidateResourceTypeConfigRequest providers.ValidateResourceTypeConfigRequest
39 ValidateResourceTypeConfigFn func(providers.ValidateResourceTypeConfigRequest) providers.ValidateResourceTypeConfigResponse
40
41 ValidateDataSourceConfigCalled bool
42 ValidateDataSourceConfigTypeName string
43 ValidateDataSourceConfigResponse providers.ValidateDataSourceConfigResponse
44 ValidateDataSourceConfigRequest providers.ValidateDataSourceConfigRequest
45 ValidateDataSourceConfigFn func(providers.ValidateDataSourceConfigRequest) providers.ValidateDataSourceConfigResponse
46
47 UpgradeResourceStateCalled bool
48 UpgradeResourceStateTypeName string
49 UpgradeResourceStateResponse providers.UpgradeResourceStateResponse
50 UpgradeResourceStateRequest providers.UpgradeResourceStateRequest
51 UpgradeResourceStateFn func(providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse
52
53 ConfigureCalled bool
54 ConfigureResponse providers.ConfigureResponse
55 ConfigureRequest providers.ConfigureRequest
56 ConfigureNewFn func(providers.ConfigureRequest) providers.ConfigureResponse // Named ConfigureNewFn so we can still have the legacy ConfigureFn declared below
57
58 StopCalled bool
59 StopFn func() error
60 StopResponse error
61
62 ReadResourceCalled bool
63 ReadResourceResponse providers.ReadResourceResponse
64 ReadResourceRequest providers.ReadResourceRequest
65 ReadResourceFn func(providers.ReadResourceRequest) providers.ReadResourceResponse
66
67 PlanResourceChangeCalled bool
68 PlanResourceChangeResponse providers.PlanResourceChangeResponse
69 PlanResourceChangeRequest providers.PlanResourceChangeRequest
70 PlanResourceChangeFn func(providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse
71
72 ApplyResourceChangeCalled bool
73 ApplyResourceChangeResponse providers.ApplyResourceChangeResponse
74 ApplyResourceChangeRequest providers.ApplyResourceChangeRequest
75 ApplyResourceChangeFn func(providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse
76
77 ImportResourceStateCalled bool
78 ImportResourceStateResponse providers.ImportResourceStateResponse
79 ImportResourceStateRequest providers.ImportResourceStateRequest
80 ImportResourceStateFn func(providers.ImportResourceStateRequest) providers.ImportResourceStateResponse
81 // Legacy return type for existing tests, which will be shimmed into an
82 // ImportResourceStateResponse if set
83 ImportStateReturn []*InstanceState
84
85 ReadDataSourceCalled bool
86 ReadDataSourceResponse providers.ReadDataSourceResponse
87 ReadDataSourceRequest providers.ReadDataSourceRequest
88 ReadDataSourceFn func(providers.ReadDataSourceRequest) providers.ReadDataSourceResponse
89
90 CloseCalled bool
91 CloseError error
92
93 // Legacy callbacks: if these are set, we will shim incoming calls for
94 // new-style methods to these old-fashioned terraform.ResourceProvider
95 // mock callbacks, for the benefit of older tests that were written against
96 // the old mock API.
97 ValidateFn func(c *ResourceConfig) (ws []string, es []error)
98 ConfigureFn func(c *ResourceConfig) error
99 DiffFn func(info *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error)
100 ApplyFn func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error)
101 }
102
103 func (p *MockProvider) GetSchema() providers.GetSchemaResponse {
104 p.Lock()
105 defer p.Unlock()
106 p.GetSchemaCalled = true
107 return p.getSchema()
108 }
109
110 func (p *MockProvider) getSchema() providers.GetSchemaResponse {
111 // This version of getSchema doesn't do any locking, so it's suitable to
112 // call from other methods of this mock as long as they are already
113 // holding the lock.
114
115 ret := providers.GetSchemaResponse{
116 Provider: providers.Schema{},
117 DataSources: map[string]providers.Schema{},
118 ResourceTypes: map[string]providers.Schema{},
119 }
120 if p.GetSchemaReturn != nil {
121 ret.Provider.Block = p.GetSchemaReturn.Provider
122 for n, s := range p.GetSchemaReturn.DataSources {
123 ret.DataSources[n] = providers.Schema{
124 Block: s,
125 }
126 }
127 for n, s := range p.GetSchemaReturn.ResourceTypes {
128 ret.ResourceTypes[n] = providers.Schema{
129 Version: int64(p.GetSchemaReturn.ResourceTypeSchemaVersions[n]),
130 Block: s,
131 }
132 }
133 }
134
135 return ret
136 }
137
138 func (p *MockProvider) PrepareProviderConfig(r providers.PrepareProviderConfigRequest) providers.PrepareProviderConfigResponse {
139 p.Lock()
140 defer p.Unlock()
141
142 p.PrepareProviderConfigCalled = true
143 p.PrepareProviderConfigRequest = r
144 if p.PrepareProviderConfigFn != nil {
145 return p.PrepareProviderConfigFn(r)
146 }
147 return p.PrepareProviderConfigResponse
148 }
149
150 func (p *MockProvider) ValidateResourceTypeConfig(r providers.ValidateResourceTypeConfigRequest) providers.ValidateResourceTypeConfigResponse {
151 p.Lock()
152 defer p.Unlock()
153
154 p.ValidateResourceTypeConfigCalled = true
155 p.ValidateResourceTypeConfigRequest = r
156
157 if p.ValidateFn != nil {
158 resp := p.getSchema()
159 schema := resp.Provider.Block
160 rc := NewResourceConfigShimmed(r.Config, schema)
161 warns, errs := p.ValidateFn(rc)
162 ret := providers.ValidateResourceTypeConfigResponse{}
163 for _, warn := range warns {
164 ret.Diagnostics = ret.Diagnostics.Append(tfdiags.SimpleWarning(warn))
165 }
166 for _, err := range errs {
167 ret.Diagnostics = ret.Diagnostics.Append(err)
168 }
169 }
170 if p.ValidateResourceTypeConfigFn != nil {
171 return p.ValidateResourceTypeConfigFn(r)
172 }
173
174 return p.ValidateResourceTypeConfigResponse
175 }
176
177 func (p *MockProvider) ValidateDataSourceConfig(r providers.ValidateDataSourceConfigRequest) providers.ValidateDataSourceConfigResponse {
178 p.Lock()
179 defer p.Unlock()
180
181 p.ValidateDataSourceConfigCalled = true
182 p.ValidateDataSourceConfigRequest = r
183
184 if p.ValidateDataSourceConfigFn != nil {
185 return p.ValidateDataSourceConfigFn(r)
186 }
187
188 return p.ValidateDataSourceConfigResponse
189 }
190
191 func (p *MockProvider) UpgradeResourceState(r providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse {
192 p.Lock()
193 defer p.Unlock()
194
195 schemas := p.getSchema()
196 schema := schemas.ResourceTypes[r.TypeName]
197 schemaType := schema.Block.ImpliedType()
198
199 p.UpgradeResourceStateCalled = true
200 p.UpgradeResourceStateRequest = r
201
202 if p.UpgradeResourceStateFn != nil {
203 return p.UpgradeResourceStateFn(r)
204 }
205
206 resp := p.UpgradeResourceStateResponse
207
208 if resp.UpgradedState == cty.NilVal {
209 switch {
210 case r.RawStateFlatmap != nil:
211 v, err := hcl2shim.HCL2ValueFromFlatmap(r.RawStateFlatmap, schemaType)
212 if err != nil {
213 resp.Diagnostics = resp.Diagnostics.Append(err)
214 return resp
215 }
216 resp.UpgradedState = v
217 case len(r.RawStateJSON) > 0:
218 v, err := ctyjson.Unmarshal(r.RawStateJSON, schemaType)
219
220 if err != nil {
221 resp.Diagnostics = resp.Diagnostics.Append(err)
222 return resp
223 }
224 resp.UpgradedState = v
225 }
226 }
227 return resp
228 }
229
230 func (p *MockProvider) Configure(r providers.ConfigureRequest) providers.ConfigureResponse {
231 p.Lock()
232 defer p.Unlock()
233
234 p.ConfigureCalled = true
235 p.ConfigureRequest = r
236
237 if p.ConfigureFn != nil {
238 resp := p.getSchema()
239 schema := resp.Provider.Block
240 rc := NewResourceConfigShimmed(r.Config, schema)
241 ret := providers.ConfigureResponse{}
242
243 err := p.ConfigureFn(rc)
244 if err != nil {
245 ret.Diagnostics = ret.Diagnostics.Append(err)
246 }
247 return ret
248 }
249 if p.ConfigureNewFn != nil {
250 return p.ConfigureNewFn(r)
251 }
252
253 return p.ConfigureResponse
254 }
255
256 func (p *MockProvider) Stop() error {
257 // We intentionally don't lock in this one because the whole point of this
258 // method is to be called concurrently with another operation that can
259 // be cancelled. The provider itself is responsible for handling
260 // any concurrency concerns in this case.
261
262 p.StopCalled = true
263 if p.StopFn != nil {
264 return p.StopFn()
265 }
266
267 return p.StopResponse
268 }
269
270 func (p *MockProvider) ReadResource(r providers.ReadResourceRequest) providers.ReadResourceResponse {
271 p.Lock()
272 defer p.Unlock()
273
274 p.ReadResourceCalled = true
275 p.ReadResourceRequest = r
276
277 if p.ReadResourceFn != nil {
278 return p.ReadResourceFn(r)
279 }
280
281 // make sure the NewState fits the schema
282 newState, err := p.GetSchemaReturn.ResourceTypes[r.TypeName].CoerceValue(p.ReadResourceResponse.NewState)
283 if err != nil {
284 panic(err)
285 }
286 resp := p.ReadResourceResponse
287 resp.NewState = newState
288
289 return resp
290 }
291
292 func (p *MockProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
293 p.Lock()
294 defer p.Unlock()
295
296 p.PlanResourceChangeCalled = true
297 p.PlanResourceChangeRequest = r
298
299 if p.DiffFn != nil {
300 ps := p.getSchema()
301 if ps.ResourceTypes == nil || ps.ResourceTypes[r.TypeName].Block == nil {
302 return providers.PlanResourceChangeResponse{
303 Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Printf("mock provider has no schema for resource type %s", r.TypeName)),
304 }
305 }
306 schema := ps.ResourceTypes[r.TypeName].Block
307 info := &InstanceInfo{
308 Type: r.TypeName,
309 }
310 priorState := NewInstanceStateShimmedFromValue(r.PriorState, 0)
311 cfg := NewResourceConfigShimmed(r.Config, schema)
312
313 legacyDiff, err := p.DiffFn(info, priorState, cfg)
314
315 var res providers.PlanResourceChangeResponse
316 res.PlannedState = r.ProposedNewState
317 if err != nil {
318 res.Diagnostics = res.Diagnostics.Append(err)
319 }
320 if legacyDiff != nil {
321 newVal, err := legacyDiff.ApplyToValue(r.PriorState, schema)
322 if err != nil {
323 res.Diagnostics = res.Diagnostics.Append(err)
324 }
325
326 res.PlannedState = newVal
327
328 var requiresNew []string
329 for attr, d := range legacyDiff.Attributes {
330 if d.RequiresNew {
331 requiresNew = append(requiresNew, attr)
332 }
333 }
334 requiresReplace, err := hcl2shim.RequiresReplace(requiresNew, schema.ImpliedType())
335 if err != nil {
336 res.Diagnostics = res.Diagnostics.Append(err)
337 }
338 res.RequiresReplace = requiresReplace
339 }
340 return res
341 }
342 if p.PlanResourceChangeFn != nil {
343 return p.PlanResourceChangeFn(r)
344 }
345
346 return p.PlanResourceChangeResponse
347 }
348
349 func (p *MockProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
350 p.Lock()
351 p.ApplyResourceChangeCalled = true
352 p.ApplyResourceChangeRequest = r
353 p.Unlock()
354
355 if p.ApplyFn != nil {
356 // ApplyFn is a special callback fashioned after our old provider
357 // interface, which expected to be given an actual diff rather than
358 // separate old/new values to apply. Therefore we need to approximate
359 // a diff here well enough that _most_ of our legacy ApplyFns in old
360 // tests still see the behavior they are expecting. New tests should
361 // not use this, and should instead use ApplyResourceChangeFn directly.
362 providerSchema := p.getSchema()
363 schema, ok := providerSchema.ResourceTypes[r.TypeName]
364 if !ok {
365 return providers.ApplyResourceChangeResponse{
366 Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("no mocked schema available for resource type %s", r.TypeName)),
367 }
368 }
369
370 info := &InstanceInfo{
371 Type: r.TypeName,
372 }
373
374 priorVal := r.PriorState
375 plannedVal := r.PlannedState
376 priorMap := hcl2shim.FlatmapValueFromHCL2(priorVal)
377 plannedMap := hcl2shim.FlatmapValueFromHCL2(plannedVal)
378 s := NewInstanceStateShimmedFromValue(priorVal, 0)
379 d := &InstanceDiff{
380 Attributes: make(map[string]*ResourceAttrDiff),
381 }
382 if plannedMap == nil { // destroying, then
383 d.Destroy = true
384 // Destroy diffs don't have any attribute diffs
385 } else {
386 if priorMap == nil { // creating, then
387 // We'll just make an empty prior map to make things easier below.
388 priorMap = make(map[string]string)
389 }
390
391 for k, new := range plannedMap {
392 old := priorMap[k]
393 newComputed := false
394 if new == config.UnknownVariableValue {
395 new = ""
396 newComputed = true
397 }
398 d.Attributes[k] = &ResourceAttrDiff{
399 Old: old,
400 New: new,
401 NewComputed: newComputed,
402 Type: DiffAttrInput, // not generally used in tests, so just hard-coded
403 }
404 }
405 // Also need any attributes that were removed in "planned"
406 for k, old := range priorMap {
407 if _, ok := plannedMap[k]; ok {
408 continue
409 }
410 d.Attributes[k] = &ResourceAttrDiff{
411 Old: old,
412 NewRemoved: true,
413 Type: DiffAttrInput,
414 }
415 }
416 }
417 newState, err := p.ApplyFn(info, s, d)
418 resp := providers.ApplyResourceChangeResponse{}
419 if err != nil {
420 resp.Diagnostics = resp.Diagnostics.Append(err)
421 }
422 if newState != nil {
423 var newVal cty.Value
424 if newState != nil {
425 var err error
426 newVal, err = newState.AttrsAsObjectValue(schema.Block.ImpliedType())
427 if err != nil {
428 resp.Diagnostics = resp.Diagnostics.Append(err)
429 }
430 } else {
431 // If apply returned a nil new state then that's the old way to
432 // indicate that the object was destroyed. Our new interface calls
433 // for that to be signalled as a null value.
434 newVal = cty.NullVal(schema.Block.ImpliedType())
435 }
436 resp.NewState = newVal
437 }
438
439 return resp
440 }
441 if p.ApplyResourceChangeFn != nil {
442 return p.ApplyResourceChangeFn(r)
443 }
444
445 return p.ApplyResourceChangeResponse
446 }
447
448 func (p *MockProvider) ImportResourceState(r providers.ImportResourceStateRequest) providers.ImportResourceStateResponse {
449 p.Lock()
450 defer p.Unlock()
451
452 if p.ImportStateReturn != nil {
453 for _, is := range p.ImportStateReturn {
454 if is.Attributes == nil {
455 is.Attributes = make(map[string]string)
456 }
457 is.Attributes["id"] = is.ID
458
459 typeName := is.Ephemeral.Type
460 // Use the requested type if the resource has no type of it's own.
461 // We still return the empty type, which will error, but this prevents a panic.
462 if typeName == "" {
463 typeName = r.TypeName
464 }
465
466 schema := p.GetSchemaReturn.ResourceTypes[typeName]
467 if schema == nil {
468 panic("no schema found for " + typeName)
469 }
470
471 private, err := json.Marshal(is.Meta)
472 if err != nil {
473 panic(err)
474 }
475
476 state, err := hcl2shim.HCL2ValueFromFlatmap(is.Attributes, schema.ImpliedType())
477 if err != nil {
478 panic(err)
479 }
480
481 state, err = schema.CoerceValue(state)
482 if err != nil {
483 panic(err)
484 }
485
486 p.ImportResourceStateResponse.ImportedResources = append(
487 p.ImportResourceStateResponse.ImportedResources,
488 providers.ImportedResource{
489 TypeName: is.Ephemeral.Type,
490 State: state,
491 Private: private,
492 })
493 }
494 }
495
496 p.ImportResourceStateCalled = true
497 p.ImportResourceStateRequest = r
498 if p.ImportResourceStateFn != nil {
499 return p.ImportResourceStateFn(r)
500 }
501
502 return p.ImportResourceStateResponse
503 }
504
505 func (p *MockProvider) ReadDataSource(r providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
506 p.Lock()
507 defer p.Unlock()
508
509 p.ReadDataSourceCalled = true
510 p.ReadDataSourceRequest = r
511
512 if p.ReadDataSourceFn != nil {
513 return p.ReadDataSourceFn(r)
514 }
515
516 return p.ReadDataSourceResponse
517 }
518
519 func (p *MockProvider) Close() error {
520 p.CloseCalled = true
521 return p.CloseError
522 }