Repository: scionproto/scion
Pull request #3717 (2020-04-17 13:37:11)

beacon: drop convey from tests
This PR drops all goconvey imports from go/cs/beacon*

<!-- 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/3717)
<!-- Reviewable:end -->



Patch:
diff --git a/go/cs/beacon/BUILD.bazel b/go/cs/beacon/BUILD.bazel
index 844b1b4b2..474048004 100644
--- a/go/cs/beacon/BUILD.bazel
+++ b/go/cs/beacon/BUILD.bazel
@@ -54,12 +54,12 @@ go_test(
         "//go/lib/ctrl/seg:go_default_library",
         "//go/lib/hiddenpath:go_default_library",
         "//go/lib/hiddenpath/hiddenpathtest:go_default_library",
+        "//go/lib/spath:go_default_library",
         "//go/lib/util:go_default_library",
         "//go/lib/xtest:go_default_library",
         "//go/lib/xtest/graph:go_default_library",
         "//go/proto:go_default_library",
         "@com_github_golang_mock//gomock: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/cs/beaconing/BUILD.bazel b/go/cs/beaconing/BUILD.bazel
index 2c57309a9..491e4fe7b 100644
--- a/go/cs/beaconing/BUILD.bazel
+++ b/go/cs/beaconing/BUILD.bazel
@@ -81,7 +81,6 @@ go_test(
         "//go/lib/xtest/graph:go_default_library",
         "//go/proto:go_default_library",
         "@com_github_golang_mock//gomock: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",
     ],


Test patch:
diff --git a/go/cs/beacon/beacondbtest/beacondbtest.go b/go/cs/beacon/beacondbtest/beacondbtest.go
index 48cba68af..578cf019d 100644
--- a/go/cs/beacon/beacondbtest/beacondbtest.go
+++ b/go/cs/beacon/beacondbtest/beacondbtest.go
@@ -102,7 +102,7 @@ func Test(t *testing.T, db Testable) {
 		return func(t *testing.T) {
 			ctrl := gomock.NewController(t)
 			defer ctrl.Finish()
-			prepareCtx, cancelF := context.WithTimeout(context.Background(), timeout)
+			prepareCtx, cancelF := context.WithTimeout(context.Background(), 2*timeout)
 			defer cancelF()
 			db.Prepare(t, prepareCtx)
 			test(t, ctrl, db)
diff --git a/go/cs/beacon/metrics_test.go b/go/cs/beacon/metrics_test.go
index 0c08d205b..f8b8c4e86 100644
--- a/go/cs/beacon/metrics_test.go
+++ b/go/cs/beacon/metrics_test.go
@@ -18,6 +18,8 @@ import (
 	"context"
 	"testing"
 
+	"github.com/stretchr/testify/require"
+
 	"github.com/scionproto/scion/go/cs/beacon"
 	"github.com/scionproto/scion/go/cs/beacon/beacondbsqlite"
 	"github.com/scionproto/scion/go/cs/beacon/beacondbtest"
@@ -34,7 +36,7 @@ type TestBackend struct {
 
 func (b *TestBackend) Prepare(t *testing.T, _ context.Context) {
 	db, err := beacondbsqlite.New("file::memory:", testIA)
-	xtest.FailOnErr(t, err)
+	require.NoError(t, err)
 	b.DB = beacon.DBWithMetrics("testdb", db)
 }
 
diff --git a/go/cs/beacon/policy_test.go b/go/cs/beacon/policy_test.go
index a2acc9fdf..7ddec8fe7 100644
--- a/go/cs/beacon/policy_test.go
+++ b/go/cs/beacon/policy_test.go
@@ -17,11 +17,12 @@ package beacon_test
 import (
 	"testing"
 
-	. "github.com/smartystreets/goconvey/convey"
+	"github.com/stretchr/testify/assert"
 
 	"github.com/scionproto/scion/go/cs/beacon"
 	"github.com/scionproto/scion/go/lib/addr"
 	"github.com/scionproto/scion/go/lib/ctrl/seg"
+	"github.com/scionproto/scion/go/lib/spath"
 	"github.com/scionproto/scion/go/lib/xtest"
 )
 
@@ -39,120 +40,119 @@ var (
 )
 
 func TestLoadPolicyFromYaml(t *testing.T) {
-	checkPolicy := func(p *beacon.Policy, t beacon.PolicyType) {
-		SoMsg("BestSetSize", p.BestSetSize, ShouldEqual, 6)
-		SoMsg("CandidateSetSize", p.CandidateSetSize, ShouldEqual, 20)
-		SoMsg("Type", p.Type, ShouldEqual, t)
-		SoMsg("MaxExpTime", *p.MaxExpTime, ShouldEqual, 42)
-		SoMsg("MaxHopsLength", p.Filter.MaxHopsLength, ShouldEqual, 8)
-		SoMsg("AsBlackList", p.Filter.AsBlackList, ShouldResemble, []addr.AS{ia110.A, ia111.A})
-		SoMsg("IsdBlackList", p.Filter.IsdBlackList, ShouldResemble, []addr.ISD{1, 2, 3})
-		SoMsg("AllowIsdLoop", *p.Filter.AllowIsdLoop, ShouldBeTrue)
-
+	tests := map[string]struct {
+		File         string
+		Type         beacon.PolicyType
+		ErrAssertion assert.ErrorAssertionFunc
+	}{
+		"policy with matching type": {
+			File:         "testdata/typedPolicy.yml",
+			Type:         beacon.PropPolicy,
+			ErrAssertion: assert.NoError,
+		},
+		"policy with wrong type": {
+			File:         "testdata/typedPolicy.yml",
+			Type:         beacon.UpRegPolicy,
+			ErrAssertion: assert.Error,
+		},
+		"policy without type": {
+			File:         "testdata/typedPolicy.yml",
+			Type:         beacon.PropPolicy,
+			ErrAssertion: assert.NoError,
+		},
 	}
-	Convey("Given a policy file with policy type set", t, func() {
-		fn := "testdata/typedPolicy.yml"
-		Convey("The policy is parsed correctly if the type matches", func() {
-			p, err := beacon.LoadPolicyFromYaml(fn, beacon.PropPolicy)
-			SoMsg("err", err, ShouldBeNil)
-			checkPolicy(p, beacon.PropPolicy)
-		})
-		Convey("An error is returned if the type does not match", func() {
-			_, err := beacon.LoadPolicyFromYaml(fn, beacon.UpRegPolicy)
-			SoMsg("err", err, ShouldNotBeNil)
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			p, err := beacon.LoadPolicyFromYaml(test.File, test.Type)
+			test.ErrAssertion(t, err)
+			if err != nil {
+				return
+			}
+			assert.Equal(t, 6, p.BestSetSize)
+			assert.Equal(t, 20, p.CandidateSetSize)
+			assert.Equal(t, test.Type, p.Type)
+			assert.Equal(t, spath.ExpTimeType(42), *p.MaxExpTime)
+			assert.Equal(t, 8, p.Filter.MaxHopsLength)
+			assert.Equal(t, []addr.AS{ia110.A, ia111.A}, p.Filter.AsBlackList)
+			assert.Equal(t, []addr.ISD{1, 2, 3}, p.Filter.IsdBlackList)
+			assert.True(t, *p.Filter.AllowIsdLoop)
 		})
-
-	})
-	Convey("Given a policy file with policy type unset", t, func() {
-		loadWithType := func(polType beacon.PolicyType) {
-			Convey(string("Load with type "+polType+" should succeed"), func() {
-				p, err := beacon.LoadPolicyFromYaml("testdata/policy.yml", polType)
-				SoMsg("err", err, ShouldBeNil)
-				checkPolicy(p, polType)
-			})
-		}
-		for _, t := range []beacon.PolicyType{beacon.PropPolicy, beacon.UpRegPolicy,
-			beacon.DownRegPolicy, beacon.CoreRegPolicy} {
-			loadWithType(t)
-		}
-	})
+	}
 }
 
 func TestFilterApply(t *testing.T) {
-	Convey("Given a filter", t, func() {
-		f := beacon.Filter{
-			MaxHopsLength: 2,
-			AsBlackList:   []addr.AS{ia112.A},
-			IsdBlackList:  []addr.ISD{2},
-			AllowIsdLoop:  &false_val,
-		}
-		testCases := []struct {
-			Name         string
-			Beacon       beacon.Beacon
-			Filter       *beacon.Filter
-			ShouldFilter bool
-		}{
-			{
-				Name:         "Accepted: [1-ff00:0:110, 1-ff00:0:111]",
-				Beacon:       newTestBeacon(ia110, ia111),
-				ShouldFilter: false,
-			},
-			{
-				Name:         "Too Long: [1-ff00:0:110, 1-ff00:0:111, 1-ff00:0:113]",
-				Beacon:       newTestBeacon(ia110, ia111, ia113),
-				ShouldFilter: true,
-			},
-			{
-				Name:         "Blacklisted AS: [1-ff00:0:112]",
-				Beacon:       newTestBeacon(ia112),
-				ShouldFilter: true,
-			},
-			{
-				Name:         "Blacklisted ISD[2-ff00:0:210]",
-				Beacon:       newTestBeacon(ia210),
-				ShouldFilter: true,
-			},
-			{
-				Name:         "AS Repeated [1-ff00:0:110, 1-ff00:0:110]",
-				Beacon:       newTestBeacon(ia110, ia110),
-				ShouldFilter: true,
-			},
-			{
-				Name:         "AS loop [1-ff00:0:110, 1-ff00:0:111, 1-ff00:0:113, 1-ff00:0:110]",
-				Beacon:       newTestBeacon(ia110, ia111, ia113, ia110),
-				Filter:       &beacon.Filter{MaxHopsLength: 8, AllowIsdLoop: &false_val},
-				ShouldFilter: true,
-			},
-			{
-				Name:         "ISD loop [1-ff00:0:110, 3-ff00:0:310, 3-ff00:0:311, 1-ff00:0:111]",
-				Beacon:       newTestBeacon(ia110, ia310, ia311, ia111),
-				Filter:       &beacon.Filter{MaxHopsLength: 8, AllowIsdLoop: &false_val},
-				ShouldFilter: true,
-			},
-			{
-				Name:         "ISD/AS Loop [1-ff00:0:110, 3-ff00:0:311, 1-ff00:0:110]",
-				Beacon:       newTestBeacon(ia110, ia311, ia110),
-				Filter:       &beacon.Filter{MaxHopsLength: 8, AllowIsdLoop: &true_val},
-				ShouldFilter: true,
-			},
-			{
-				Name:         "ISD Loop allowed [1-ff00:0:110, 3-ff00:0:311, 1-ff00:0:111]",
-				Beacon:       newTestBeacon(ia110, ia311, ia111),
-				Filter:       &beacon.Filter{MaxHopsLength: 8, AllowIsdLoop: &true_val},
-				ShouldFilter: false,
-			},
-		}
-
-		for _, test := range testCases {
-			Convey(test.Name, func() {
-				testFilter := f
-				if test.Filter != nil {
-					testFilter = *test.Filter
-				}
-				xtest.SoMsgError("filter", testFilter.Apply(test.Beacon), test.ShouldFilter)
-			})
-		}
-	})
+	defaultFilter := &beacon.Filter{
+		MaxHopsLength: 2,
+		AsBlackList:   []addr.AS{ia112.A},
+		IsdBlackList:  []addr.ISD{2},
+		AllowIsdLoop:  &false_val,
+	}
+	testCases := []struct {
+		Name         string
+		Beacon       beacon.Beacon
+		Filter       *beacon.Filter
+		ErrAssertion assert.ErrorAssertionFunc
+	}{
+		{
+			Name:         "Accepted: [1-ff00:0:110, 1-ff00:0:111]",
+			Beacon:       newTestBeacon(ia110, ia111),
+			Filter:       defaultFilter,
+			ErrAssertion: assert.NoError,
+		},
+		{
+			Name:         "Too Long: [1-ff00:0:110, 1-ff00:0:111, 1-ff00:0:113]",
+			Beacon:       newTestBeacon(ia110, ia111, ia113),
+			Filter:       defaultFilter,
+			ErrAssertion: assert.Error,
+		},
+		{
+			Name:         "Blacklisted AS: [1-ff00:0:112]",
+			Beacon:       newTestBeacon(ia112),
+			Filter:       defaultFilter,
+			ErrAssertion: assert.Error,
+		},
+		{
+			Name:         "Blacklisted ISD[2-ff00:0:210]",
+			Beacon:       newTestBeacon(ia210),
+			Filter:       defaultFilter,
+			ErrAssertion: assert.Error,
+		},
+		{
+			Name:         "AS Repeated [1-ff00:0:110, 1-ff00:0:110]",
+			Beacon:       newTestBeacon(ia110, ia110),
+			Filter:       defaultFilter,
+			ErrAssertion: assert.Error,
+		},
+		{
+			Name:         "AS loop [1-ff00:0:110, 1-ff00:0:111, 1-ff00:0:113, 1-ff00:0:110]",
+			Beacon:       newTestBeacon(ia110, ia111, ia113, ia110),
+			Filter:       &beacon.Filter{MaxHopsLength: 8, AllowIsdLoop: &false_val},
+			ErrAssertion: assert.Error,
+		},
+		{
+			Name:         "ISD loop [1-ff00:0:110, 3-ff00:0:310, 3-ff00:0:311, 1-ff00:0:111]",
+			Beacon:       newTestBeacon(ia110, ia310, ia311, ia111),
+			Filter:       &beacon.Filter{MaxHopsLength: 8, AllowIsdLoop: &false_val},
+			ErrAssertion: assert.Error,
+		},
+		{
+			Name:         "ISD/AS Loop [1-ff00:0:110, 3-ff00:0:311, 1-ff00:0:110]",
+			Beacon:       newTestBeacon(ia110, ia311, ia110),
+			Filter:       &beacon.Filter{MaxHopsLength: 8, AllowIsdLoop: &true_val},
+			ErrAssertion: assert.Error,
+		},
+		{
+			Name:         "ISD Loop allowed [1-ff00:0:110, 3-ff00:0:311, 1-ff00:0:111]",
+			Beacon:       newTestBeacon(ia110, ia311, ia111),
+			Filter:       &beacon.Filter{MaxHopsLength: 8, AllowIsdLoop: &true_val},
+			ErrAssertion: assert.NoError,
+		},
+	}
+	for _, test := range testCases {
+		t.Run(test.Name, func(t *testing.T) {
+			test.ErrAssertion(t, test.Filter.Apply(test.Beacon))
+		})
+	}
 }
 
 func TestFilterLoop(t *testing.T) {
@@ -161,46 +161,40 @@ func TestFilterLoop(t *testing.T) {
 		Beacon       beacon.Beacon
 		Next         addr.IA
 		AllowIsdLoop bool
-		ShouldFilter bool
+		ErrAssertion assert.ErrorAssertionFunc
 	}{
 		{
 			Name:         "AS Repeated [1-ff00:0:110, 1-ff00:0:110]",
 			Beacon:       newTestBeacon(ia110),
 			Next:         ia110,
-			ShouldFilter: true,
+			ErrAssertion: assert.Error,
 		},
 		{
 			Name:         "AS loop [1-ff00:0:110, 1-ff00:0:111, 1-ff00:0:113, 1-ff00:0:110]",
 			Beacon:       newTestBeacon(ia110, ia111, ia113, ia110),
-			ShouldFilter: true,
+			ErrAssertion: assert.Error,
 		},
 		{
 			Name:         "ISD loop [1-ff00:0:110, 3-ff00:0:310, 3-ff00:0:311, 1-ff00:0:111]",
 			Beacon:       newTestBeacon(ia110, ia310, ia311, ia111),
-			ShouldFilter: true,
+			ErrAssertion: assert.Error,
 		},
 		{
 			Name:         "ISD/AS Loop [1-ff00:0:110, 3-ff00:0:311, 1-ff00:0:110]",
 			Beacon:       newTestBeacon(ia110, ia311, ia110),
 			AllowIsdLoop: true,
-			ShouldFilter: true,
+			ErrAssertion: assert.Error,
 		},
 		{
 			Name:         "ISD Loop allowed [1-ff00:0:110, 3-ff00:0:311, 1-ff00:0:111]",
 			Beacon:       newTestBeacon(ia110, ia311, ia111),
 			AllowIsdLoop: true,
-			ShouldFilter: false,
+			ErrAssertion: assert.NoError,
 		},
 	}
 	for _, test := range testCases {
 		t.Run(test.Name, func(t *testing.T) {
-			if test.ShouldFilter {
-				if beacon.FilterLoop(test.Beacon, test.Next, test.AllowIsdLoop) == nil {
-					t.Errorf("Should filter")
-				}
-			} else {
-				xtest.FailOnErr(t, beacon.FilterLoop(test.Beacon, test.Next, test.AllowIsdLoop))
-			}
+			test.ErrAssertion(t, beacon.FilterLoop(test.Beacon, test.Next, test.AllowIsdLoop))
 		})
 	}
 }
diff --git a/go/cs/beacon/store_test.go b/go/cs/beacon/store_test.go
index 84dd6a77d..7492ad85a 100644
--- a/go/cs/beacon/store_test.go
+++ b/go/cs/beacon/store_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	"github.com/golang/mock/gomock"
+	"github.com/stretchr/testify/require"
 
 	"github.com/scionproto/scion/go/cs/beacon"
 	"github.com/scionproto/scion/go/cs/beacon/mock_beacon"
@@ -160,7 +161,7 @@ func testStoreSelection(t *testing.T,
 				DownReg: beacon.Policy{BestSetSize: test.bestSize},
 			}
 			store, err := beacon.NewBeaconStore(policies, db)
-			xtest.FailOnErr(t, err)
+			require.NoError(t, err)
 			db.EXPECT().CandidateBeacons(gomock.Any(), gomock.Any(), gomock.Any(),
 				addr.IA{}).DoAndReturn(
 				func(_ ...interface{}) (<-chan beacon.BeaconOrErr, error) {
@@ -326,7 +327,7 @@ func testCoreStoreSelection(t *testing.T,
 				CoreReg: beacon.Policy{BestSetSize: test.bestSize},
 			}
 			store, err := beacon.NewCoreBeaconStore(policies, db)
-			xtest.FailOnErr(t, err)
+			require.NoError(t, err)
 			// respFunc serves beacons on the returned channel.
 			type respFunc func(_ ...interface{}) (<-chan beacon.BeaconOrErr, error)
 			// responder is a factory that generates a function serving the specified beacons.
diff --git a/go/cs/beaconing/extender_test.go b/go/cs/beaconing/extender_test.go
index c9bb59f60..a91affae4 100644
--- a/go/cs/beaconing/extender_test.go
+++ b/go/cs/beaconing/extender_test.go
@@ -22,7 +22,8 @@ import (
 	"time"
 
 	"github.com/golang/mock/gomock"
-	. "github.com/smartystreets/goconvey/convey"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 
 	"github.com/scionproto/scion/go/cs/beacon"
 	"github.com/scionproto/scion/go/cs/ifstate"
@@ -36,17 +37,16 @@ import (
 	"github.com/scionproto/scion/go/lib/scrypto"
 	"github.com/scionproto/scion/go/lib/spath"
 	"github.com/scionproto/scion/go/lib/util"
-	"github.com/scionproto/scion/go/lib/xtest"
 	"github.com/scionproto/scion/go/lib/xtest/graph"
 	"github.com/scionproto/scion/go/proto"
 )
 
 func TestExtenderExtend(t *testing.T) {
 	topoProvider := itopotest.TopoProviderFromFile(t, topoNonCore)
-	mac, err := scrypto.InitMac(make(common.RawBytes, 16))
-	xtest.FailOnErr(t, err)
+	mac, err := scrypto.InitMac(make([]byte, 16))
+	require.NoError(t, err)
 	pub, priv, err := scrypto.GenKeyPair(scrypto.Ed25519)
-	xtest.FailOnErr(t, err)
+	require.NoError(t, err)
 
 	segDesc := []common.IFIDType{graph.If_120_X_111_B}
 	peer := graph.If_111_C_121_X
@@ -56,48 +56,51 @@ func TestExtenderExtend(t *testing.T) {
 		inIfid        common.IFIDType
 		egIfid        common.IFIDType
 		inactivePeers []common.IFIDType
-		err           bool
+		errAssertion  assert.ErrorAssertionFunc
 	}{
 		{
-			name:   "First hop, InIfid 0",
-			egIfid: graph.If_111_A_112_X,
+			name:         "First hop, InIfid 0",
+			egIfid:       graph.If_111_A_112_X,
+			errAssertion: assert.NoError,
 		},
 		{
-			name:   "First hop, EgIfid 0",
-			inIfid: graph.If_111_B_120_X,
-			err:    true,
+			name:         "First hop, EgIfid 0",
+			inIfid:       graph.If_111_B_120_X,
+			errAssertion: assert.Error,
 		},
 		{
-			name: "First hop, InIfid 0, EgIfid 0",
-			err:  true,
+			name:         "First hop, InIfid 0, EgIfid 0",
+			errAssertion: assert.Error,
 		},
 		{
-			name:   "First hop, both set",
-			inIfid: graph.If_111_B_120_X,
-			egIfid: graph.If_111_A_112_X,
-			err:    true,
+			name:         "First hop, both set",
+			inIfid:       graph.If_111_B_120_X,
+			egIfid:       graph.If_111_A_112_X,
+			errAssertion: assert.Error,
 		},
 		{
-			name:   "Second hop, InIfid 0",
-			seg:    segDesc,
-			egIfid: graph.If_111_A_112_X,
-			err:    true,
+			name:         "Second hop, InIfid 0",
+			seg:          segDesc,
+			egIfid:       graph.If_111_A_112_X,
+			errAssertion: assert.Error,
 		},
 		{
-			name:   "Second hop, EgIfid 0",
-			seg:    segDesc,
-			inIfid: graph.If_111_B_120_X,
+			name:         "Second hop, EgIfid 0",
+			seg:          segDesc,
+			inIfid:       graph.If_111_B_120_X,
+			errAssertion: assert.NoError,
 		},
 		{
-			name: "Second hop, InIfid 0, EgIfid 0",
-			seg:  segDesc,
-			err:  true,
+			name:         "Second hop, InIfid 0, EgIfid 0",
+			seg:          segDesc,
+			errAssertion: assert.Error,
 		},
 		{
-			name:   "Second hop, both set",
-			seg:    segDesc,
-			inIfid: graph.If_111_B_120_X,
-			egIfid: graph.If_111_A_112_X,
+			name:         "Second hop, both set",
+			seg:          segDesc,
+			inIfid:       graph.If_111_B_120_X,
+			egIfid:       graph.If_111_A_112_X,
+			errAssertion: assert.NoError,
 		},
 		{
 			name:          "Ignore provided, but inactive peer",
@@ -105,10 +108,11 @@ func TestExtenderExtend(t *testing.T) {
 			inIfid:        graph.If_111_B_120_X,
 			egIfid:        graph.If_111_A_112_X,
 			inactivePeers: []common.IFIDType{graph.If_111_B_211_A},
+			errAssertion:  assert.NoError,
 		},
 	}
 	for _, test := range tests {
-		Convey("Extend handles "+test.name+" correctly", t, func() {
+		t.Run(test.name, func(t *testing.T) {
 			mctrl := gomock.NewController(t)
 			defer mctrl.Finish()
 			g := graph.NewDefaultGraph(mctrl)
@@ -124,69 +128,66 @@ func TestExtenderExtend(t *testing.T) {
 				Intfs:         intfs,
 				GetMaxExpTime: maxExpTimeFactory(beacon.DefaultMaxExpTime),
 			}.new()
-			SoMsg("err", err, ShouldBeNil)
+			require.NoError(t, err)
 			// Create path segment from description, if available.
 			pseg, err := seg.NewSeg(&spath.InfoField{ISD: 1, TsInt: util.TimeToSecs(time.Now())})
 			if len(test.seg) > 0 {
 				pseg = testBeacon(g, test.seg).Segment
 			}
-			xtest.FailOnErr(t, err)
+			require.NoError(t, err)
 			// Extend the segment.
 			err = ext.extend(pseg, test.inIfid, test.egIfid, append(test.inactivePeers, peer))
-			xtest.SoMsgError("err", err, test.err)
+			test.errAssertion(t, err)
 			if err != nil {
 				return
 			}
-			Convey("Segment can be validated", func() {
-				err := pseg.Validate(seg.ValidateBeacon)
-				if test.egIfid == 0 {
-					err = pseg.Validate(seg.ValidateSegment)
-				}
-				SoMsg("err", err, ShouldBeNil)
-			})
 
-			Convey("Segment is verifiable", func() {
-				err := pseg.VerifyASEntry(context.Background(),
-					segVerifier(pub), pseg.MaxAEIdx())
-				SoMsg("err", err, ShouldBeNil)
-			})
+			if test.egIfid == 0 {
+				assert.NoError(t, pseg.Validate(seg.ValidateSegment))
+			} else {
+				assert.NoError(t, pseg.Validate(seg.ValidateBeacon))
+			}
+
+			err = pseg.VerifyASEntry(context.Background(), segVerifier(pub), pseg.MaxAEIdx())
+			require.NoError(t, err)
+
 			entry := pseg.ASEntries[pseg.MaxAEIdx()]
-			Convey("AS entry is correct", func() {
-				SoMsg("ChainVer", entry.CertVer, ShouldEqual, 42)
-				SoMsg("TRCVer", entry.TrcVer, ShouldEqual, 84)
-				SoMsg("IfIDSize", entry.IfIDSize, ShouldEqual, DefaultIfidSize)
-				SoMsg("MTU", entry.MTU, ShouldEqual, 1337)
-				SoMsg("IA", entry.IA(), ShouldResemble, topoProvider.Get().IA())
+			t.Run("AS entry", func(t *testing.T) {
+				assert.Equal(t, scrypto.Version(42), entry.CertVer)
+				assert.Equal(t, scrypto.Version(84), entry.TrcVer)
+				assert.Equal(t, uint8(DefaultIfidSize), entry.IfIDSize)
+				assert.Equal(t, uint16(1337), entry.MTU)
+				assert.Equal(t, topoProvider.Get().IA(), entry.IA())
 				// Checks that inactive peers are ignored, even when provided.
-				SoMsg("HopEntries length", len(entry.HopEntries), ShouldEqual, 2)
+				assert.Len(t, entry.HopEntries, 2)
 			})
 			infoF, err := pseg.InfoF()
-			SoMsg("infoF err", err, ShouldBeNil)
+			require.NoError(t, err)
 
-			Convey("Hop entry is correct", func() {
-				var prev common.RawBytes
+			t.Run("hop entry check", func(t *testing.T) {
+				var prev []byte
 				// The extended hop entry is not the first one.
 				if pseg.MaxAEIdx() > 0 {
 					prev = pseg.ASEntries[pseg.MaxAEIdx()-1].HopEntries[0].RawHopField
 				}
-				testHopEntry(entry.HopEntries[0], intfs, test.inIfid, test.egIfid)
+				testHopEntry(t, entry.HopEntries[0], intfs, test.inIfid, test.egIfid)
 				testHopF(t, entry.HopEntries[0], mac, infoF.TsInt, ext.cfg.Signer.Meta().ExpTime,
 					test.inIfid, test.egIfid, prev)
 			})
 
-			Convey("Peer entry is correct", func() {
-				testHopEntry(entry.HopEntries[1], intfs, peer, test.egIfid)
+			t.Run("peer entry is correct", func(t *testing.T) {
+				testHopEntry(t, entry.HopEntries[1], intfs, peer, test.egIfid)
 				testHopF(t, entry.HopEntries[1], mac, infoF.TsInt, ext.cfg.Signer.Meta().ExpTime,
 					peer, test.egIfid, entry.HopEntries[0].RawHopField)
 			})
 		})
 	}
-	Convey("The maximum expiration time is respected", t, func() {
+	t.Run("the maximum expiration time is respected", func(t *testing.T) {
 		mctrl := gomock.NewController(t)
 		defer mctrl.Finish()
 		g := graph.NewDefaultGraph(mctrl)
 		intfs := ifstate.NewInterfaces(topoProvider.Get().IFInfoMap(), ifstate.Config{})
-		xtest.FailOnErr(t, err)
+		require.NoError(t, err)
 		intfs.Get(graph.If_111_B_120_X).Activate(graph.If_120_X_111_B)
 		ext, err := ExtenderConf{
 			MTU:           1337,
@@ -195,85 +196,119 @@ func TestExtenderExtend(t *testing.T) {
 			GetMaxExpTime: maxExpTimeFactory(1),
 			Intfs:         intfs,
 		}.new()
-		SoMsg("err", err, ShouldBeNil)
+		require.NoError(t, err)
 		pseg := testBeacon(g, segDesc).Segment
 		err = ext.extend(pseg, graph.If_111_B_120_X, 0, []common.IFIDType{})
-		SoMsg("err", err, ShouldBeNil)
+		require.NoError(t, err)
 		hopF, err := pseg.ASEntries[pseg.MaxAEIdx()].HopEntries[0].HopField()
-		SoMsg("err", err, ShouldBeNil)
-		SoMsg("exp", hopF.ExpTime, ShouldEqual, 1)
+		require.NoError(t, err)
+		assert.Equal(t, spath.ExpTimeType(1), hopF.ExpTime)
 
 	})
-	Convey("Segment is not extended on error", t, func() {
-		mctrl := gomock.NewController(t)
-		defer mctrl.Finish()
-		g := graph.NewDefaultGraph(mctrl)
-		intfs := ifstate.NewInterfaces(topoProvider.Get().IFInfoMap(), ifstate.Config{})
-		xtest.FailOnErr(t, err)
-		ext, err := ExtenderConf{
-			MTU:           1337,
-			Signer:        testSigner(t, priv, topoProvider.Get().IA()),
-			Mac:           mac,
-			Intfs:         intfs,
-			GetMaxExpTime: maxExpTimeFactory(beacon.DefaultMaxExpTime),
-		}.new()
-		SoMsg("err", err, ShouldBeNil)
-		pseg := testBeacon(g, segDesc).Segment
-		Convey("Unknown Ingress IFID", func() {
-			err := ext.extend(pseg, 10, 0, []common.IFIDType{})
-			SoMsg("err", err, ShouldNotBeNil)
-		})
-		Convey("Inactive Ingress IFID", func() {
-			err := ext.extend(pseg, graph.If_111_B_120_X, 0, []common.IFIDType{})
-			SoMsg("err", err, ShouldNotBeNil)
-		})
-		Convey("Invalid Ingress Remote IFID", func() {
-			intfs.Get(graph.If_111_B_120_X).Activate(0)
-			err := ext.extend(pseg, graph.If_111_B_120_X, 0, []common.IFIDType{})
-			SoMsg("err", err, ShouldNotBeNil)
-		})
-		Convey("Unknown Egress IFID", func() {
-			intfs.Get(graph.If_111_B_120_X).Activate(graph.If_120_X_111_B)
-			err := ext.extend(pseg, graph.If_111_B_120_X, 10, []common.IFIDType{})
-			SoMsg("err", err, ShouldNotBeNil)
-		})
-		Convey("Inactive Egress IFID", func() {
-			intfs.Get(graph.If_111_B_120_X).Activate(graph.If_120_X_111_B)
-			err := ext.extend(pseg, graph.If_111_B_120_X, graph.If_111_A_112_X, []common.IFIDType{})
-			SoMsg("err", err, ShouldNotBeNil)
-		})
-		Convey("Invalid Egress Remote IFID", func() {
-			intfs.Get(graph.If_111_B_120_X).Activate(graph.If_120_X_111_B)
-			intfs.Get(graph.If_111_A_112_X).Activate(0)
-			err := ext.extend(pseg, graph.If_111_B_120_X, graph.If_111_A_112_X, []common.IFIDType{})
-			SoMsg("err", err, ShouldNotBeNil)
-		})
-		Convey("Signer expiration is to small", func() {
-			signer, err := trust.NewSigner(
-				trust.SignerConf{
-					ChainVer: 42,
-					TRCVer:   84,
-					Validity: scrypto.Validity{NotAfter: util.UnixTime{Time: time.Now()}},
-					Key: keyconf.Key{
-						Type:      keyconf.PrivateKey,
-						Algorithm: scrypto.Ed25519,
-						Bytes:     priv,
-						ID:        keyconf.ID{IA: topoProvider.Get().IA()},
-					},
+	t.Run("segment is not extended on error", func(t *testing.T) {
+		defaultSigner := func(t *testing.T) infra.Signer {
+			return testSigner(t, priv, topoProvider.Get().IA())
+		}
+		tests := map[string]struct {
+			Signer         func(t *testing.T) infra.Signer
+			InIfID, EgIfID common.IFIDType
+			Activate       func(intfs *ifstate.Interfaces)
+		}{
+			"Unknown Ingress IFID": {
+				Signer:   defaultSigner,
+				InIfID:   10,
+				Activate: func(intfs *ifstate.Interfaces) {},
+			},
+			"Inactive Ingress IFID": {
+				Signer:   defaultSigner,
+				InIfID:   graph.If_111_B_120_X,
+				Activate: func(intfs *ifstate.Interfaces) {},
+			},
+			"Invalid Ingress Remote IFID": {
+				Signer: defaultSigner,
+				InIfID: graph.If_111_B_120_X,
+				Activate: func(intfs *ifstate.Interfaces) {
+					intfs.Get(graph.If_111_B_120_X).Activate(0)
 				},
-			)
-			SoMsg("err", err, ShouldBeNil)
-			ext.cfg.Signer = signer
-			intfs.Get(graph.If_111_B_120_X).Activate(graph.If_120_X_111_B)
-			err = ext.extend(pseg, graph.If_111_B_120_X, 0, []common.IFIDType{})
-			SoMsg("err", err, ShouldNotBeNil)
-		})
-		Convey("Signer fails", func() {
-			ext.cfg.Signer = &failSigner{ext.cfg.Signer}
-			intfs.Get(graph.If_111_B_120_X).Activate(graph.If_120_X_111_B)
-			err = ext.extend(pseg, graph.If_111_B_120_X, 0, []common.IFIDType{})
-			SoMsg("err", err, ShouldNotBeNil)
-		})
+			},
+			"Unknown Egress IFID": {
+				Signer: defaultSigner,
+				InIfID: graph.If_111_B_120_X,
+				EgIfID: 10,
+				Activate: func(intfs *ifstate.Interfaces) {
+					intfs.Get(graph.If_111_B_120_X).Activate(graph.If_120_X_111_B)
+				},
+			},
+			"Inactive Egress IFID": {
+				Signer: defaultSigner,
+				InIfID: graph.If_111_B_120_X,
+				EgIfID: graph.If_111_A_112_X,
+				Activate: func(intfs *ifstate.Interfaces) {
+					intfs.Get(graph.If_111_B_120_X).Activate(graph.If_120_X_111_B)
+				},
+			},
+			"Invalid Egress Remote IFID": {
+				Signer: defaultSigner,
+				InIfID: graph.If_111_B_120_X,
+				EgIfID: graph.If_111_A_112_X,
+				Activate: func(intfs *ifstate.Interfaces) {
+					intfs.Get(graph.If_111_B_120_X).Activate(graph.If_120_X_111_B)
+					intfs.Get(graph.If_111_A_112_X).Activate(0)
+				},
+			},
+			"Signer expiration is to small": {
+				Signer: func(t *testing.T) infra.Signer {
+					signer, err := trust.NewSigner(
+						trust.SignerConf{
+							ChainVer: 42,
+							TRCVer:   84,
+							Validity: scrypto.Validity{NotAfter: util.UnixTime{Time: time.Now()}},
+							Key: keyconf.Key{
+								Type:      keyconf.PrivateKey,
+								Algorithm: scrypto.Ed25519,
+								Bytes:     priv,
+								ID:        keyconf.ID{IA: topoProvider.Get().IA()},
+							},
+						},
+					)
+					require.NoError(t, err)
+					return signer
+				},
+				InIfID: graph.If_111_B_120_X,
+				Activate: func(intfs *ifstate.Interfaces) {
+					intfs.Get(graph.If_111_B_120_X).Activate(graph.If_120_X_111_B)
+				},
+			},
+			"Signer fails": {
+				Signer: func(t *testing.T) infra.Signer { return &failSigner{defaultSigner(t)} },
+				InIfID: graph.If_111_B_120_X,
+				Activate: func(intfs *ifstate.Interfaces) {
+					intfs.Get(graph.If_111_B_120_X).Activate(graph.If_120_X_111_B)
+				},
+			},
+		}
+		for name, test := range tests {
+			t.Run(name, func(t *testing.T) {
+				mctrl := gomock.NewController(t)
+				defer mctrl.Finish()
+				g := graph.NewDefaultGraph(mctrl)
+				intfs := ifstate.NewInterfaces(topoProvider.Get().IFInfoMap(), ifstate.Config{})
+				require.NoError(t, err)
+				test.Activate(intfs)
+
+				ext, err := ExtenderConf{
+					MTU:           1337,
+					Signer:        test.Signer(t),
+					Mac:           mac,
+					Intfs:         intfs,
+					GetMaxExpTime: maxExpTimeFactory(beacon.DefaultMaxExpTime),
+				}.new()
+				require.NoError(t, err)
+				pseg := testBeacon(g, segDesc).Segment
+				err = ext.extend(pseg, test.InIfID, test.EgIfID, []common.IFIDType{})
+				assert.Error(t, err)
+			})
+		}
 	})
 }
 
@@ -281,37 +316,40 @@ func TestExtenderExtend(t *testing.T) {
 // values. The inIfid and prev are different between that cons and peer hop
 // field.
 func testHopF(t *testing.T, hop *seg.HopEntry, mac hash.Hash, ts uint32, signerExpTime time.Time,
-	inIfid, egIfid common.IFIDType, prev common.RawBytes) {
+	inIfid, egIfid common.IFIDType, prev []byte) {
 
 	if prev != nil {
 		prev = prev[1:]
 	}
 	hopF, err := spath.HopFFromRaw(hop.RawHopField)
-	SoMsg("err", err, ShouldBeNil)
-	SoMsg("hopF.ConsIngress", hopF.ConsIngress, ShouldEqual, inIfid)
-	SoMsg("hopF.ConsEgress", hopF.ConsEgress, ShouldEqual, egIfid)
-	SoMsg("hopF.Mac", hopF.Verify(mac, ts, prev), ShouldBeNil)
+	require.NoError(t, err)
+	assert.Equal(t, inIfid, hopF.ConsIngress)
+	assert.Equal(t, egIfid, hopF.ConsEgress)
+	assert.NoError(t, hopF.Verify(mac, ts, prev))
 	expiry, err := spath.ExpTimeFromDuration(signerExpTime.Sub(util.SecsToTime(ts)), false)
-	xtest.FailOnErr(t, err)
-	SoMsg("hopF.ExpTime", hopF.ExpTime, ShouldEqual, expiry)
+	require.NoError(t, err)
+	assert.Equal(t, expiry, hopF.ExpTime)
 }
 
 // testHopEntry checks whether the hop entry contains the expected values. The
 // inIfid is different between cons and peer hop entries.
-func testHopEntry(hop *seg.HopEntry, intfs *ifstate.Interfaces, inIfid, egIfid common.IFIDType) {
+func testHopEntry(t *testing.T, hop *seg.HopEntry, intfs *ifstate.Interfaces,
+	inIfid, egIfid common.IFIDType) {
+
 	ia, ifid, mtu := addr.IA{}, common.IFIDType(0), uint16(0)
 	// Hop entries that are not first on the segment, must not
 	// contain zero values.
 	if inIfid != 0 {
 		intf := intfs.Get(inIfid)
-		SoMsg("Intf", intf, ShouldNotBeNil)
-		ia = intf.TopoInfo().IA
-		ifid = intf.TopoInfo().RemoteIFID
-		mtu = uint16(intf.TopoInfo().MTU)
+		if assert.NotNil(t, intf) {
+			ia = intf.TopoInfo().IA
+			ifid = intf.TopoInfo().RemoteIFID
+			mtu = uint16(intf.TopoInfo().MTU)
+		}
 	}
-	SoMsg("Hop.InIA", hop.InIA(), ShouldResemble, ia)
-	SoMsg("Hop.InIf", hop.RemoteInIF, ShouldEqual, ifid)
-	SoMsg("hop.InMTU", hop.InMTU, ShouldEqual, mtu)
+	assert.Equal(t, ia, hop.InIA())
+	assert.Equal(t, ifid, hop.RemoteInIF)
+	assert.Equal(t, mtu, hop.InMTU)
 	ia, ifid = addr.IA{}, common.IFIDType(0)
 	// Hop entries that are not last on the segment, must not
 	// contain zero values.
@@ -320,8 +358,8 @@ func testHopEntry(hop *seg.HopEntry, intfs *ifstate.Interfaces, inIfid, egIfid c
 		ia = intf.TopoInfo().IA
 		ifid = intf.TopoInfo().RemoteIFID
 	}
-	SoMsg("Hop.OutIA", hop.OutIA(), ShouldResemble, ia)
-	SoMsg("Hop.OutIf", hop.RemoteOutIF, ShouldResemble, ifid)
+	assert.Equal(t, ia, hop.OutIA())
+	assert.Equal(t, ifid, hop.RemoteOutIF)
 }
 
 type failSigner struct {
diff --git a/go/cs/beaconing/handler_test.go b/go/cs/beaconing/handler_test.go
index ca23e1a7c..ef7f80758 100644
--- a/go/cs/beaconing/handler_test.go
+++ b/go/cs/beaconing/handler_test.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/golang/mock/gomock"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 
 	"github.com/scionproto/scion/go/cs/beacon"
 	"github.com/scionproto/scion/go/cs/beaconing/mock_beaconing"
@@ -139,7 +140,7 @@ func TestNewHandler(t *testing.T) {
 		asEntry := pseg.ASEntries[pseg.MaxAEIdx()]
 		asEntry.RawIA = xtest.MustParseIA("1-ff00:0:111").IAInt()
 		raw, err := asEntry.Pack()
-		xtest.FailOnErr(t, err)
+		require.NoError(t, err)
 		pseg.RawASEntries[pseg.MaxAEIdx()].Blob = raw
 		res := handler.Handle(defaultTestReq(rw, pseg))
 		assert.Equal(t, res, infra.MetricsErrInvalid)
@@ -150,7 +151,7 @@ func TestNewHandler(t *testing.T) {
 		asEntry := pseg.ASEntries[pseg.MaxAEIdx()]
 		asEntry.HopEntries[0].RawOutIA = xtest.MustParseIA("1-ff00:0:111").IAInt()
 		raw, err := asEntry.Pack()
-		xtest.FailOnErr(t, err)
+		require.NoError(t, err)
 		pseg.RawASEntries[pseg.MaxAEIdx()].Blob = raw
 		res := handler.Handle(defaultTestReq(rw, pseg))
 		assert.Equal(t, res, infra.MetricsErrInvalid)
@@ -160,7 +161,7 @@ func TestNewHandler(t *testing.T) {
 		asEntry := pseg.ASEntries[pseg.MaxAEIdx()]
 		asEntry.HopEntries[0].RemoteOutIF = 42
 		raw, err := asEntry.Pack()
-		xtest.FailOnErr(t, err)
+		require.NoError(t, err)
 		pseg.RawASEntries[pseg.MaxAEIdx()].Blob = raw
 		res := handler.Handle(defaultTestReq(rw, pseg))
 		assert.Equal(t, res, infra.MetricsErrInvalid)
diff --git a/go/cs/beaconing/originator_test.go b/go/cs/beaconing/originator_test.go
index 66ddc6de7..c3ccd4c30 100644
--- a/go/cs/beaconing/originator_test.go
+++ b/go/cs/beaconing/originator_test.go
@@ -24,7 +24,8 @@ import (
 	"time"
 
 	"github.com/golang/mock/gomock"
-	. "github.com/smartystreets/goconvey/convey"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 
 	"github.com/scionproto/scion/go/cs/beacon"
 	"github.com/scionproto/scion/go/cs/ifstate"
@@ -49,11 +50,11 @@ const (
 func TestOriginatorRun(t *testing.T) {
 	topoProvider := itopotest.TopoProviderFromFile(t, topoCore)
 	mac, err := scrypto.InitMac(make(common.RawBytes, 16))
-	xtest.FailOnErr(t, err)
+	require.NoError(t, err)
 	pub, priv, err := scrypto.GenKeyPair(scrypto.Ed25519)
-	xtest.FailOnErr(t, err)
+	require.NoError(t, err)
 	signer := testSigner(t, priv, topoProvider.Get().IA())
-	Convey("Run originates ifid packets on all active core and child interfaces", t, func() {
+	t.Run("run originates ifid packets on all active interfaces", func(t *testing.T) {
 		mctrl := gomock.NewController(t)
 		defer mctrl.Finish()
 		intfs := ifstate.NewInterfaces(topoProvider.Get().IFInfoMap(), ifstate.Config{})
@@ -79,7 +80,7 @@ func TestOriginatorRun(t *testing.T) {
 				},
 			},
 		}.New()
-		xtest.FailOnErr(t, err)
+		require.NoError(t, err)
 		// Activate interfaces
 		intfs.Get(42).Activate(84)
 		intfs.Get(1129).Activate(82)
@@ -100,14 +101,14 @@ func TestOriginatorRun(t *testing.T) {
 		// Start beacon messages.
 		o.Run(nil)
 		for i, msg := range msgs {
-			Convey(fmt.Sprintf("Packet %d is correct", i), func() {
+			t.Run(fmt.Sprintf("Packet %d is correct", i), func(t *testing.T) {
 				checkMsg(t, msg, pub, topoProvider.Get().IFInfoMap())
 			})
 		}
 		// The second run should not cause any beacons to originate.
 		o.Run(nil)
 	})
-	Convey("Fast recovery", t, func() {
+	t.Run("Fast recovery", func(t *testing.T) {
 		mctrl := gomock.NewController(t)
 		defer mctrl.Finish()
 		intfs := ifstate.NewInterfaces(topoProvider.Get().IFInfoMap(), ifstate.Config{})
@@ -133,7 +134,7 @@ func TestOriginatorRun(t *testing.T) {
 				},
 			},
 		}.New()
-		xtest.FailOnErr(t, err)
+		require.NoError(t, err)
 		// Activate interfaces
 		intfs.Get(42).Activate(84)
 		intfs.Get(1129).Activate(82)
@@ -166,29 +167,29 @@ type msg struct {
 func checkMsg(t *testing.T, msg msg, pub common.RawBytes, infos topology.IfInfoMap) {
 	// Extract segment from the payload
 	spld, err := ctrl.NewSignedPldFromRaw(msg.pkt.Payload.(common.RawBytes))
-	SoMsg("SPldErr", err, ShouldBeNil)
+	require.NoError(t, err)
 	pld, err := spld.UnsafePld()
-	SoMsg("PldErr", err, ShouldBeNil)
+	require.NoError(t, err)
 	err = pld.Beacon.Parse()
-	SoMsg("ParseErr", err, ShouldBeNil)
+	require.NoError(t, err)
+
+	// Check the beacon is valid and verifiable.
 	pseg := pld.Beacon.Segment
-	Convey("Segment can be validated", func() {
-		err = pseg.Validate(seg.ValidateBeacon)
-		SoMsg("err", err, ShouldBeNil)
-	})
-	Convey("Segment can be verified", func() {
-		err = pseg.VerifyASEntry(context.Background(), segVerifier(pub), pseg.MaxAEIdx())
-		SoMsg("err", err, ShouldBeNil)
-	})
-	Convey("Beacon on correct interface", func() {
-		hopF, err := msg.pkt.Path.GetHopField(msg.pkt.Path.HopOff)
-		xtest.FailOnErr(t, err)
-		bHopF, err := pseg.ASEntries[pseg.MaxAEIdx()].HopEntries[0].HopField()
-		xtest.FailOnErr(t, err)
-		SoMsg("Egress", hopF.ConsEgress, ShouldEqual, bHopF.ConsEgress)
-		brAddr := infos[hopF.ConsEgress].InternalAddr
-		SoMsg("ov", msg.ov, ShouldResemble, brAddr)
-	})
+	assert.NoError(t, pseg.Validate(seg.ValidateBeacon))
+	assert.NoError(t, pseg.VerifyASEntry(context.Background(), segVerifier(pub), pseg.MaxAEIdx()))
+
+	// Extract the the first hop field from the constructed one hop path the
+	// beacon is sent on. We want to make sure that the beacon is sent on the
+	// correct egress interface.
+	hopF, err := msg.pkt.Path.GetHopField(msg.pkt.Path.HopOff)
+	require.NoError(t, err)
+	// Extract the hop field from the current AS entry to compare.
+	bHopF, err := pseg.ASEntries[pseg.MaxAEIdx()].HopEntries[0].HopField()
+	require.NoError(t, err)
+	// Check the interface matches.
+	assert.Equal(t, bHopF.ConsEgress, hopF.ConsEgress)
+	// Check that the beacon is sent to the correct border router.
+	assert.Equal(t, infos[hopF.ConsEgress].InternalAddr, msg.ov)
 }
 
 type segVerifier []byte
diff --git a/go/cs/beaconing/propagator_test.go b/go/cs/beaconing/propagator_test.go
index 1b12b45fa..9176c8ad8 100644
--- a/go/cs/beaconing/propagator_test.go
+++ b/go/cs/beaconing/propagator_test.go
@@ -23,7 +23,7 @@ import (
 	"time"
 
 	"github.com/golang/mock/gomock"
-	. "github.com/smartystreets/goconvey/convey"
+	"github.com/stretchr/testify/require"
 
 	"github.com/scionproto/scion/go/cs/beacon"
 	"github.com/scionproto/scion/go/cs/beaconing/mock_beaconing"
@@ -34,17 +34,16 @@ import (
 	"github.com/scionproto/scion/go/lib/scrypto"
 	"github.com/scionproto/scion/go/lib/snet"
 	"github.com/scionproto/scion/go/lib/snet/mock_snet"
-	"github.com/scionproto/scion/go/lib/xtest"
 	"github.com/scionproto/scion/go/lib/xtest/graph"
 )
 
 func TestPropagatorRun(t *testing.T) {
 	macProp, err := scrypto.InitMac(make(common.RawBytes, 16))
-	xtest.FailOnErr(t, err)
+	require.NoError(t, err)
 	macSender, err := scrypto.InitMac(make(common.RawBytes, 16))
-	xtest.FailOnErr(t, err)
+	require.NoError(t, err)
 	pub, priv, err := scrypto.GenKeyPair(scrypto.Ed25519)
-	xtest.FailOnErr(t, err)
+	require.NoError(t, err)
 
 	type test struct {
 		name     string
@@ -138,7 +137,7 @@ func TestPropagatorRun(t *testing.T) {
 		},
 	}
 	for _, test := range tests {
-		Convey(test.name, t, func() {
+		t.Run(test.name, func(t *testing.T) {
 			mctrl := gomock.NewController(t)
 			defer mctrl.Finish()
 			topoProvider := itopotest.TopoProviderFromFile(t, topoFile[test.core])
@@ -169,7 +168,7 @@ func TestPropagatorRun(t *testing.T) {
 				},
 			}
 			p, err := cfg.New()
-			SoMsg("err", err, ShouldBeNil)
+			require.NoError(t, err)
 			for ifid, remote := range allIntfs[test.core] {
 				if test.inactive[ifid] {
 					continue
@@ -202,7 +201,7 @@ func TestPropagatorRun(t *testing.T) {
 			)
 			p.Run(nil)
 			for i, msg := range msgs {
-				Convey(fmt.Sprintf("Packet %d is correct", i), func() {
+				t.Run(fmt.Sprintf("Packet %d is correct", i), func(t *testing.T) {
 					checkMsg(t, msg, pub, topoProvider.Get().IFInfoMap())
 				})
 			}
@@ -210,7 +209,7 @@ func TestPropagatorRun(t *testing.T) {
 			p.Run(nil)
 		})
 	}
-	Convey("Fast recovery", t, func() {
+	t.Run("Fast recovery", func(t *testing.T) {
 		mctrl := gomock.NewController(t)
 		defer mctrl.Finish()
 		topoProvider := itopotest.TopoProviderFromFile(t, topoCore)
@@ -241,7 +240,7 @@ func TestPropagatorRun(t *testing.T) {
 			},
 		}
 		p, err := cfg.New()
-		SoMsg("err", err, ShouldBeNil)
+		require.NoError(t, err)
 		for ifid, remote := range allIntfs[true] {
 			cfg.Config.Intfs.Get(ifid).Activate(remote)
 		}
diff --git a/go/cs/beaconstorage/beaconstoragetest/BUILD.bazel b/go/cs/beaconstorage/beaconstoragetest/BUILD.bazel
index e754982ea..29ca3c091 100644
--- a/go/cs/beaconstorage/beaconstoragetest/BUILD.bazel
+++ b/go/cs/beaconstorage/beaconstoragetest/BUILD.bazel
@@ -21,6 +21,7 @@ go_test(
         "//go/cs/beaconstorage:go_default_library",
         "//go/lib/config:go_default_library",
         "@com_github_burntsushi_toml//: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/cs/beaconstorage/beaconstoragetest/config_test.go b/go/cs/beaconstorage/beaconstoragetest/config_test.go
index 26c217208..49a10cce3 100644
--- a/go/cs/beaconstorage/beaconstoragetest/config_test.go
+++ b/go/cs/beaconstorage/beaconstoragetest/config_test.go
@@ -19,21 +19,20 @@ import (
 	"testing"
 
 	"github.com/BurntSushi/toml"
-	. "github.com/smartystreets/goconvey/convey"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 
 	"github.com/scionproto/scion/go/cs/beaconstorage"
 	"github.com/scionproto/scion/go/lib/config"
 )
 
 func TestBeaconDBConfSample(t *testing.T) {
-	Convey("Sample correct", t, func() {
-		var sample bytes.Buffer
-		var cfg beaconstorage.BeaconDBConf
-		cfg.Sample(&sample, nil, map[string]string{config.ID: "test"})
-		InitTestBeaconDBConf(&cfg)
-		meta, err := toml.Decode(sample.String(), &cfg)
-		SoMsg("err", err, ShouldBeNil)
-		SoMsg("unparsed", meta.Undecoded(), ShouldBeEmpty)
-		CheckTestBeaconDBConf(t, &cfg, "test")
-	})
+	var sample bytes.Buffer
+	var cfg beaconstorage.BeaconDBConf
+	cfg.Sample(&sample, nil, map[string]string{config.ID: "test"})
+	InitTestBeaconDBConf(&cfg)
+	meta, err := toml.Decode(sample.String(), &cfg)
+	require.NoError(t, err)
+	assert.Empty(t, meta.Undecoded())
+	CheckTestBeaconDBConf(t, &cfg, "test")
 }