core: When planning to destroy an orphan instance, nil it in state

While we're planning we must always update the state with the proposed new
data resulting from the plan. In this case, we must record that the
orphan instance doesn't exist at all in the proposed new state by storing
its state as nil.

This in turn allows references to the containing resource to evaluate
properly, using the new updated resource count. This fixes
TestContext2Apply_multiVarCountDec.

This also includes a number of changes to the test output of
TestContext2Apply_multiVarCountDec that make it easier to debug failures.
This commit is contained in:
Martin Atkins 2018-05-31 15:52:57 -07:00
parent f7aa06726a
commit 26f76dd222
3 changed files with 26 additions and 7 deletions

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"log"
"reflect" "reflect"
"runtime" "runtime"
"sort" "sort"
@ -3772,16 +3773,18 @@ func TestContext2Apply_multiVarCountDec(t *testing.T) {
}, },
}) })
log.Print("\n========\nStep 1 Plan\n========")
if _, diags := ctx.Plan(); diags.HasErrors() { if _, diags := ctx.Plan(); diags.HasErrors() {
t.Fatalf("diags: %s", diags.Err()) t.Fatalf("diags: %s", diags.Err())
} }
log.Print("\n========\nStep 1 Apply\n========")
state, diags := ctx.Apply() state, diags := ctx.Apply()
if diags.HasErrors() { if diags.HasErrors() {
t.Fatalf("diags: %s", diags.Err()) t.Fatalf("diags: %s", diags.Err())
} }
t.Logf("Step 1 state: %s", state) t.Logf("Step 1 state:\n%s", state)
s = state s = state
} }
@ -3838,20 +3841,25 @@ func TestContext2Apply_multiVarCountDec(t *testing.T) {
}, },
}) })
if _, diags := ctx.Plan(); diags.HasErrors() { log.Print("\n========\nStep 2 Plan\n========")
t.Fatalf("diags: %s", diags.Err()) plan, diags := ctx.Plan()
if diags.HasErrors() {
t.Fatalf("plan errors: %s", diags.Err())
} }
t.Logf("Step 2 plan:\n%s", plan)
log.Print("\n========\nStep 2 Apply\n========")
state, diags := ctx.Apply() state, diags := ctx.Apply()
if diags.HasErrors() { if diags.HasErrors() {
t.Fatalf("diags: %s", diags.Err()) t.Fatalf("apply errors: %s", diags.Err())
} }
if !checked { if !checked {
t.Fatal("apply never called") t.Error("apply never called")
} }
t.Logf("Step 2 state: %s", state) t.Logf("Step 2 state:\n%s", state)
s = state s = state
} }

View File

@ -463,6 +463,11 @@ func (n *EvalDiffDestroy) Eval(ctx EvalContext) (interface{}, error) {
// Update our output // Update our output
*n.Output = diff *n.Output = diff
if n.State != nil {
// Record our proposed new state, which is nil because we're destroying.
*n.State = nil
}
return nil, nil return nil, nil
} }

View File

@ -46,7 +46,7 @@ func (n *NodePlannableResourceInstanceOrphan) EvalTree() EvalNode {
}, },
&EvalDiffDestroy{ &EvalDiffDestroy{
Addr: addr.Resource, Addr: addr.Resource,
State: &state, State: &state, // Will point to a nil state after this complete, signalling destroyed
Output: &diff, Output: &diff,
}, },
&EvalCheckPreventDestroy{ &EvalCheckPreventDestroy{
@ -58,6 +58,12 @@ func (n *NodePlannableResourceInstanceOrphan) EvalTree() EvalNode {
Name: stateId, Name: stateId,
Diff: &diff, Diff: &diff,
}, },
&EvalWriteState{
Name: stateId,
ResourceType: addr.Resource.Resource.Type,
Provider: n.ResolvedProvider,
State: &state,
},
}, },
} }
} }