github.com/rjeczalik/terraform@v0.6.7-0.20160812060014-e251d5c7bd39/helper/resource/testing_config.go (about) 1 package resource 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/hashicorp/terraform/terraform" 9 ) 10 11 // testStepConfig runs a config-mode test step 12 func testStepConfig( 13 opts terraform.ContextOpts, 14 state *terraform.State, 15 step TestStep) (*terraform.State, error) { 16 return testStep(opts, state, step) 17 } 18 19 func testStep( 20 opts terraform.ContextOpts, 21 state *terraform.State, 22 step TestStep) (*terraform.State, error) { 23 mod, err := testModule(opts, step) 24 if err != nil { 25 return state, err 26 } 27 28 // Build the context 29 opts.Module = mod 30 opts.State = state 31 opts.Destroy = step.Destroy 32 ctx, err := terraform.NewContext(&opts) 33 if err != nil { 34 return state, fmt.Errorf("Error initializing context: %s", err) 35 } 36 if ws, es := ctx.Validate(); len(ws) > 0 || len(es) > 0 { 37 if len(es) > 0 { 38 estrs := make([]string, len(es)) 39 for i, e := range es { 40 estrs[i] = e.Error() 41 } 42 return state, fmt.Errorf( 43 "Configuration is invalid.\n\nWarnings: %#v\n\nErrors: %#v", 44 ws, estrs) 45 } 46 log.Printf("[WARN] Config warnings: %#v", ws) 47 } 48 49 // Refresh! 50 state, err = ctx.Refresh() 51 if err != nil { 52 return state, fmt.Errorf( 53 "Error refreshing: %s", err) 54 } 55 56 // Plan! 57 if p, err := ctx.Plan(); err != nil { 58 return state, fmt.Errorf( 59 "Error planning: %s", err) 60 } else { 61 log.Printf("[WARN] Test: Step plan: %s", p) 62 } 63 64 // We need to keep a copy of the state prior to destroying 65 // such that destroy steps can verify their behaviour in the check 66 // function 67 stateBeforeApplication := state.DeepCopy() 68 69 // Apply! 70 state, err = ctx.Apply() 71 if err != nil { 72 return state, fmt.Errorf("Error applying: %s", err) 73 } 74 75 // Check! Excitement! 76 if step.Check != nil { 77 if step.Destroy { 78 if err := step.Check(stateBeforeApplication); err != nil { 79 return state, fmt.Errorf("Check failed: %s", err) 80 } 81 } else { 82 if err := step.Check(state); err != nil { 83 return state, fmt.Errorf("Check failed: %s", err) 84 } 85 } 86 } 87 88 // Now, verify that Plan is now empty and we don't have a perpetual diff issue 89 // We do this with TWO plans. One without a refresh. 90 var p *terraform.Plan 91 if p, err = ctx.Plan(); err != nil { 92 return state, fmt.Errorf("Error on follow-up plan: %s", err) 93 } 94 if p.Diff != nil && !p.Diff.Empty() { 95 if step.ExpectNonEmptyPlan { 96 log.Printf("[INFO] Got non-empty plan, as expected:\n\n%s", p) 97 } else { 98 return state, fmt.Errorf( 99 "After applying this step, the plan was not empty:\n\n%s", p) 100 } 101 } 102 103 // And another after a Refresh. 104 if !step.Destroy || (step.Destroy && !step.PreventPostDestroyRefresh) { 105 state, err = ctx.Refresh() 106 if err != nil { 107 return state, fmt.Errorf( 108 "Error on follow-up refresh: %s", err) 109 } 110 } 111 if p, err = ctx.Plan(); err != nil { 112 return state, fmt.Errorf("Error on second follow-up plan: %s", err) 113 } 114 empty := p.Diff == nil || p.Diff.Empty() 115 116 // Data resources are tricky because they legitimately get instantiated 117 // during refresh so that they will be already populated during the 118 // plan walk. Because of this, if we have any data resources in the 119 // config we'll end up wanting to destroy them again here. This is 120 // acceptable and expected, and we'll treat it as "empty" for the 121 // sake of this testing. 122 if step.Destroy { 123 empty = true 124 125 for _, moduleDiff := range p.Diff.Modules { 126 for k, instanceDiff := range moduleDiff.Resources { 127 if !strings.HasPrefix(k, "data.") { 128 empty = false 129 break 130 } 131 132 if !instanceDiff.Destroy { 133 empty = false 134 } 135 } 136 } 137 } 138 139 if !empty { 140 if step.ExpectNonEmptyPlan { 141 log.Printf("[INFO] Got non-empty plan, as expected:\n\n%s", p) 142 } else { 143 return state, fmt.Errorf( 144 "After applying this step and refreshing, "+ 145 "the plan was not empty:\n\n%s", p) 146 } 147 } 148 149 // Made it here, but expected a non-empty plan, fail! 150 if step.ExpectNonEmptyPlan && (p.Diff == nil || p.Diff.Empty()) { 151 return state, fmt.Errorf("Expected a non-empty plan, but got an empty plan!") 152 } 153 154 // Made it here? Good job test step! 155 return state, nil 156 }