addrs: MoveEndpointInModule.SelectsResource

This is similar to the existing SelectsModule method, returning true if
the reciever selects either a particular resource as a whole or any of the
instances of that resource.

We don't need this test in the normal case, but we will need it in a
subsequent commit when we'll be possibly generating _implied_ move
statements between instances of resources, but only if there aren't
explicit move statements mentioning those resources already.
This commit is contained in:
Martin Atkins 2021-09-16 17:23:32 -07:00
parent 2b6a1be18f
commit 7f99a8802e
2 changed files with 158 additions and 0 deletions

View File

@ -233,6 +233,37 @@ func (e *MoveEndpointInModule) SelectsModule(addr ModuleInstance) bool {
return true
}
// SelectsResource returns true if the receiver directly selects either
// the given resource or one of its instances.
func (e *MoveEndpointInModule) SelectsResource(addr AbsResource) bool {
// Only a subset of subject types can possibly select a resource, so
// we'll take care of those quickly before we do anything more expensive.
switch e.relSubject.(type) {
case AbsResource, AbsResourceInstance:
// okay
default:
return false // can't possibly match
}
if !e.SelectsModule(addr.Module) {
return false
}
// If we get here then we know the module part matches, so we only need
// to worry about the relative resource part.
switch relSubject := e.relSubject.(type) {
case AbsResource:
return addr.Resource.Equal(relSubject.Resource)
case AbsResourceInstance:
// We intentionally ignore the instance key, because we consider
// instances to be part of the resource they belong to.
return addr.Resource.Equal(relSubject.Resource.Resource)
default:
// We should've filtered out all other types above
panic(fmt.Sprintf("unsupported relSubject type %T", relSubject))
}
}
// moduleInstanceCanMatch indicates that modA can match modB taking into
// account steps with an anyKey InstanceKey as wildcards. The comparison of
// wildcard steps is done symmetrically, because varying portions of either

View File

@ -1457,6 +1457,133 @@ func TestSelectsModule(t *testing.T) {
}
}
func TestSelectsResource(t *testing.T) {
matchingResource := Resource{
Mode: ManagedResourceMode,
Type: "foo",
Name: "matching",
}
unmatchingResource := Resource{
Mode: ManagedResourceMode,
Type: "foo",
Name: "unmatching",
}
childMod := Module{
"child",
}
childModMatchingInst := ModuleInstance{
ModuleInstanceStep{Name: "child", InstanceKey: StringKey("matching")},
}
childModUnmatchingInst := ModuleInstance{
ModuleInstanceStep{Name: "child", InstanceKey: StringKey("unmatching")},
}
tests := []struct {
Endpoint *MoveEndpointInModule
Addr AbsResource
Selects bool
}{
{
Endpoint: &MoveEndpointInModule{
relSubject: matchingResource.Absolute(nil),
},
Addr: matchingResource.Absolute(nil),
Selects: true, // exact match
},
{
Endpoint: &MoveEndpointInModule{
relSubject: unmatchingResource.Absolute(nil),
},
Addr: matchingResource.Absolute(nil),
Selects: false, // wrong resource name
},
{
Endpoint: &MoveEndpointInModule{
relSubject: unmatchingResource.Instance(IntKey(1)).Absolute(nil),
},
Addr: matchingResource.Absolute(nil),
Selects: false, // wrong resource name
},
{
Endpoint: &MoveEndpointInModule{
relSubject: matchingResource.Instance(NoKey).Absolute(nil),
},
Addr: matchingResource.Absolute(nil),
Selects: true, // matches one instance
},
{
Endpoint: &MoveEndpointInModule{
relSubject: matchingResource.Instance(IntKey(0)).Absolute(nil),
},
Addr: matchingResource.Absolute(nil),
Selects: true, // matches one instance
},
{
Endpoint: &MoveEndpointInModule{
relSubject: matchingResource.Instance(StringKey("a")).Absolute(nil),
},
Addr: matchingResource.Absolute(nil),
Selects: true, // matches one instance
},
{
Endpoint: &MoveEndpointInModule{
module: childMod,
relSubject: matchingResource.Absolute(nil),
},
Addr: matchingResource.Absolute(childModMatchingInst),
Selects: true, // in one of the instances of the module where the statement was written
},
{
Endpoint: &MoveEndpointInModule{
relSubject: matchingResource.Absolute(childModMatchingInst),
},
Addr: matchingResource.Absolute(childModMatchingInst),
Selects: true, // exact match
},
{
Endpoint: &MoveEndpointInModule{
relSubject: matchingResource.Instance(IntKey(2)).Absolute(childModMatchingInst),
},
Addr: matchingResource.Absolute(childModMatchingInst),
Selects: true, // matches one instance
},
{
Endpoint: &MoveEndpointInModule{
relSubject: matchingResource.Absolute(childModMatchingInst),
},
Addr: matchingResource.Absolute(childModUnmatchingInst),
Selects: false, // the containing module instance doesn't match
},
{
Endpoint: &MoveEndpointInModule{
relSubject: AbsModuleCall{
Module: mustParseModuleInstanceStr("module.foo[2]"),
Call: ModuleCall{Name: "bar"},
},
},
Addr: matchingResource.Absolute(mustParseModuleInstanceStr("module.foo[2]")),
Selects: false, // a module call can't match a resource
},
{
Endpoint: &MoveEndpointInModule{
relSubject: mustParseModuleInstanceStr("module.foo[2]"),
},
Addr: matchingResource.Absolute(mustParseModuleInstanceStr("module.foo[2]")),
Selects: false, // a module instance can't match a resource
},
}
for i, test := range tests {
t.Run(fmt.Sprintf("[%02d]%s SelectsResource(%s)", i, test.Endpoint, test.Addr),
func(t *testing.T) {
if got, want := test.Endpoint.SelectsResource(test.Addr), test.Selects; got != want {
t.Errorf("wrong result\nReceiver: %s\nArgument: %s\ngot: %t\nwant: %t", test.Endpoint, test.Addr, got, want)
}
},
)
}
}
func mustParseAbsResourceInstanceStr(s string) AbsResourceInstance {
r, diags := ParseAbsResourceInstanceStr(s)
if diags.HasErrors() {