ae691ada79
I've decided instead to release a minimum viable product for v0.7.0 and get some feedback from the community, and most importantly some motivation as well to be able to keep working on magnetico as it currently feels like a Sisyphean where the development seem to never going to end...
232 lines
6.6 KiB
Go
232 lines
6.6 KiB
Go
package mainline
|
|
|
|
import (
|
|
"bytes"
|
|
"net"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/anacrolix/torrent/bencode"
|
|
)
|
|
|
|
var codecTest_validInstances = []struct {
|
|
data []byte
|
|
msg Message
|
|
}{
|
|
// ping Query:
|
|
{
|
|
data: []byte("d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t2:aa1:y1:qe"),
|
|
msg: Message{
|
|
T: []byte("aa"),
|
|
Y: "q",
|
|
Q: "ping",
|
|
A: QueryArguments{
|
|
ID: []byte("abcdefghij0123456789"),
|
|
},
|
|
},
|
|
},
|
|
// ping or announce_peer Response:
|
|
// Also, includes NUL and EOT characters as transaction ID (`t`).
|
|
{
|
|
data: []byte("d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:\x00\x041:y1:re"),
|
|
msg: Message{
|
|
T: []byte("\x00\x04"),
|
|
Y: "r",
|
|
R: ResponseValues{
|
|
ID: []byte("mnopqrstuvwxyz123456"),
|
|
},
|
|
},
|
|
},
|
|
// find_node Query:
|
|
{
|
|
data: []byte("d1:ad2:id20:abcdefghij01234567896:target20:mnopqrstuvwxyz123456e1:q9:find_node1:t2:\x09\x0a1:y1:qe"),
|
|
msg: Message{
|
|
T: []byte("\x09\x0a"),
|
|
Y: "q",
|
|
Q: "find_node",
|
|
A: QueryArguments{
|
|
ID: []byte("abcdefghij0123456789"),
|
|
Target: []byte("mnopqrstuvwxyz123456"),
|
|
},
|
|
},
|
|
},
|
|
// find_node Response with no nodes (`nodes` key still exists):
|
|
{
|
|
data: []byte("d1:rd2:id20:0123456789abcdefghij5:nodes0:e1:t2:aa1:y1:re"),
|
|
msg: Message{
|
|
T: []byte("aa"),
|
|
Y: "r",
|
|
R: ResponseValues{
|
|
ID: []byte("0123456789abcdefghij"),
|
|
Nodes: []CompactNodeInfo{},
|
|
},
|
|
},
|
|
},
|
|
// find_node Response with a single node:
|
|
{
|
|
data: []byte("d1:rd2:id20:0123456789abcdefghij5:nodes26:abcdefghijklmnopqrst\x8b\x82\x8e\xf5\x0cae1:t2:aa1:y1:re"),
|
|
msg: Message{
|
|
T: []byte("aa"),
|
|
Y: "r",
|
|
R: ResponseValues{
|
|
ID: []byte("0123456789abcdefghij"),
|
|
Nodes: []CompactNodeInfo{
|
|
{
|
|
ID: []byte("abcdefghijklmnopqrst"),
|
|
Addr: net.UDPAddr{IP: []byte("\x8b\x82\x8e\xf5"), Port: 3169, Zone: ""},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
// find_node Response with 8 nodes (all the same except the very last one):
|
|
{
|
|
data: []byte("d1:rd2:id20:0123456789abcdefghij5:nodes208:abcdefghijklmnopqrst\x8b\x82\x8e\xf5\x0caabcdefghijklmnopqrst\x8b\x82\x8e\xf5\x0caabcdefghijklmnopqrst\x8b\x82\x8e\xf5\x0caabcdefghijklmnopqrst\x8b\x82\x8e\xf5\x0caabcdefghijklmnopqrst\x8b\x82\x8e\xf5\x0caabcdefghijklmnopqrst\x8b\x82\x8e\xf5\x0caabcdefghijklmnopqrst\x8b\x82\x8e\xf5\x0cazyxwvutsrqponmlkjihg\xf5\x8e\x82\x8b\x1b\x13e1:t2:aa1:y1:re"),
|
|
msg: Message{
|
|
T: []byte("aa"),
|
|
Y: "r",
|
|
R: ResponseValues{
|
|
ID: []byte("0123456789abcdefghij"),
|
|
Nodes: []CompactNodeInfo{
|
|
{
|
|
ID: []byte("abcdefghijklmnopqrst"),
|
|
Addr: net.UDPAddr{IP: []byte("\x8b\x82\x8e\xf5"), Port: 3169, Zone: ""},
|
|
},
|
|
{
|
|
ID: []byte("abcdefghijklmnopqrst"),
|
|
Addr: net.UDPAddr{IP: []byte("\x8b\x82\x8e\xf5"), Port: 3169, Zone: ""},
|
|
},
|
|
{
|
|
ID: []byte("abcdefghijklmnopqrst"),
|
|
Addr: net.UDPAddr{IP: []byte("\x8b\x82\x8e\xf5"), Port: 3169, Zone: ""},
|
|
},
|
|
{
|
|
ID: []byte("abcdefghijklmnopqrst"),
|
|
Addr: net.UDPAddr{IP: []byte("\x8b\x82\x8e\xf5"), Port: 3169, Zone: ""},
|
|
},
|
|
{
|
|
ID: []byte("abcdefghijklmnopqrst"),
|
|
Addr: net.UDPAddr{IP: []byte("\x8b\x82\x8e\xf5"), Port: 3169, Zone: ""},
|
|
},
|
|
{
|
|
ID: []byte("abcdefghijklmnopqrst"),
|
|
Addr: net.UDPAddr{IP: []byte("\x8b\x82\x8e\xf5"), Port: 3169, Zone: ""},
|
|
},
|
|
{
|
|
ID: []byte("abcdefghijklmnopqrst"),
|
|
Addr: net.UDPAddr{IP: []byte("\x8b\x82\x8e\xf5"), Port: 3169, Zone: ""},
|
|
},
|
|
{
|
|
ID: []byte("zyxwvutsrqponmlkjihg"),
|
|
Addr: net.UDPAddr{IP: []byte("\xf5\x8e\x82\x8b"), Port: 6931, Zone: ""},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
// get_peers Query:
|
|
{
|
|
data: []byte("d1:ad2:id20:abcdefghij01234567899:info_hash20:mnopqrstuvwxyz123456e1:q9:get_peers1:t2:aa1:y1:qe"),
|
|
msg: Message{
|
|
T: []byte("aa"),
|
|
Y: "q",
|
|
Q: "get_peers",
|
|
A: QueryArguments{
|
|
ID: []byte("abcdefghij0123456789"),
|
|
InfoHash: []byte("mnopqrstuvwxyz123456"),
|
|
},
|
|
},
|
|
},
|
|
// get_peers Response with 2 peers (`values`):
|
|
{
|
|
data: []byte("d1:rd2:id20:abcdefghij01234567895:token8:aoeusnth6:valuesl6:axje.u6:idhtnmee1:t2:aa1:y1:re"),
|
|
msg: Message{
|
|
T: []byte("aa"),
|
|
Y: "r",
|
|
R: ResponseValues{
|
|
ID: []byte("abcdefghij0123456789"),
|
|
Token: []byte("aoeusnth"),
|
|
Values: []CompactPeer{
|
|
{IP: []byte("axje"), Port: 11893},
|
|
{IP: []byte("idht"), Port: 28269},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
// get_peers Response with 2 closest nodes (`nodes`):
|
|
{
|
|
data: []byte("d1:rd2:id20:abcdefghij01234567895:nodes52:abcdefghijklmnopqrst\x8b\x82\x8e\xf5\x0cazyxwvutsrqponmlkjihg\xf5\x8e\x82\x8b\x1b\x135:token8:aoeusnthe1:t2:aa1:y1:re"),
|
|
msg: Message{
|
|
T: []byte("aa"),
|
|
Y: "r",
|
|
R: ResponseValues{
|
|
ID: []byte("abcdefghij0123456789"),
|
|
Token: []byte("aoeusnth"),
|
|
Nodes: []CompactNodeInfo{
|
|
{
|
|
ID: []byte("abcdefghijklmnopqrst"),
|
|
Addr: net.UDPAddr{IP: []byte("\x8b\x82\x8e\xf5"), Port: 3169, Zone: ""},
|
|
},
|
|
{
|
|
ID: []byte("zyxwvutsrqponmlkjihg"),
|
|
Addr: net.UDPAddr{IP: []byte("\xf5\x8e\x82\x8b"), Port: 6931, Zone: ""},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
// announce_peer Query without optional `implied_port` argument:
|
|
{
|
|
data: []byte("d1:ad2:id20:abcdefghij01234567899:info_hash20:mnopqrstuvwxyz1234564:porti6881e5:token8:aoeusnthe1:q13:announce_peer1:t2:aa1:y1:qe"),
|
|
msg: Message{
|
|
T: []byte("aa"),
|
|
Y: "q",
|
|
Q: "announce_peer",
|
|
A: QueryArguments{
|
|
ID: []byte("abcdefghij0123456789"),
|
|
InfoHash: []byte("mnopqrstuvwxyz123456"),
|
|
Port: 6881,
|
|
Token: []byte("aoeusnth"),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
data: []byte("d1:eli201e23:A Generic Error Ocurrede1:t2:aa1:y1:ee"),
|
|
msg: Message{
|
|
T: []byte("aa"),
|
|
Y: "e",
|
|
E: Error{Code: 201, Message: []byte("A Generic Error Ocurred")},
|
|
},
|
|
},
|
|
// TODO: Test Error where E.Message is an empty string, and E.Message contains invalid Unicode characters.
|
|
// TODO: Add announce_peer Query with optional `implied_port` argument.
|
|
}
|
|
|
|
func TestUnmarshal(t *testing.T) {
|
|
for i, instance := range codecTest_validInstances {
|
|
msg := Message{}
|
|
err := bencode.Unmarshal(instance.data, &msg)
|
|
if err != nil {
|
|
t.Errorf("Error while unmarshalling valid data #%d: %v", i+1, err)
|
|
continue
|
|
}
|
|
if reflect.DeepEqual(msg, instance.msg) != true {
|
|
t.Errorf("Valid data #%d unmarshalled wrong!\n\tGot : %+v\n\tExpected: %+v",
|
|
i+1, msg, instance.msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMarshal(t *testing.T) {
|
|
for i, instance := range codecTest_validInstances {
|
|
data, err := bencode.Marshal(instance.msg)
|
|
if err != nil {
|
|
t.Errorf("Error while marshalling valid msg #%d: %v", i+1, err)
|
|
}
|
|
if bytes.Equal(data, instance.data) != true {
|
|
t.Errorf("Valid msg #%d marshalled wrong!\n\tGot : %q\n\tExpected: %q",
|
|
i+1, data, instance.data)
|
|
}
|
|
}
|
|
}
|