github.com/jrasell/terraform@v0.6.17-0.20160523115548-2652f5232949/terraform/context_test.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 "time" 8 ) 9 10 func TestNewContextState(t *testing.T) { 11 cases := map[string]struct { 12 Input *ContextOpts 13 Err bool 14 }{ 15 "empty TFVersion": { 16 &ContextOpts{ 17 State: &State{}, 18 }, 19 false, 20 }, 21 22 "past TFVersion": { 23 &ContextOpts{ 24 State: &State{TFVersion: "0.1.2"}, 25 }, 26 false, 27 }, 28 29 "equal TFVersion": { 30 &ContextOpts{ 31 State: &State{TFVersion: Version}, 32 }, 33 false, 34 }, 35 36 "future TFVersion": { 37 &ContextOpts{ 38 State: &State{TFVersion: "99.99.99"}, 39 }, 40 true, 41 }, 42 43 "future TFVersion, allowed": { 44 &ContextOpts{ 45 State: &State{TFVersion: "99.99.99"}, 46 StateFutureAllowed: true, 47 }, 48 false, 49 }, 50 } 51 52 for k, tc := range cases { 53 ctx, err := NewContext(tc.Input) 54 if (err != nil) != tc.Err { 55 t.Fatalf("%s: err: %s", k, err) 56 } 57 if err != nil { 58 continue 59 } 60 61 // Version should always be set to our current 62 if ctx.state.TFVersion != Version { 63 t.Fatalf("%s: state not set to current version", k) 64 } 65 } 66 } 67 68 func testContext2(t *testing.T, opts *ContextOpts) *Context { 69 ctx, err := NewContext(opts) 70 if err != nil { 71 t.Fatalf("err: %s", err) 72 } 73 74 return ctx 75 } 76 77 func testApplyFn( 78 info *InstanceInfo, 79 s *InstanceState, 80 d *InstanceDiff) (*InstanceState, error) { 81 if d.Destroy { 82 return nil, nil 83 } 84 85 id := "foo" 86 if idAttr, ok := d.Attributes["id"]; ok && !idAttr.NewComputed { 87 id = idAttr.New 88 } 89 90 result := &InstanceState{ 91 ID: id, 92 Attributes: make(map[string]string), 93 } 94 95 // Copy all the prior attributes 96 for k, v := range s.Attributes { 97 result.Attributes[k] = v 98 } 99 100 if d != nil { 101 result = result.MergeDiff(d) 102 } 103 return result, nil 104 } 105 106 func testDiffFn( 107 info *InstanceInfo, 108 s *InstanceState, 109 c *ResourceConfig) (*InstanceDiff, error) { 110 var diff InstanceDiff 111 diff.Attributes = make(map[string]*ResourceAttrDiff) 112 113 for k, v := range c.Raw { 114 if _, ok := v.(string); !ok { 115 continue 116 } 117 118 // Ignore __-prefixed keys since they're used for magic 119 if k[0] == '_' && k[1] == '_' { 120 continue 121 } 122 123 if k == "nil" { 124 return nil, nil 125 } 126 127 // This key is used for other purposes 128 if k == "compute_value" { 129 continue 130 } 131 132 if k == "compute" { 133 attrDiff := &ResourceAttrDiff{ 134 Old: "", 135 New: "", 136 NewComputed: true, 137 } 138 139 if cv, ok := c.Config["compute_value"]; ok { 140 if cv.(string) == "1" { 141 attrDiff.NewComputed = false 142 attrDiff.New = fmt.Sprintf("computed_%s", v.(string)) 143 } 144 } 145 146 diff.Attributes[v.(string)] = attrDiff 147 continue 148 } 149 150 // If this key is not computed, then look it up in the 151 // cleaned config. 152 found := false 153 for _, ck := range c.ComputedKeys { 154 if ck == k { 155 found = true 156 break 157 } 158 } 159 if !found { 160 v = c.Config[k] 161 } 162 163 attrDiff := &ResourceAttrDiff{ 164 Old: "", 165 New: v.(string), 166 } 167 168 if k == "require_new" { 169 attrDiff.RequiresNew = true 170 } 171 if _, ok := c.Raw["__"+k+"_requires_new"]; ok { 172 attrDiff.RequiresNew = true 173 } 174 diff.Attributes[k] = attrDiff 175 } 176 177 for _, k := range c.ComputedKeys { 178 diff.Attributes[k] = &ResourceAttrDiff{ 179 Old: "", 180 NewComputed: true, 181 } 182 } 183 184 for k, v := range diff.Attributes { 185 if v.NewComputed { 186 continue 187 } 188 189 old, ok := s.Attributes[k] 190 if !ok { 191 continue 192 } 193 if old == v.New { 194 delete(diff.Attributes, k) 195 } 196 } 197 198 if !diff.Empty() { 199 diff.Attributes["type"] = &ResourceAttrDiff{ 200 Old: "", 201 New: info.Type, 202 } 203 } 204 205 return &diff, nil 206 } 207 208 func testProvider(prefix string) *MockResourceProvider { 209 p := new(MockResourceProvider) 210 p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) { 211 return s, nil 212 } 213 p.ResourcesReturn = []ResourceType{ 214 ResourceType{ 215 Name: fmt.Sprintf("%s_instance", prefix), 216 }, 217 } 218 219 return p 220 } 221 222 func testProvisioner() *MockResourceProvisioner { 223 p := new(MockResourceProvisioner) 224 return p 225 } 226 227 func checkStateString(t *testing.T, state *State, expected string) { 228 actual := strings.TrimSpace(state.String()) 229 expected = strings.TrimSpace(expected) 230 231 if actual != expected { 232 t.Fatalf("state does not match! actual:\n%s\n\nexpected:\n%s", actual, expected) 233 } 234 } 235 236 func resourceState(resourceType, resourceID string) *ResourceState { 237 return &ResourceState{ 238 Type: resourceType, 239 Primary: &InstanceState{ 240 ID: resourceID, 241 }, 242 } 243 } 244 245 // Test helper that gives a function 3 seconds to finish, assumes deadlock and 246 // fails test if it does not. 247 func testCheckDeadlock(t *testing.T, f func()) { 248 timeout := make(chan bool, 1) 249 done := make(chan bool, 1) 250 go func() { 251 time.Sleep(3 * time.Second) 252 timeout <- true 253 }() 254 go func(f func(), done chan bool) { 255 defer func() { done <- true }() 256 f() 257 }(f, done) 258 select { 259 case <-timeout: 260 t.Fatalf("timed out! probably deadlock") 261 case <-done: 262 // ok 263 } 264 } 265 266 const testContextGraph = ` 267 root: root 268 aws_instance.bar 269 aws_instance.bar -> provider.aws 270 aws_instance.foo 271 aws_instance.foo -> provider.aws 272 provider.aws 273 root 274 root -> aws_instance.bar 275 root -> aws_instance.foo 276 ` 277 278 const testContextRefreshModuleStr = ` 279 aws_instance.web: (1 tainted) 280 ID = <not created> 281 Tainted ID 1 = bar 282 283 module.child: 284 aws_instance.web: 285 ID = new 286 ` 287 288 const testContextRefreshOutputStr = ` 289 aws_instance.web: 290 ID = foo 291 foo = bar 292 293 Outputs: 294 295 foo = bar 296 ` 297 298 const testContextRefreshOutputPartialStr = ` 299 <no state> 300 ` 301 302 const testContextRefreshTaintedStr = ` 303 aws_instance.web: (1 tainted) 304 ID = <not created> 305 Tainted ID 1 = foo 306 `