New node ID:s contain four Luhn check digits and are grouped differently. Code uses NodeID type instead of string, so it's formatted homogenously everywhere.
229 lines
5.1 KiB
Go
229 lines
5.1 KiB
Go
// Copyright (C) 2014 Jakob Borg and other contributors. All rights reserved.
|
|
// Use of this source code is governed by an MIT-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
package protocol
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"testing"
|
|
"testing/quick"
|
|
)
|
|
|
|
var (
|
|
c0ID = NewNodeID([]byte{1})
|
|
c1ID = NewNodeID([]byte{2})
|
|
)
|
|
|
|
func TestHeaderFunctions(t *testing.T) {
|
|
f := func(ver, id, typ int) bool {
|
|
ver = int(uint(ver) % 16)
|
|
id = int(uint(id) % 4096)
|
|
typ = int(uint(typ) % 256)
|
|
h0 := header{ver, id, typ}
|
|
h1 := decodeHeader(encodeHeader(h0))
|
|
return h0 == h1
|
|
}
|
|
if err := quick.Check(f, nil); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestHeaderLayout(t *testing.T) {
|
|
var e, a uint32
|
|
|
|
// Version are the first four bits
|
|
e = 0xf0000000
|
|
a = encodeHeader(header{0xf, 0, 0})
|
|
if a != e {
|
|
t.Errorf("Header layout incorrect; %08x != %08x", a, e)
|
|
}
|
|
|
|
// Message ID are the following 12 bits
|
|
e = 0x0fff0000
|
|
a = encodeHeader(header{0, 0xfff, 0})
|
|
if a != e {
|
|
t.Errorf("Header layout incorrect; %08x != %08x", a, e)
|
|
}
|
|
|
|
// Type are the last 8 bits before reserved
|
|
e = 0x0000ff00
|
|
a = encodeHeader(header{0, 0, 0xff})
|
|
if a != e {
|
|
t.Errorf("Header layout incorrect; %08x != %08x", a, e)
|
|
}
|
|
}
|
|
|
|
func TestPing(t *testing.T) {
|
|
ar, aw := io.Pipe()
|
|
br, bw := io.Pipe()
|
|
|
|
c0 := NewConnection(c0ID, ar, bw, nil).(wireFormatConnection).next.(*rawConnection)
|
|
c1 := NewConnection(c1ID, br, aw, nil).(wireFormatConnection).next.(*rawConnection)
|
|
|
|
if ok := c0.ping(); !ok {
|
|
t.Error("c0 ping failed")
|
|
}
|
|
if ok := c1.ping(); !ok {
|
|
t.Error("c1 ping failed")
|
|
}
|
|
}
|
|
|
|
func TestPingErr(t *testing.T) {
|
|
e := errors.New("something broke")
|
|
|
|
for i := 0; i < 12; i++ {
|
|
for j := 0; j < 12; j++ {
|
|
m0 := newTestModel()
|
|
m1 := newTestModel()
|
|
|
|
ar, aw := io.Pipe()
|
|
br, bw := io.Pipe()
|
|
eaw := &ErrPipe{PipeWriter: *aw, max: i, err: e}
|
|
ebw := &ErrPipe{PipeWriter: *bw, max: j, err: e}
|
|
|
|
c0 := NewConnection(c0ID, ar, ebw, m0).(wireFormatConnection).next.(*rawConnection)
|
|
NewConnection(c1ID, br, eaw, m1)
|
|
|
|
res := c0.ping()
|
|
if (i < 4 || j < 4) && res {
|
|
t.Errorf("Unexpected ping success; i=%d, j=%d", i, j)
|
|
} else if (i >= 8 && j >= 8) && !res {
|
|
t.Errorf("Unexpected ping fail; i=%d, j=%d", i, j)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// func TestRequestResponseErr(t *testing.T) {
|
|
// e := errors.New("something broke")
|
|
|
|
// var pass bool
|
|
// for i := 0; i < 48; i++ {
|
|
// for j := 0; j < 38; j++ {
|
|
// m0 := newTestModel()
|
|
// m0.data = []byte("response data")
|
|
// m1 := newTestModel()
|
|
|
|
// ar, aw := io.Pipe()
|
|
// br, bw := io.Pipe()
|
|
// eaw := &ErrPipe{PipeWriter: *aw, max: i, err: e}
|
|
// ebw := &ErrPipe{PipeWriter: *bw, max: j, err: e}
|
|
|
|
// NewConnection(c0ID, ar, ebw, m0, nil)
|
|
// c1 := NewConnection(c1ID, br, eaw, m1, nil).(wireFormatConnection).next.(*rawConnection)
|
|
|
|
// d, err := c1.Request("default", "tn", 1234, 5678)
|
|
// if err == e || err == ErrClosed {
|
|
// t.Logf("Error at %d+%d bytes", i, j)
|
|
// if !m1.isClosed() {
|
|
// t.Fatal("c1 not closed")
|
|
// }
|
|
// if !m0.isClosed() {
|
|
// t.Fatal("c0 not closed")
|
|
// }
|
|
// continue
|
|
// }
|
|
// if err != nil {
|
|
// t.Fatal(err)
|
|
// }
|
|
// if string(d) != "response data" {
|
|
// t.Fatalf("Incorrect response data %q", string(d))
|
|
// }
|
|
// if m0.repo != "default" {
|
|
// t.Fatalf("Incorrect repo %q", m0.repo)
|
|
// }
|
|
// if m0.name != "tn" {
|
|
// t.Fatalf("Incorrect name %q", m0.name)
|
|
// }
|
|
// if m0.offset != 1234 {
|
|
// t.Fatalf("Incorrect offset %d", m0.offset)
|
|
// }
|
|
// if m0.size != 5678 {
|
|
// t.Fatalf("Incorrect size %d", m0.size)
|
|
// }
|
|
// t.Logf("Pass at %d+%d bytes", i, j)
|
|
// pass = true
|
|
// }
|
|
// }
|
|
// if !pass {
|
|
// t.Fatal("Never passed")
|
|
// }
|
|
// }
|
|
|
|
func TestVersionErr(t *testing.T) {
|
|
m0 := newTestModel()
|
|
m1 := newTestModel()
|
|
|
|
ar, aw := io.Pipe()
|
|
br, bw := io.Pipe()
|
|
|
|
c0 := NewConnection(c0ID, ar, bw, m0).(wireFormatConnection).next.(*rawConnection)
|
|
NewConnection(c1ID, br, aw, m1)
|
|
|
|
c0.xw.WriteUint32(encodeHeader(header{
|
|
version: 2,
|
|
msgID: 0,
|
|
msgType: 0,
|
|
}))
|
|
c0.flush()
|
|
|
|
if !m1.isClosed() {
|
|
t.Error("Connection should close due to unknown version")
|
|
}
|
|
}
|
|
|
|
func TestTypeErr(t *testing.T) {
|
|
m0 := newTestModel()
|
|
m1 := newTestModel()
|
|
|
|
ar, aw := io.Pipe()
|
|
br, bw := io.Pipe()
|
|
|
|
c0 := NewConnection(c0ID, ar, bw, m0).(wireFormatConnection).next.(*rawConnection)
|
|
NewConnection(c1ID, br, aw, m1)
|
|
|
|
c0.xw.WriteUint32(encodeHeader(header{
|
|
version: 0,
|
|
msgID: 0,
|
|
msgType: 42,
|
|
}))
|
|
c0.flush()
|
|
|
|
if !m1.isClosed() {
|
|
t.Error("Connection should close due to unknown message type")
|
|
}
|
|
}
|
|
|
|
func TestClose(t *testing.T) {
|
|
m0 := newTestModel()
|
|
m1 := newTestModel()
|
|
|
|
ar, aw := io.Pipe()
|
|
br, bw := io.Pipe()
|
|
|
|
c0 := NewConnection(c0ID, ar, bw, m0).(wireFormatConnection).next.(*rawConnection)
|
|
NewConnection(c1ID, br, aw, m1)
|
|
|
|
c0.close(nil)
|
|
|
|
<-c0.closed
|
|
if !m0.isClosed() {
|
|
t.Fatal("Connection should be closed")
|
|
}
|
|
|
|
// None of these should panic, some should return an error
|
|
|
|
if c0.ping() {
|
|
t.Error("Ping should not return true")
|
|
}
|
|
|
|
c0.Index("default", nil)
|
|
c0.Index("default", nil)
|
|
|
|
if _, err := c0.Request("default", "foo", 0, 0); err == nil {
|
|
t.Error("Request should return an error")
|
|
}
|
|
}
|