-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tests: reliable workers tests for reordering and acks (#60)
Tests for down and up workers in reliable service, covering reordering towards the upper layer and checking that any incoming packet is eventually ACKed. This PR also includes some needed test utilities that can be reused to exercise different parts of the system. --------- Co-authored-by: Simone Basso <bassosimone@gmail.com>
- Loading branch information
1 parent
86b9861
commit a3610f7
Showing
15 changed files
with
860 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
name: build-refactor | ||
# this action is covering internal/ tree with go1.21 | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
pull_request: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
short-tests: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: setup go | ||
uses: actions/setup-go@v2 | ||
with: | ||
go-version: '1.21' | ||
- name: Run short tests | ||
run: go test --short -cover ./internal/... | ||
|
||
gosec: | ||
runs-on: ubuntu-latest | ||
env: | ||
GO111MODULE: on | ||
steps: | ||
- name: Checkout Source | ||
uses: actions/checkout@v2 | ||
- name: Run Gosec security scanner | ||
uses: securego/gosec@master | ||
with: | ||
args: '-no-fail ./...' | ||
|
||
coverage-threshold: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: setup go | ||
uses: actions/setup-go@v2 | ||
with: | ||
go-version: '1.21' | ||
- name: Ensure coverage threshold | ||
run: make test-coverage-threshold-refactor | ||
|
||
integration: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: setup go | ||
uses: actions/setup-go@v2 | ||
with: | ||
go-version: '1.21' | ||
- name: run integration tests | ||
run: go test -v ./tests/integration | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,8 +8,6 @@ | |
*.swo | ||
*.pem | ||
*.ovpn | ||
/*.out | ||
data/* | ||
measurements/* | ||
coverage.out | ||
coverage-ping.out | ||
cov-threshold.out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package reliabletransport | ||
|
||
import ( | ||
"github.com/apex/log" | ||
"github.com/ooni/minivpn/internal/bytesx" | ||
"github.com/ooni/minivpn/internal/model" | ||
"github.com/ooni/minivpn/internal/runtimex" | ||
"github.com/ooni/minivpn/internal/session" | ||
"github.com/ooni/minivpn/internal/workers" | ||
) | ||
|
||
// | ||
// Common utilities for tests in this package. | ||
// | ||
|
||
// initManagers initializes a workers manager and a session manager. | ||
func initManagers() (*workers.Manager, *session.Manager) { | ||
w := workers.NewManager(log.Log) | ||
s, err := session.NewManager(log.Log) | ||
runtimex.PanicOnError(err, "cannot create session manager") | ||
return w, s | ||
} | ||
|
||
// newRandomSessionID returns a random session ID to initialize mock sessions. | ||
func newRandomSessionID() model.SessionID { | ||
b, err := bytesx.GenRandomBytes(8) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return model.SessionID(b) | ||
} | ||
|
||
func ackSetFromInts(s []int) *ackSet { | ||
acks := make([]model.PacketID, 0) | ||
for _, i := range s { | ||
acks = append(acks, model.PacketID(i)) | ||
} | ||
return newACKSet(acks...) | ||
} | ||
|
||
func ackSetFromRange(start, total int) *ackSet { | ||
acks := make([]model.PacketID, 0) | ||
for i := 0; i < total; i++ { | ||
acks = append(acks, model.PacketID(start+i)) | ||
} | ||
return newACKSet(acks...) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
package reliabletransport | ||
|
||
import ( | ||
"slices" | ||
"testing" | ||
"time" | ||
|
||
"github.com/apex/log" | ||
"github.com/ooni/minivpn/internal/model" | ||
"github.com/ooni/minivpn/internal/vpntest" | ||
) | ||
|
||
// test that everything that is received from below is eventually ACKed to the sender. | ||
func TestReliable_ACK(t *testing.T) { | ||
|
||
log.SetLevel(log.DebugLevel) | ||
|
||
type args struct { | ||
inputSequence []string | ||
start int | ||
wantacks int | ||
} | ||
|
||
tests := []struct { | ||
name string | ||
args args | ||
}{ | ||
{ | ||
name: "ten ordered packets in", | ||
args: args{ | ||
inputSequence: []string{ | ||
"[1] CONTROL_V1 +1ms", | ||
"[2] CONTROL_V1 +1ms", | ||
"[3] CONTROL_V1 +1ms", | ||
"[4] CONTROL_V1 +1ms", | ||
"[5] CONTROL_V1 +1ms", | ||
"[6] CONTROL_V1 +1ms", | ||
"[7] CONTROL_V1 +1ms", | ||
"[8] CONTROL_V1 +1ms", | ||
"[9] CONTROL_V1 +1ms", | ||
"[10] CONTROL_V1 +1ms", | ||
}, | ||
start: 1, | ||
wantacks: 10, | ||
}, | ||
}, | ||
{ | ||
name: "five ordered packets with offset", | ||
args: args{ | ||
inputSequence: []string{ | ||
"[100] CONTROL_V1 +1ms", | ||
"[101] CONTROL_V1 +1ms", | ||
"[102] CONTROL_V1 +1ms", | ||
"[103] CONTROL_V1 +1ms", | ||
"[104] CONTROL_V1 +1ms", | ||
}, | ||
start: 100, | ||
wantacks: 5, | ||
}, | ||
}, | ||
{ | ||
name: "five reversed packets", | ||
args: args{ | ||
inputSequence: []string{ | ||
"[5] CONTROL_V1 +1ms", | ||
"[4] CONTROL_V1 +1ms", | ||
"[3] CONTROL_V1 +1ms", | ||
"[2] CONTROL_V1 +1ms", | ||
"[1] CONTROL_V1 +1ms", | ||
}, | ||
start: 1, | ||
wantacks: 5, | ||
}, | ||
}, | ||
{ | ||
name: "ten unordered packets with duplicates", | ||
args: args{ | ||
inputSequence: []string{ | ||
"[5] CONTROL_V1 +1ms", | ||
"[1] CONTROL_V1 +1ms", | ||
"[5] CONTROL_V1 +1ms", | ||
"[2] CONTROL_V1 +1ms", | ||
"[1] CONTROL_V1 +1ms", | ||
"[4] CONTROL_V1 +1ms", | ||
"[2] CONTROL_V1 +1ms", | ||
"[3] CONTROL_V1 +1ms", | ||
"[3] CONTROL_V1 +1ms", | ||
"[4] CONTROL_V1 +1ms", | ||
}, | ||
start: 1, | ||
wantacks: 5, | ||
}, | ||
}, | ||
/* | ||
{ | ||
name: "a burst of packets", | ||
args: args{ | ||
inputSequence: []string{ | ||
"[5] CONTROL_V1 +1ms", | ||
"[1] CONTROL_V1 +1ms", | ||
"[3] CONTROL_V1 +1ms", | ||
"[2] CONTROL_V1 +1ms", | ||
"[4] CONTROL_V1 +1ms", | ||
}, | ||
start: 1, | ||
wantacks: 5, | ||
}, | ||
}, | ||
*/ | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
s := &Service{} | ||
|
||
// just to properly initialize it, we don't care about these | ||
s.ControlToReliable = make(chan *model.Packet) | ||
// this one up to control/tls also needs to be buffered because otherwise | ||
// we'll block on the receiver when delivering up. | ||
reliableToControl := make(chan *model.Packet, 1024) | ||
s.ReliableToControl = &reliableToControl | ||
|
||
// the only two channels we're going to be testing on this test | ||
// we want to buffer enough to be safe writing to them. | ||
dataIn := make(chan *model.Packet, 1024) | ||
dataOut := make(chan *model.Packet, 1024) | ||
|
||
s.MuxerToReliable = dataIn // up | ||
s.DataOrControlToMuxer = &dataOut // down | ||
|
||
workers, session := initManagers() | ||
|
||
t0 := time.Now() | ||
|
||
// let the workers pump up the jam! | ||
s.StartWorkers(log.Log, workers, session) | ||
|
||
writer := vpntest.NewPacketWriter(dataIn) | ||
|
||
// initialize a mock session ID for our peer | ||
peerSessionID := newRandomSessionID() | ||
|
||
writer.RemoteSessionID = model.SessionID(session.LocalSessionID()) | ||
writer.LocalSessionID = peerSessionID | ||
session.SetRemoteSessionID(peerSessionID) | ||
|
||
go writer.WriteSequence(tt.args.inputSequence) | ||
|
||
reader := vpntest.NewPacketReader(dataOut) | ||
witness := vpntest.NewWitness(reader) | ||
|
||
if ok := witness.VerifyNumberOfACKs(tt.args.start, tt.args.wantacks, t0); !ok { | ||
got := len(witness.Log().ACKs()) | ||
t.Errorf("TestACK: got = %v, want %v", got, tt.args.wantacks) | ||
} | ||
gotAckSet := ackSetFromInts(witness.Log().ACKs()).sorted() | ||
wantAckSet := ackSetFromRange(tt.args.start, tt.args.wantacks).sorted() | ||
|
||
if !slices.Equal(gotAckSet, wantAckSet) { | ||
t.Errorf("TestACK: got = %v, want %v", gotAckSet, wantAckSet) | ||
|
||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.