interfaces: ensure that legacy interface methods are unused #3284

Merged
merged 4 commits into from May 10, 2017
@@ -20,7 +20,17 @@
package builtin_test
import (
+ "reflect"
+
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/apparmor"
"github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/interfaces/dbus"
+ "github.com/snapcore/snapd/interfaces/kmod"
+ "github.com/snapcore/snapd/interfaces/mount"
+ "github.com/snapcore/snapd/interfaces/seccomp"
+ "github.com/snapcore/snapd/interfaces/systemd"
+ "github.com/snapcore/snapd/interfaces/udev"
. "github.com/snapcore/snapd/testutil"
. "gopkg.in/check.v1"
@@ -107,3 +117,194 @@ func (s *AllSuite) TestInterfaces(c *C) {
c.Check(all, DeepContains, builtin.NewUnity8ContactsInterface())
c.Check(all, DeepContains, builtin.NewX11Interface())
}
+
+// This section contains a list of *valid* defines that represent methods that
+// backends recognize and call. They are in individual interfaces as each snapd
+// interface can define a subset that it is interested in providing. Those are,
+// essentially, the only valid methods that a snapd interface can have, apart
+// from what is defined in the Interface golang interface.
+
+type apparmorDefiner1 interface {
+ AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+}
+type apparmorDefiner2 interface {
+ AppArmorConnectedSlot(spec *apparmor.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+}
+type apparmorDefiner3 interface {
+ AppArmorPermanentPlug(spec *apparmor.Specification, plug *interfaces.Plug) error
+}
+type apparmorDefiner4 interface {
+ AppArmorPermanentSlot(spec *apparmor.Specification, slot *interfaces.Slot) error
+}
+
+type dbusDefiner1 interface {
+ DBusConnectedPlug(spec *dbus.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+}
+type dbusDefiner2 interface {
+ DBusConnectedSlot(spec *dbus.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+}
+type dbusDefiner3 interface {
+ DBusPermanentPlug(spec *dbus.Specification, plug *interfaces.Plug) error
+}
+type dbusDefiner4 interface {
+ DBusPermanentSlot(spec *dbus.Specification, slot *interfaces.Slot) error
+}
+
+type kmodDefiner1 interface {
+ KModConnectedPlug(spec *kmod.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+}
+type kmodDefiner2 interface {
+ KModConnectedSlot(spec *kmod.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+}
+type kmodDefiner3 interface {
+ KModPermanentPlug(spec *kmod.Specification, plug *interfaces.Plug) error
+}
+type kmodDefiner4 interface {
+ KModPermanentSlot(spec *kmod.Specification, slot *interfaces.Slot) error
+}
+
+type mountDefiner1 interface {
+ MountConnectedPlug(spec *mount.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+}
+type mountDefiner2 interface {
+ MountConnectedSlot(spec *mount.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+}
+type mountDefiner3 interface {
+ MountPermanentPlug(spec *mount.Specification, plug *interfaces.Plug) error
+}
+type mountDefiner4 interface {
+ MountPermanentSlot(spec *mount.Specification, slot *interfaces.Slot) error
+}
+
+type seccompDefiner1 interface {
+ SecCompConnectedPlug(spec *seccomp.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+}
+type seccompDefiner2 interface {
+ SecCompConnectedSlot(spec *seccomp.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+}
+type seccompDefiner3 interface {
+ SecCompPermanentPlug(spec *seccomp.Specification, plug *interfaces.Plug) error
+}
+type seccompDefiner4 interface {
+ SecCompPermanentSlot(spec *seccomp.Specification, slot *interfaces.Slot) error
+}
+
+type systemdDefiner1 interface {
+ SystemdConnectedPlug(spec *systemd.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+}
+type systemdDefiner2 interface {
+ SystemdConnectedSlot(spec *systemd.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+}
+type systemdDefiner3 interface {
+ SystemdPermanentPlug(spec *systemd.Specification, plug *interfaces.Plug) error
+}
+type systemdDefiner4 interface {
+ SystemdPermanentSlot(spec *systemd.Specification, slot *interfaces.Slot) error
+}
+
+type udevDefiner1 interface {
+ UDevConnectedPlug(spec *udev.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+}
+type udevDefiner2 interface {
+ UDevConnectedSlot(spec *udev.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error
+}
+type udevDefiner3 interface {
+ UDevPermanentPlug(spec *udev.Specification, plug *interfaces.Plug) error
+}
+type udevDefiner4 interface {
+ UDevPermanentSlot(spec *udev.Specification, slot *interfaces.Slot) error
+}
+
+// allGoodDefiners contains all valid specification definers for all known backends.
+var allGoodDefiners = []reflect.Type{
+ // apparmor
+ reflect.TypeOf((*apparmorDefiner1)(nil)).Elem(),
+ reflect.TypeOf((*apparmorDefiner2)(nil)).Elem(),
+ reflect.TypeOf((*apparmorDefiner3)(nil)).Elem(),
+ reflect.TypeOf((*apparmorDefiner4)(nil)).Elem(),
+ // dbus
+ reflect.TypeOf((*dbusDefiner1)(nil)).Elem(),
+ reflect.TypeOf((*dbusDefiner2)(nil)).Elem(),
+ reflect.TypeOf((*dbusDefiner3)(nil)).Elem(),
+ reflect.TypeOf((*dbusDefiner4)(nil)).Elem(),
+ // kmod
+ reflect.TypeOf((*kmodDefiner1)(nil)).Elem(),
+ reflect.TypeOf((*kmodDefiner2)(nil)).Elem(),
+ reflect.TypeOf((*kmodDefiner3)(nil)).Elem(),
+ reflect.TypeOf((*kmodDefiner4)(nil)).Elem(),
+ // mount
+ reflect.TypeOf((*mountDefiner1)(nil)).Elem(),
+ reflect.TypeOf((*mountDefiner2)(nil)).Elem(),
+ reflect.TypeOf((*mountDefiner3)(nil)).Elem(),
+ reflect.TypeOf((*mountDefiner4)(nil)).Elem(),
+ // seccomp
+ reflect.TypeOf((*seccompDefiner1)(nil)).Elem(),
+ reflect.TypeOf((*seccompDefiner2)(nil)).Elem(),
+ reflect.TypeOf((*seccompDefiner3)(nil)).Elem(),
+ reflect.TypeOf((*seccompDefiner4)(nil)).Elem(),
+ // systemd
+ reflect.TypeOf((*systemdDefiner1)(nil)).Elem(),
+ reflect.TypeOf((*systemdDefiner2)(nil)).Elem(),
+ reflect.TypeOf((*systemdDefiner3)(nil)).Elem(),
+ reflect.TypeOf((*systemdDefiner4)(nil)).Elem(),
+ // udev
+ reflect.TypeOf((*udevDefiner1)(nil)).Elem(),
+ reflect.TypeOf((*udevDefiner2)(nil)).Elem(),
+ reflect.TypeOf((*udevDefiner3)(nil)).Elem(),
+ reflect.TypeOf((*udevDefiner4)(nil)).Elem(),
+}
+
+// Check that each interface defines at least one definer method we recognize.
+func (s *AllSuite) TestEachInterfaceImplementsSomeBackendMethods(c *C) {
+ for _, iface := range builtin.Interfaces() {
+ bogus := true
+ for _, definer := range allGoodDefiners {
+ if reflect.TypeOf(iface).Implements(definer) {
+ bogus = false
@stolowski

stolowski May 9, 2017

Contributor

Micro-optization: break once you found a matching one ;)

@zyga

zyga May 9, 2017

Contributor

Done :)

+ break
+ }
+ }
+ c.Assert(bogus, Equals, false,
+ Commentf("interface %q does not implement any specification methods", iface.Name()))
+ }
+}
+
+// pre-specification snippet functions
+type snippetDefiner1 interface {
+ ConnectedPlugSnippet(plug *interfaces.Plug, slot *interfaces.Slot, sec interfaces.SecuritySystem) error
+}
+type snippetDefiner2 interface {
+ ConnectedSlotSnippet(plug *interfaces.Plug, slot *interfaces.Slot, sec interfaces.SecuritySystem) error
+}
+type snippetDefiner3 interface {
+ PermanentPlugSnippet(plug *interfaces.Plug, sec interfaces.SecuritySystem) error
+}
+type snippetDefiner4 interface {
+ PermanentSlotSnippet(slot *interfaces.Slot, sec interfaces.SecuritySystem) error
+}
+
+// old auto-connect function
+type legacyAutoConnect interface {
+ LegacyAutoConnect() bool
+}
+
+// allBadDefiners contains all old/unused specification definers for all known backends.
+var allBadDefiners = []reflect.Type{
+ // pre-specification snippet methods
+ reflect.TypeOf((*snippetDefiner1)(nil)).Elem(),
+ reflect.TypeOf((*snippetDefiner2)(nil)).Elem(),
+ reflect.TypeOf((*snippetDefiner3)(nil)).Elem(),
+ reflect.TypeOf((*snippetDefiner4)(nil)).Elem(),
+ // old auto-connect function
+ reflect.TypeOf((*legacyAutoConnect)(nil)).Elem(),
+}
+
+// Check that no interface defines older definer methods.
+func (s *AllSuite) TestNoInterfaceImplementsOldBackendMethods(c *C) {
+ for _, iface := range builtin.Interfaces() {
+ for _, definer := range allBadDefiners {
+ c.Assert(reflect.TypeOf(iface).Implements(definer), Equals, false,
+ Commentf("interface %q implement old/unused methods %s", iface.Name(), definer))
+ }
+ }
+}
@@ -110,10 +110,6 @@ func (iface *I2cInterface) UDevConnectedPlug(spec *udev.Specification, plug *int
return nil
}
-func (iface *I2cInterface) LegacyAutoConnect() bool {
- return false
-}
-
func (iface *I2cInterface) AutoConnect(*interfaces.Plug, *interfaces.Slot) bool {
// Allow what is allowed in the declarations
return true
@@ -310,10 +310,6 @@ func (iface *OfonoInterface) SanitizeSlot(slot *interfaces.Slot) error {
return nil
}
-func (iface *OfonoInterface) LegacyAutoConnect() bool {
- return false
-}
-
func (iface *OfonoInterface) AutoConnect(*interfaces.Plug, *interfaces.Slot) bool {
// allow what declarations allowed
return true