Repository: scionproto/scion
Pull request #3572 (2020-01-06 14:15:34)

BS: reduce interface state to active/revoked
Contributes #2926

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/scionproto/scion/3572)
<!-- Reviewable:end -->



Patch:
diff --git a/doc/BeaconService.md b/doc/BeaconService.md
index 998a08463..272f58a0b 100644
--- a/doc/BeaconService.md
+++ b/doc/BeaconService.md
@@ -162,16 +162,17 @@ type Interface interface {
     // necessary, and sets the remote interface id. The return value indicates
     // the previous state of the interface.
     func Activate(remote common.IFIDType) State
-    // Expire checks whether the interface has not been activated for a certain
-    // amount of time. If that is the case and the current state is inactive or
-    // active, the state changes to Expired. The return value indicates,
-    // whether the state is expired or revoked when the call returns.
-    func Expire() bool
-    // Revoke changes the state of the interface to revoked and updates the
-    // revocation, unless the current state is active. In that case, the
-    // interface has been activated in the meantime and should not be revoked.
+    // Revoke checks whether the interface has not been activated for a certain
+    // amount of time. If that is the case and the current state is active, the
+    // state changes to Revoked. The times for last beacon origination and
+    // propagation are reset to the zero value. The return value indicates, whether
+    // the state is revoked when the call returns.
+    func Revoke() bool
+    // SetRevocation sets the revocation for this interface. This can only be
+    // invoked when the interface is in revoked state. Otherwise it is assumed that
+    // the interface has been activated in the meantime and should not be revoked.
     // This is indicated through an error.
-    func Revoke(rev *path_mgmt.SignedRevInfo) error
+    func SetRevocation(rev *path_mgmt.SignedRevInfo) error
     // Revocation returns the revocation.
     func Revocation() *path_mgmt.SignedRevInfo
     // TopoInfo returns the topology information.
@@ -184,13 +185,8 @@ type Interface interface {
 type State string
 
 const (
-    // Inactive indicates that the interface has not been activated or
-    // expired yet.
-    Inactive State = "Inactive"
     // Active indicates that the interface is active.
     Active State = "Active"
-    // Expired indicates that the interface is expired.
-    Expired State = "Expired"
     // Revoked indicates that the interface is revoked.
     Revoked State = "Revoked"
 )
@@ -316,14 +312,15 @@ after a stale period.
 
 #### Interface Revocation
 
-*(uses: `Interfaces.All`, `Interface.Expire`,  `Interface.Revoke`, `BeaconStore.InsertRevocation`).*
+*(uses: `Interfaces.All`, `Interface.Revoke`, `Interface.SetRevocation`,
+ `BeaconStore.InsertRevocation`).*
 
 Each BS instance keeps track of the interface state in an in-memory structure. When a configurable
 amount of keepalive messages for a given interface is not received, the interface is revoked by the
 BS.
 
-1. Call `Interface.Expire` on all infos.
-1. Revoke all expired interfaces in `InterfaceState`, update the revocation if necessary (certain
+1. Call `Interface.Revoke` on all infos.
+1. Revoke all revoked interfaces in `InterfaceState`, update the revocation if necessary (certain
    amount of previous revocation period has passed).
 1. Insert revocation in beacon store.
 1. Send revocation to all BRs in the local AS.
diff --git a/go.mod b/go.mod
index 1b68275ea..3ef41dc64 100644
--- a/go.mod
+++ b/go.mod
@@ -33,7 +33,6 @@ require (
 	github.com/prometheus/client_golang v1.1.0
 	github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect
 	github.com/sergi/go-diff v1.0.1-0.20180205163309-da645544ed44
-	github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d
 	github.com/smartystreets/goconvey v1.6.4
 	github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b
 	github.com/spf13/cobra v0.0.3-0.20180408161736-cd30c2a7e91a
diff --git a/go/beacon_srv/internal/ifstate/BUILD.bazel b/go/beacon_srv/internal/ifstate/BUILD.bazel
index a987b9232..c8849f131 100644
--- a/go/beacon_srv/internal/ifstate/BUILD.bazel
+++ b/go/beacon_srv/internal/ifstate/BUILD.bazel
@@ -33,6 +33,7 @@ go_library(
 go_test(
     name = "go_default_test",
     srcs = [
+        "export_test.go",
         "handler_test.go",
         "ifstate_test.go",
         "pusher_test.go",
@@ -59,8 +60,8 @@ go_test(
         "//go/lib/xtest/matchers:go_default_library",
         "//go/proto:go_default_library",
         "@com_github_golang_mock//gomock:go_default_library",
-        "@com_github_smartystreets_assertions//:go_default_library",
-        "@com_github_smartystreets_assertions//should:go_default_library",
         "@com_github_smartystreets_goconvey//convey:go_default_library",
+        "@com_github_stretchr_testify//assert:go_default_library",
+        "@com_github_stretchr_testify//require:go_default_library",
     ],
 )
diff --git a/go/beacon_srv/internal/ifstate/ifstate.go b/go/beacon_srv/internal/ifstate/ifstate.go
index f6e25ee37..a77c7a205 100644
--- a/go/beacon_srv/internal/ifstate/ifstate.go
+++ b/go/beacon_srv/internal/ifstate/ifstate.go
@@ -34,13 +34,8 @@ const (
 )
 
 const (
-	// Inactive indicates that the interface has not been activated or
-	// expired yet.
-	Inactive State = "Inactive"
 	// Active indicates that the interface is active.
 	Active State = "Active"
-	// Expired indicates that the interface is expired.
-	Expired State = "Expired"
 	// Revoked indicates that the interface is revoked.
 	Revoked State = "Revoked"
 )
@@ -94,7 +89,7 @@ func (intfs *Interfaces) Update(ifInfomap topology.IfInfoMap) {
 		} else {
 			m[ifid] = &Interface{
 				topoInfo:     info,
-				state:        Inactive,
+				state:        Active,
 				lastActivate: time.Now(),
 				cfg:          intfs.cfg,
 			}
@@ -157,35 +152,31 @@ func (intf *Interface) Activate(remote common.IFIDType) State {
 	return prev
 }
 
-// Expire checks whether the interface has not been activated for a certain
-// amount of time. If that is the case and the current state is inactive or
-// active, the state changes to Expired. The times for last beacon origination
-// and propagation are reset to the zero value. The return value indicates,
-// whether the state is expired or revoked when the call returns.
-func (intf *Interface) Expire() bool {
+// Revoke checks whether the interface has not been activated for a certain
+// amount of time. If that is the case and the current state is active, the
+// state changes to Revoked. The times for last beacon origination and
+// propagation are reset to the zero value. The return value indicates, whether
+// the state is revoked when the call returns.
+func (intf *Interface) Revoke() bool {
 	intf.mu.Lock()
 	defer intf.mu.Unlock()
-	if intf.state == Expired || intf.state == Revoked {
-		return true
-	}
 	if time.Now().Sub(intf.lastActivate) > intf.cfg.KeepaliveTimeout {
 		intf.lastOriginate = time.Time{}
 		intf.lastPropagate = time.Time{}
-		intf.state = Expired
-		return true
+		intf.state = Revoked
 	}
-	return false
+	return intf.state == Revoked
 }
 
-// Revoke changes the state of the interface to revoked and updates the
-// revocation, unless the current state is active. In that case, the
-// interface has been activated in the meantime and should not be revoked.
+// SetRevocation sets the revocation for this interface. This can only be
+// invoked when the interface is in revoked state. Otherwise it is assumed that
+// the interface has been activated in the meantime and should not be revoked.
 // This is indicated through an error.
-func (intf *Interface) Revoke(rev *path_mgmt.SignedRevInfo) error {
+func (intf *Interface) SetRevocation(rev *path_mgmt.SignedRevInfo) error {
 	intf.mu.Lock()
 	defer intf.mu.Unlock()
 	if intf.state == Active {
-		return serrors.New("Interface activated in the meantime")
+		return serrors.New("interface activated in the meantime")
 	}
 	intf.state = Revoked
 	intf.revocation = rev
@@ -244,7 +235,7 @@ func (intf *Interface) LastPropagate() time.Time {
 func (intf *Interface) reset() {
 	intf.mu.Lock()
 	defer intf.mu.Unlock()
-	intf.state = Inactive
+	intf.state = Active
 	intf.revocation = nil
 	intf.lastOriginate = time.Time{}
 	intf.lastPropagate = time.Time{}
diff --git a/go/beacon_srv/internal/ifstate/revoker.go b/go/beacon_srv/internal/ifstate/revoker.go
index c1e1fceb2..63cf3a26e 100644
--- a/go/beacon_srv/internal/ifstate/revoker.go
+++ b/go/beacon_srv/internal/ifstate/revoker.go
@@ -96,7 +96,7 @@ func (r *Revoker) Run(ctx context.Context) {
 			NeighIA: intf.TopoInfo().IA,
 		}
 
-		if intf.Expire() && !r.hasValidRevocation(intf) {
+		if intf.Revoke() && !r.hasValidRevocation(intf) {
 			if intf.Revocation() == nil {
 				labelsIssued.State = metrics.RevNew
 				logger.Info("[ifstate.Revoker] interface went down", "ifid", ifid)
@@ -107,7 +107,7 @@ func (r *Revoker) Run(ctx context.Context) {
 					"ifid", ifid, "err", err)
 				continue
 			}
-			if err := intf.Revoke(srev); err != nil {
+			if err := intf.SetRevocation(srev); err != nil {
 				logger.Error("[ifstate.Revoker] Failed to revoke!", "ifid", ifid, "err", err)
 				continue
 			}


Test patch:
diff --git a/go/beacon_srv/internal/ifstate/export_test.go b/go/beacon_srv/internal/ifstate/export_test.go
new file mode 100644
index 000000000..a3fe38787
--- /dev/null
+++ b/go/beacon_srv/internal/ifstate/export_test.go
@@ -0,0 +1,19 @@
+// Copyright 2019 Anapaya Systems
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ifstate
+
+func (intf *Interface) SetState(s State) {
+	intf.state = s
+}
diff --git a/go/beacon_srv/internal/ifstate/handler_test.go b/go/beacon_srv/internal/ifstate/handler_test.go
index da29bd65e..8e2a4a30a 100644
--- a/go/beacon_srv/internal/ifstate/handler_test.go
+++ b/go/beacon_srv/internal/ifstate/handler_test.go
@@ -20,8 +20,8 @@ import (
 	"testing"
 
 	"github.com/golang/mock/gomock"
-	"github.com/smartystreets/assertions"
-	"github.com/smartystreets/assertions/should"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 
 	"github.com/scionproto/scion/go/lib/ctrl/path_mgmt"
 	"github.com/scionproto/scion/go/lib/infra"
@@ -90,7 +90,6 @@ func TestHandler(t *testing.T) {
 		t.Run(test.name, func(t *testing.T) {
 			mctrl := gomock.NewController(t)
 			defer mctrl.Finish()
-			assert := assertions.New(t)
 			rw := mock_infra.NewMockResponseWriter(mctrl)
 			var reply *path_mgmt.IFStateInfos
 			rw.EXPECT().SendIfStateInfoReply(gomock.Any(), gomock.Any()).DoAndReturn(
@@ -102,11 +101,11 @@ func TestHandler(t *testing.T) {
 			serveCtx := infra.NewContextWithResponseWriter(context.Background(), rw)
 			req := infra.NewRequest(serveCtx, test.req, nil, nil, 0)
 			handlerRes := h.Handle(req)
-			assert.So(handlerRes, should.Equal, infra.MetricsResultOk)
+			assert.Equal(t, infra.MetricsResultOk, handlerRes)
 			sort.Slice(reply.Infos, func(i, j int) bool {
 				return reply.Infos[i].IfID < reply.Infos[j].IfID
 			})
-			assert.So(reply, should.Resemble, test.expected)
+			assert.Equal(t, test.expected, reply)
 		})
 	}
 }
@@ -119,9 +118,9 @@ func interfaces(t *testing.T, topoProvider topology.Provider,
 	for _, info := range expectedIfSate.Infos {
 		if !info.Active {
 			intf := intfs.Get(info.IfID)
-			intf.state = Inactive
+			intf.SetState(Revoked)
 			if info.SRevInfo != nil {
-				xtest.FailOnErr(t, intf.Revoke(info.SRevInfo))
+				require.NoError(t, intf.SetRevocation(info.SRevInfo))
 			}
 		}
 	}
diff --git a/go/beacon_srv/internal/ifstate/ifstate_test.go b/go/beacon_srv/internal/ifstate/ifstate_test.go
index 777a8bfbf..15bc6db7d 100644
--- a/go/beacon_srv/internal/ifstate/ifstate_test.go
+++ b/go/beacon_srv/internal/ifstate/ifstate_test.go
@@ -19,64 +19,62 @@ import (
 	"time"
 
 	. "github.com/smartystreets/goconvey/convey"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 
 	"github.com/scionproto/scion/go/lib/ctrl/path_mgmt"
 	"github.com/scionproto/scion/go/lib/topology"
 )
 
 func TestInterfacesUpdate(t *testing.T) {
-	Convey("Given an interface infos map with existing entries", t, func() {
-		intfs := testInterfaces()
-		Convey("The update retains the state of the interface", func() {
-			topoMap := topology.IfInfoMap{
-				1: {BRName: "BR-1-new"},
-				2: {BRName: "BR-2-new"},
-			}
-			intfs.Update(topoMap)
-			// The topo info should come from the updated map.
-			SoMsg("Name 1", intfs.Get(1).TopoInfo().BRName, ShouldEqual, "BR-1-new")
-			SoMsg("Name 2", intfs.Get(2).TopoInfo().BRName, ShouldEqual, "BR-2-new")
-			// The remote ifid should be kept
-			SoMsg("Ifid 1", intfs.Get(1).TopoInfo().RemoteIFID, ShouldEqual, 11)
-			SoMsg("Ifid 2", intfs.Get(2).TopoInfo().RemoteIFID, ShouldEqual, 22)
-			// The state should be kept
-			SoMsg("State 1", intfs.Get(1).State(), ShouldEqual, Active)
-			SoMsg("State 2", intfs.Get(2).State(), ShouldEqual, Revoked)
-		})
-		Convey("The update adds new interfaces and removes missing", func() {
-			topoMap := topology.IfInfoMap{
-				3: {BRName: "BR-3-new"},
-			}
-			intfs.Update(topoMap)
-			SoMsg("Gone 1", intfs.Get(1), ShouldBeNil)
-			SoMsg("Gone 2", intfs.Get(2), ShouldBeNil)
-			SoMsg("Name 3", intfs.Get(3).TopoInfo().BRName, ShouldEqual, "BR-3-new")
-		})
+	t.Run("The update retains the state of the interface", func(t *testing.T) {
+		intfs := testInterfaces(t)
+		topoMap := topology.IfInfoMap{
+			1: {BRName: "BR-1-new"},
+			2: {BRName: "BR-2-new"},
+		}
+		intfs.Update(topoMap)
+		// The topo info should come from the updated map.
+		assert.Equal(t, "BR-1-new", intfs.Get(1).TopoInfo().BRName)
+		assert.Equal(t, "BR-2-new", intfs.Get(2).TopoInfo().BRName)
+		// The remote ifid should be kept
+		assert.EqualValues(t, 11, intfs.Get(1).TopoInfo().RemoteIFID)
+		assert.EqualValues(t, 22, intfs.Get(2).TopoInfo().RemoteIFID)
+		// The state should be kept
+		assert.Equal(t, Active, intfs.Get(1).State())
+		assert.Equal(t, Revoked, intfs.Get(2).State())
+	})
+	t.Run("The update adds new interfaces and removes missing", func(t *testing.T) {
+		intfs := testInterfaces(t)
+		topoMap := topology.IfInfoMap{
+			3: {BRName: "BR-3-new"},
+		}
+		intfs.Update(topoMap)
+		assert.Nil(t, intfs.Get(1))
+		assert.Nil(t, intfs.Get(2))
+		assert.Equal(t, "BR-3-new", intfs.Get(3).TopoInfo().BRName)
 	})
 }
 
 func TestInterfacesReset(t *testing.T) {
-	Convey("Given an interface infos map with existing entries", t, func() {
-		intfs := testInterfaces()
-		Convey("Reset resets the info state", func() {
-			intfs.Reset()
-			// The topo info should remain.
-			SoMsg("Name 1", intfs.Get(1).TopoInfo().BRName, ShouldEqual, "BR-1")
-			SoMsg("Name 2", intfs.Get(2).TopoInfo().BRName, ShouldEqual, "BR-2")
-			SoMsg("Ifid 1", intfs.Get(1).TopoInfo().RemoteIFID, ShouldEqual, 11)
-			SoMsg("Ifid 2", intfs.Get(2).TopoInfo().RemoteIFID, ShouldEqual, 22)
-			// The state and revocations should be reset.
-			SoMsg("State 1", intfs.Get(1).State(), ShouldEqual, Inactive)
-			SoMsg("State 2", intfs.Get(2).State(), ShouldEqual, Inactive)
-			SoMsg("Revocation 1", intfs.Get(1).Revocation(), ShouldBeNil)
-			SoMsg("Revocation 2", intfs.Get(2).Revocation(), ShouldBeNil)
-		})
-	})
+	intfs := testInterfaces(t)
+	intfs.Reset()
+	// The topo info should remain.
+	assert.Equal(t, "BR-1", intfs.Get(1).TopoInfo().BRName)
+	assert.Equal(t, "BR-1", intfs.Get(1).TopoInfo().BRName)
+	assert.Equal(t, "BR-2", intfs.Get(2).TopoInfo().BRName)
+	assert.EqualValues(t, 11, intfs.Get(1).TopoInfo().RemoteIFID)
+	assert.EqualValues(t, 22, intfs.Get(2).TopoInfo().RemoteIFID)
+	// The state and revocations should be reset.
+	assert.Equal(t, Active, intfs.Get(1).State())
+	assert.Equal(t, Active, intfs.Get(2).State())
+	assert.Nil(t, intfs.Get(1).Revocation())
+	assert.Nil(t, intfs.Get(2).Revocation())
 }
 
 func TestInterfacesAll(t *testing.T) {
 	Convey("Given an interface infos map with existing entries", t, func() {
-		intfs := testInterfaces()
+		intfs := testInterfaces(t)
 		Convey("All should return all infos", func() {
 			all := intfs.All()
 			// The topo info should remain.
@@ -93,7 +91,7 @@ func TestInterfacesAll(t *testing.T) {
 }
 
 func TestInfoActivate(t *testing.T) {
-	for _, state := range []State{Inactive, Active, Expired, Revoked} {
+	for _, state := range []State{Active, Revoked} {
 		Convey("Activate switches correctly from "+string(state), t, func() {
 			intf := &Interface{state: state, revocation: &path_mgmt.SignedRevInfo{}}
 			intf.cfg.InitDefaults()
@@ -107,15 +105,13 @@ func TestInfoActivate(t *testing.T) {
 	}
 }
 
-func TestInfoExpire(t *testing.T) {
+func TestInfoRevoke(t *testing.T) {
 	Convey("Given an interface that has not received a keepalive", t, func() {
 		testCases := []struct {
 			PrevState State
 			NextState State
 		}{
-			{PrevState: Inactive, NextState: Expired},
-			{PrevState: Active, NextState: Expired},
-			{PrevState: Expired, NextState: Expired},
+			{PrevState: Active, NextState: Revoked},
 			{PrevState: Revoked, NextState: Revoked},
 		}
 		for _, test := range testCases {
@@ -125,7 +121,7 @@ func TestInfoExpire(t *testing.T) {
 					lastActivate: time.Now().Add(-DefaultKeepaliveTimeout - time.Second),
 				}
 				intf.cfg.InitDefaults()
-				expired := intf.Expire()
+				expired := intf.Revoke()
 				SoMsg("Expired", expired, ShouldBeTrue)
 				SoMsg("State", intf.State(), ShouldEqual, test.NextState)
 				SoMsg("LastActivate", time.Now().Sub(intf.lastActivate), ShouldBeGreaterThan,
@@ -134,31 +130,29 @@ func TestInfoExpire(t *testing.T) {
 		}
 	})
 	Convey("Given the keepalive has been received in the last keepalive timeout", t, func() {
-		for _, test := range []State{Inactive, Active, Expired, Revoked} {
+		for _, test := range []State{Active, Revoked} {
 			Convey("Test "+string(test), func() {
 				intf := &Interface{
 					state:        test,
 					lastActivate: time.Now().Add(-DefaultKeepaliveTimeout + time.Second),
 				}
 				intf.cfg.InitDefaults()
-				expired := intf.Expire()
-				SoMsg("Expired", expired, ShouldEqual, test == Revoked || test == Expired)
+				expired := intf.Revoke()
+				SoMsg("Expired", expired, ShouldEqual, test == Revoked)
 				SoMsg("State", intf.State(), ShouldEqual, test)
 			})
 		}
 	})
 }
 
-func TestInfoRevoke(t *testing.T) {
+func TestInfoSetRevocation(t *testing.T) {
 	Convey("Given an interface in a certain state", t, func() {
 		testCases := []struct {
 			PrevState State
 			NextState State
 			Error     bool
 		}{
-			{PrevState: Inactive, NextState: Revoked, Error: false},
 			{PrevState: Active, NextState: Active, Error: true},
-			{PrevState: Expired, NextState: Revoked, Error: false},
 			{PrevState: Revoked, NextState: Revoked, Error: false},
 		}
 		for _, test := range testCases {
@@ -167,7 +161,7 @@ func TestInfoRevoke(t *testing.T) {
 					state: test.PrevState,
 				}
 				intf.cfg.InitDefaults()
-				err := intf.Revoke(&path_mgmt.SignedRevInfo{})
+				err := intf.SetRevocation(&path_mgmt.SignedRevInfo{})
 				SoMsg("State", intf.State(), ShouldEqual, test.NextState)
 				if test.Error {
 					SoMsg("err", err, ShouldNotBeNil)
@@ -181,7 +175,7 @@ func TestInfoRevoke(t *testing.T) {
 	})
 }
 
-func testInterfaces() *Interfaces {
+func testInterfaces(t *testing.T) *Interfaces {
 	topoMap := topology.IfInfoMap{
 		1: {BRName: "BR-1"},
 		2: {BRName: "BR-2"},
@@ -189,6 +183,8 @@ func testInterfaces() *Interfaces {
 	intfs := NewInterfaces(topoMap, Config{})
 	intfs.Get(1).Activate(11)
 	intfs.Get(2).topoInfo.RemoteIFID = 22
-	intfs.Get(2).Revoke(&path_mgmt.SignedRevInfo{})
+	intfs.Get(2).state = Revoked
+	err := intfs.Get(2).SetRevocation(&path_mgmt.SignedRevInfo{})
+	require.NoError(t, err)
 	return intfs
 }
diff --git a/go/beacon_srv/internal/ifstate/pusher_test.go b/go/beacon_srv/internal/ifstate/pusher_test.go
index d5078cebb..a20c1a8d6 100644
--- a/go/beacon_srv/internal/ifstate/pusher_test.go
+++ b/go/beacon_srv/internal/ifstate/pusher_test.go
@@ -47,10 +47,8 @@ func TestPusherPush(t *testing.T) {
 	}
 	// When to expect a message being pushed.
 	tests := map[State]bool{
-		Inactive: false,
-		Active:   true,
-		Expired:  false,
-		Revoked:  false,
+		Active:  true,
+		Revoked: false,
 	}
 	for state, expectMsg := range tests {
 		t.Run(fmt.Sprintf("Interface state: %s", state), func(t *testing.T) {
diff --git a/go/beacon_srv/internal/ifstate/revoker_test.go b/go/beacon_srv/internal/ifstate/revoker_test.go
index d02f781af..a1991d240 100644
--- a/go/beacon_srv/internal/ifstate/revoker_test.go
+++ b/go/beacon_srv/internal/ifstate/revoker_test.go
@@ -150,7 +150,7 @@ func TestRevokedInterfaceNotRevokedImmediately(t *testing.T) {
 		revInserter := mock_ifstate.NewMockRevInserter(mctrl)
 		intfs := NewInterfaces(topoProvider.Get().IFInfoMap(), Config{})
 		activateAll(intfs)
-		intfs.Get(101).state = Expired
+		intfs.Get(101).state = Revoked
 		srev, err := path_mgmt.NewSignedRevInfo(&path_mgmt.RevInfo{
 			IfID:         101,
 			RawIsdas:     ia.IAInt(),
@@ -159,7 +159,7 @@ func TestRevokedInterfaceNotRevokedImmediately(t *testing.T) {
 			RawTTL:       uint32(ttl.Seconds()),
 		}, infra.NullSigner)
 		xtest.FailOnErr(t, err)
-		intfs.Get(101).Revoke(srev)
+		intfs.Get(101).SetRevocation(srev)
 		cfg := RevokerConf{
 			Intfs:        intfs,
 			Msgr:         msgr,
@@ -195,7 +195,7 @@ func TestRevokedInterfaceRevokedAgain(t *testing.T) {
 		revInserter := mock_ifstate.NewMockRevInserter(mctrl)
 		intfs := NewInterfaces(topoProvider.Get().IFInfoMap(), Config{})
 		activateAll(intfs)
-		intfs.Get(101).state = Expired
+		intfs.Get(101).state = Revoked
 		srev, err := path_mgmt.NewSignedRevInfo(&path_mgmt.RevInfo{
 			IfID:         101,
 			RawIsdas:     ia.IAInt(),
@@ -204,7 +204,7 @@ func TestRevokedInterfaceRevokedAgain(t *testing.T) {
 			RawTTL:       uint32(ttl.Seconds()),
 		}, infra.NullSigner)
 		xtest.FailOnErr(t, err)
-		intfs.Get(101).Revoke(srev)
+		intfs.Get(101).SetRevocation(srev)
 		revInserter.EXPECT().InsertRevocations(gomock.Any(), &matchers.SignedRevs{
 			Verifier: revVerifier(pub),
 			MatchRevs: []path_mgmt.RevInfo{{
diff --git a/go/beacon_srv/internal/keepalive/handler_test.go b/go/beacon_srv/internal/keepalive/handler_test.go
index 7c8839fb8..c7f37abe0 100644
--- a/go/beacon_srv/internal/keepalive/handler_test.go
+++ b/go/beacon_srv/internal/keepalive/handler_test.go
@@ -24,6 +24,7 @@ import (
 
 	"github.com/golang/mock/gomock"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 
 	"github.com/scionproto/scion/go/beacon_srv/internal/ifstate"
 	"github.com/scionproto/scion/go/beacon_srv/internal/keepalive/mock_keepalive"
@@ -71,7 +72,7 @@ func TestNewHandler(t *testing.T) {
 		set(dropper.EXPECT().DeleteRevocation(gomock.Any(), localIA, localIF)).Return(nil)
 		set(dropper.EXPECT().DeleteRevocation(gomock.Any(), originIA, originIF)).Return(nil)
 
-		handler := NewHandler(localIA, testInterfaces(), StateChangeTasks{
+		handler := NewHandler(localIA, testInterfaces(t), StateChangeTasks{
 			IfStatePusher: pusher,
 			RevDropper:    dropper,
 		})
@@ -84,7 +85,7 @@ func TestNewHandler(t *testing.T) {
 	})
 
 	t.Run("Active interface should cause no tasks to execute", func(t *testing.T) {
-		intfs := testInterfaces()
+		intfs := testInterfaces(t)
 		intfs.Get(localIF).Activate(42)
 		handler := NewHandler(localIA, intfs, zeroCallTasks(mctrl))
 		req := infra.NewRequest(context.Background(), &ifid.IFID{OrigIfID: originIF}, nil,
@@ -94,7 +95,7 @@ func TestNewHandler(t *testing.T) {
 	})
 
 	t.Run("Invalid requests cause an error", func(t *testing.T) {
-		handler := NewHandler(localIA, testInterfaces(), zeroCallTasks(mctrl))
+		handler := NewHandler(localIA, testInterfaces(t), zeroCallTasks(mctrl))
 
 		tests := []struct {
 			msg string
@@ -142,9 +143,11 @@ func TestNewHandler(t *testing.T) {
 	})
 }
 
-func testInterfaces() *ifstate.Interfaces {
+func testInterfaces(t *testing.T) *ifstate.Interfaces {
 	infoMap := topology.IfInfoMap{localIF: topology.IFInfo{IA: originIA}}
-	return ifstate.NewInterfaces(infoMap, ifstate.Config{})
+	intfs := ifstate.NewInterfaces(infoMap, ifstate.Config{KeepaliveTimeout: time.Nanosecond})
+	require.True(t, intfs.Get(localIF).Revoke(), "must revoke interface")
+	return intfs
 }
 
 func zeroCallTasks(mctrl *gomock.Controller) StateChangeTasks {