194 lines
4.4 KiB
Go
194 lines
4.4 KiB
Go
|
package dht
|
||
|
|
||
|
import (
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/zeebo/bencode"
|
||
|
)
|
||
|
|
||
|
func TestPing(t *testing.T) {
|
||
|
dhtNodeID := newRandomBitmap()
|
||
|
testNodeID := newRandomBitmap()
|
||
|
|
||
|
conn := newTestUDPConn("127.0.0.1:21217")
|
||
|
|
||
|
dht := New(&Config{Address: ":21216", NodeID: dhtNodeID.Hex()})
|
||
|
dht.conn = conn
|
||
|
dht.listen()
|
||
|
go dht.runHandler()
|
||
|
|
||
|
messageID := newRandomBitmap().RawString()
|
||
|
|
||
|
data, err := bencode.EncodeBytes(map[string]interface{}{
|
||
|
headerTypeField: requestType,
|
||
|
headerMessageIDField: messageID,
|
||
|
headerNodeIDField: testNodeID.RawString(),
|
||
|
headerPayloadField: "ping",
|
||
|
headerArgsField: []string{},
|
||
|
})
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
conn.toRead <- testUDPPacket{addr: conn.addr, data: data}
|
||
|
timer := time.NewTimer(3 * time.Second)
|
||
|
|
||
|
select {
|
||
|
case <-timer.C:
|
||
|
t.Error("timeout")
|
||
|
case resp := <-conn.writes:
|
||
|
var response map[string]interface{}
|
||
|
err := bencode.DecodeBytes(resp.data, &response)
|
||
|
if err != nil {
|
||
|
t.Error(err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if len(response) != 4 {
|
||
|
t.Errorf("expected 4 response fields, got %d", len(response))
|
||
|
}
|
||
|
|
||
|
_, ok := response[headerTypeField]
|
||
|
if !ok {
|
||
|
t.Error("missing type field")
|
||
|
} else {
|
||
|
rType, ok := response[headerTypeField].(int64)
|
||
|
if !ok {
|
||
|
t.Error("type is not an integer")
|
||
|
} else if rType != responseType {
|
||
|
t.Error("unexpected response type")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_, ok = response[headerMessageIDField]
|
||
|
if !ok {
|
||
|
t.Error("missing message id field")
|
||
|
} else {
|
||
|
rMessageID, ok := response[headerMessageIDField].(string)
|
||
|
if !ok {
|
||
|
t.Error("message ID is not a string")
|
||
|
} else if rMessageID != messageID {
|
||
|
t.Error("unexpected message ID")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_, ok = response[headerNodeIDField]
|
||
|
if !ok {
|
||
|
t.Error("missing node id field")
|
||
|
} else {
|
||
|
rNodeID, ok := response[headerNodeIDField].(string)
|
||
|
if !ok {
|
||
|
t.Error("node ID is not a string")
|
||
|
} else if rNodeID != dhtNodeID.RawString() {
|
||
|
t.Error("unexpected node ID")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_, ok = response[headerPayloadField]
|
||
|
if !ok {
|
||
|
t.Error("missing payload field")
|
||
|
} else {
|
||
|
rNodeID, ok := response[headerPayloadField].(string)
|
||
|
if !ok {
|
||
|
t.Error("payload is not a string")
|
||
|
} else if rNodeID != pingSuccessResponse {
|
||
|
t.Error("did not pong")
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestStore(t *testing.T) {
|
||
|
dhtNodeID := newRandomBitmap()
|
||
|
testNodeID := newRandomBitmap()
|
||
|
|
||
|
conn := newTestUDPConn("127.0.0.1:21217")
|
||
|
|
||
|
dht := New(&Config{Address: ":21216", NodeID: dhtNodeID.Hex()})
|
||
|
dht.conn = conn
|
||
|
dht.listen()
|
||
|
go dht.runHandler()
|
||
|
|
||
|
messageID := newRandomBitmap().RawString()
|
||
|
idToStore := newRandomBitmap().RawString()
|
||
|
|
||
|
data, err := bencode.EncodeBytes(map[string]interface{}{
|
||
|
headerTypeField: requestType,
|
||
|
headerMessageIDField: messageID,
|
||
|
headerNodeIDField: testNodeID.RawString(),
|
||
|
headerPayloadField: "store",
|
||
|
headerArgsField: []string{idToStore},
|
||
|
})
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
conn.toRead <- testUDPPacket{addr: conn.addr, data: data}
|
||
|
timer := time.NewTimer(3 * time.Second)
|
||
|
|
||
|
select {
|
||
|
case <-timer.C:
|
||
|
t.Error("timeout")
|
||
|
case resp := <-conn.writes:
|
||
|
var response map[string]interface{}
|
||
|
err := bencode.DecodeBytes(resp.data, &response)
|
||
|
if err != nil {
|
||
|
t.Error(err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if len(response) != 4 {
|
||
|
t.Errorf("expected 4 response fields, got %d", len(response))
|
||
|
}
|
||
|
|
||
|
_, ok := response[headerTypeField]
|
||
|
if !ok {
|
||
|
t.Error("missing type field")
|
||
|
} else {
|
||
|
rType, ok := response[headerTypeField].(int64)
|
||
|
if !ok {
|
||
|
t.Error("type is not an integer")
|
||
|
} else if rType != responseType {
|
||
|
t.Error("unexpected response type")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_, ok = response[headerMessageIDField]
|
||
|
if !ok {
|
||
|
t.Error("missing message id field")
|
||
|
} else {
|
||
|
rMessageID, ok := response[headerMessageIDField].(string)
|
||
|
if !ok {
|
||
|
t.Error("message ID is not a string")
|
||
|
} else if rMessageID != messageID {
|
||
|
t.Error("unexpected message ID")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_, ok = response[headerNodeIDField]
|
||
|
if !ok {
|
||
|
t.Error("missing node id field")
|
||
|
} else {
|
||
|
rNodeID, ok := response[headerNodeIDField].(string)
|
||
|
if !ok {
|
||
|
t.Error("node ID is not a string")
|
||
|
} else if rNodeID != dhtNodeID.RawString() {
|
||
|
t.Error("unexpected node ID")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_, ok = response[headerPayloadField]
|
||
|
if !ok {
|
||
|
t.Error("missing payload field")
|
||
|
} else {
|
||
|
rNodeID, ok := response[headerPayloadField].(string)
|
||
|
if !ok {
|
||
|
t.Error("payload is not a string")
|
||
|
} else if rNodeID != storeSuccessResponse {
|
||
|
t.Error("did not return OK")
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|