github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/terraform/transform_reference_test.go (about) 1 package terraform 2 3 import ( 4 "reflect" 5 "sort" 6 "strings" 7 "testing" 8 9 "github.com/muratcelep/terraform/not-internal/addrs" 10 "github.com/muratcelep/terraform/not-internal/dag" 11 ) 12 13 func TestReferenceTransformer_simple(t *testing.T) { 14 g := Graph{Path: addrs.RootModuleInstance} 15 g.Add(&graphNodeRefParentTest{ 16 NameValue: "A", 17 Names: []string{"A"}, 18 }) 19 g.Add(&graphNodeRefChildTest{ 20 NameValue: "B", 21 Refs: []string{"A"}, 22 }) 23 24 tf := &ReferenceTransformer{} 25 if err := tf.Transform(&g); err != nil { 26 t.Fatalf("err: %s", err) 27 } 28 29 actual := strings.TrimSpace(g.String()) 30 expected := strings.TrimSpace(testTransformRefBasicStr) 31 if actual != expected { 32 t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) 33 } 34 } 35 36 func TestReferenceTransformer_self(t *testing.T) { 37 g := Graph{Path: addrs.RootModuleInstance} 38 g.Add(&graphNodeRefParentTest{ 39 NameValue: "A", 40 Names: []string{"A"}, 41 }) 42 g.Add(&graphNodeRefChildTest{ 43 NameValue: "B", 44 Refs: []string{"A", "B"}, 45 }) 46 47 tf := &ReferenceTransformer{} 48 if err := tf.Transform(&g); err != nil { 49 t.Fatalf("err: %s", err) 50 } 51 52 actual := strings.TrimSpace(g.String()) 53 expected := strings.TrimSpace(testTransformRefBasicStr) 54 if actual != expected { 55 t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) 56 } 57 } 58 59 func TestReferenceTransformer_path(t *testing.T) { 60 g := Graph{Path: addrs.RootModuleInstance} 61 g.Add(&graphNodeRefParentTest{ 62 NameValue: "A", 63 Names: []string{"A"}, 64 }) 65 g.Add(&graphNodeRefChildTest{ 66 NameValue: "B", 67 Refs: []string{"A"}, 68 }) 69 g.Add(&graphNodeRefParentTest{ 70 NameValue: "child.A", 71 PathValue: addrs.ModuleInstance{addrs.ModuleInstanceStep{Name: "child"}}, 72 Names: []string{"A"}, 73 }) 74 g.Add(&graphNodeRefChildTest{ 75 NameValue: "child.B", 76 PathValue: addrs.ModuleInstance{addrs.ModuleInstanceStep{Name: "child"}}, 77 Refs: []string{"A"}, 78 }) 79 80 tf := &ReferenceTransformer{} 81 if err := tf.Transform(&g); err != nil { 82 t.Fatalf("err: %s", err) 83 } 84 85 actual := strings.TrimSpace(g.String()) 86 expected := strings.TrimSpace(testTransformRefPathStr) 87 if actual != expected { 88 t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) 89 } 90 } 91 92 func TestReferenceTransformer_resourceInstances(t *testing.T) { 93 // Our reference analyses are all done based on unexpanded addresses 94 // so that we can use this transformer both in the plan graph (where things 95 // are not expanded yet) and the apply graph (where resource instances are 96 // pre-expanded but nothing else is.) 97 // However, that would make the result too conservative about instances 98 // of the same resource in different instances of the same module, so we 99 // make an exception for that situation in particular, keeping references 100 // between resource instances segregated by their containing module 101 // instance. 102 g := Graph{Path: addrs.RootModuleInstance} 103 moduleInsts := []addrs.ModuleInstance{ 104 { 105 { 106 Name: "foo", InstanceKey: addrs.IntKey(0), 107 }, 108 }, 109 { 110 { 111 Name: "foo", InstanceKey: addrs.IntKey(1), 112 }, 113 }, 114 } 115 resourceAs := make([]addrs.AbsResourceInstance, len(moduleInsts)) 116 for i, moduleInst := range moduleInsts { 117 resourceAs[i] = addrs.Resource{ 118 Mode: addrs.ManagedResourceMode, 119 Type: "thing", 120 Name: "a", 121 }.Instance(addrs.NoKey).Absolute(moduleInst) 122 } 123 resourceBs := make([]addrs.AbsResourceInstance, len(moduleInsts)) 124 for i, moduleInst := range moduleInsts { 125 resourceBs[i] = addrs.Resource{ 126 Mode: addrs.ManagedResourceMode, 127 Type: "thing", 128 Name: "b", 129 }.Instance(addrs.NoKey).Absolute(moduleInst) 130 } 131 g.Add(&graphNodeFakeResourceInstance{ 132 Addr: resourceAs[0], 133 }) 134 g.Add(&graphNodeFakeResourceInstance{ 135 Addr: resourceBs[0], 136 Refs: []*addrs.Reference{ 137 { 138 Subject: resourceAs[0].Resource, 139 }, 140 }, 141 }) 142 g.Add(&graphNodeFakeResourceInstance{ 143 Addr: resourceAs[1], 144 }) 145 g.Add(&graphNodeFakeResourceInstance{ 146 Addr: resourceBs[1], 147 Refs: []*addrs.Reference{ 148 { 149 Subject: resourceAs[1].Resource, 150 }, 151 }, 152 }) 153 154 tf := &ReferenceTransformer{} 155 if err := tf.Transform(&g); err != nil { 156 t.Fatalf("unexpected error: %s", err) 157 } 158 159 // Resource B should be connected to resource A in each module instance, 160 // but there should be no connections between the two module instances. 161 actual := strings.TrimSpace(g.String()) 162 expected := strings.TrimSpace(` 163 module.foo[0].thing.a 164 module.foo[0].thing.b 165 module.foo[0].thing.a 166 module.foo[1].thing.a 167 module.foo[1].thing.b 168 module.foo[1].thing.a 169 `) 170 if actual != expected { 171 t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) 172 } 173 } 174 175 func TestReferenceMapReferences(t *testing.T) { 176 cases := map[string]struct { 177 Nodes []dag.Vertex 178 Check dag.Vertex 179 Result []string 180 }{ 181 "simple": { 182 Nodes: []dag.Vertex{ 183 &graphNodeRefParentTest{ 184 NameValue: "A", 185 Names: []string{"A"}, 186 }, 187 }, 188 Check: &graphNodeRefChildTest{ 189 NameValue: "foo", 190 Refs: []string{"A"}, 191 }, 192 Result: []string{"A"}, 193 }, 194 } 195 196 for tn, tc := range cases { 197 t.Run(tn, func(t *testing.T) { 198 rm := NewReferenceMap(tc.Nodes) 199 result := rm.References(tc.Check) 200 201 var resultStr []string 202 for _, v := range result { 203 resultStr = append(resultStr, dag.VertexName(v)) 204 } 205 206 sort.Strings(resultStr) 207 sort.Strings(tc.Result) 208 if !reflect.DeepEqual(resultStr, tc.Result) { 209 t.Fatalf("bad: %#v", resultStr) 210 } 211 }) 212 } 213 } 214 215 type graphNodeRefParentTest struct { 216 NameValue string 217 PathValue addrs.ModuleInstance 218 Names []string 219 } 220 221 var _ GraphNodeReferenceable = (*graphNodeRefParentTest)(nil) 222 223 func (n *graphNodeRefParentTest) Name() string { 224 return n.NameValue 225 } 226 227 func (n *graphNodeRefParentTest) ReferenceableAddrs() []addrs.Referenceable { 228 ret := make([]addrs.Referenceable, len(n.Names)) 229 for i, name := range n.Names { 230 ret[i] = addrs.LocalValue{Name: name} 231 } 232 return ret 233 } 234 235 func (n *graphNodeRefParentTest) Path() addrs.ModuleInstance { 236 return n.PathValue 237 } 238 239 func (n *graphNodeRefParentTest) ModulePath() addrs.Module { 240 return n.PathValue.Module() 241 } 242 243 type graphNodeRefChildTest struct { 244 NameValue string 245 PathValue addrs.ModuleInstance 246 Refs []string 247 } 248 249 var _ GraphNodeReferencer = (*graphNodeRefChildTest)(nil) 250 251 func (n *graphNodeRefChildTest) Name() string { 252 return n.NameValue 253 } 254 255 func (n *graphNodeRefChildTest) References() []*addrs.Reference { 256 ret := make([]*addrs.Reference, len(n.Refs)) 257 for i, name := range n.Refs { 258 ret[i] = &addrs.Reference{ 259 Subject: addrs.LocalValue{Name: name}, 260 } 261 } 262 return ret 263 } 264 265 func (n *graphNodeRefChildTest) Path() addrs.ModuleInstance { 266 return n.PathValue 267 } 268 269 func (n *graphNodeRefChildTest) ModulePath() addrs.Module { 270 return n.PathValue.Module() 271 } 272 273 type graphNodeFakeResourceInstance struct { 274 Addr addrs.AbsResourceInstance 275 Refs []*addrs.Reference 276 } 277 278 var _ GraphNodeResourceInstance = (*graphNodeFakeResourceInstance)(nil) 279 var _ GraphNodeReferenceable = (*graphNodeFakeResourceInstance)(nil) 280 var _ GraphNodeReferencer = (*graphNodeFakeResourceInstance)(nil) 281 282 func (n *graphNodeFakeResourceInstance) ResourceInstanceAddr() addrs.AbsResourceInstance { 283 return n.Addr 284 } 285 286 func (n *graphNodeFakeResourceInstance) ModulePath() addrs.Module { 287 return n.Addr.Module.Module() 288 } 289 290 func (n *graphNodeFakeResourceInstance) ReferenceableAddrs() []addrs.Referenceable { 291 return []addrs.Referenceable{n.Addr.Resource} 292 } 293 294 func (n *graphNodeFakeResourceInstance) References() []*addrs.Reference { 295 return n.Refs 296 } 297 298 func (n *graphNodeFakeResourceInstance) StateDependencies() []addrs.ConfigResource { 299 return nil 300 } 301 302 func (n *graphNodeFakeResourceInstance) String() string { 303 return n.Addr.String() 304 } 305 306 const testTransformRefBasicStr = ` 307 A 308 B 309 A 310 ` 311 312 const testTransformRefPathStr = ` 313 A 314 B 315 A 316 child.A 317 child.B 318 child.A 319 `