1// Copyright (c) 2013-2016 The btcsuite developers
2// Use of this source code is governed by an ISC
3// license that can be found in the LICENSE file.
4
5package wire
6
7import (
8	"bytes"
9	"io"
10	"reflect"
11	"testing"
12
13	"github.com/davecgh/go-spew/spew"
14)
15
16// TestPing tests the MsgPing API against the latest protocol version.
17func TestPing(t *testing.T) {
18	pver := ProtocolVersion
19
20	// Ensure we get the same nonce back out.
21	nonce, err := RandomUint64()
22	if err != nil {
23		t.Errorf("RandomUint64: Error generating nonce: %v", err)
24	}
25	msg := NewMsgPing(nonce)
26	if msg.Nonce != nonce {
27		t.Errorf("NewMsgPing: wrong nonce - got %v, want %v",
28			msg.Nonce, nonce)
29	}
30
31	// Ensure the command is expected value.
32	wantCmd := "ping"
33	if cmd := msg.Command(); cmd != wantCmd {
34		t.Errorf("NewMsgPing: wrong command - got %v want %v",
35			cmd, wantCmd)
36	}
37
38	// Ensure max payload is expected value for latest protocol version.
39	wantPayload := uint32(8)
40	maxPayload := msg.MaxPayloadLength(pver)
41	if maxPayload != wantPayload {
42		t.Errorf("MaxPayloadLength: wrong max payload length for "+
43			"protocol version %d - got %v, want %v", pver,
44			maxPayload, wantPayload)
45	}
46}
47
48// TestPingBIP0031 tests the MsgPing API against the protocol version
49// BIP0031Version.
50func TestPingBIP0031(t *testing.T) {
51	// Use the protocol version just prior to BIP0031Version changes.
52	pver := BIP0031Version
53	enc := BaseEncoding
54
55	nonce, err := RandomUint64()
56	if err != nil {
57		t.Errorf("RandomUint64: Error generating nonce: %v", err)
58	}
59	msg := NewMsgPing(nonce)
60	if msg.Nonce != nonce {
61		t.Errorf("NewMsgPing: wrong nonce - got %v, want %v",
62			msg.Nonce, nonce)
63	}
64
65	// Ensure max payload is expected value for old protocol version.
66	wantPayload := uint32(0)
67	maxPayload := msg.MaxPayloadLength(pver)
68	if maxPayload != wantPayload {
69		t.Errorf("MaxPayloadLength: wrong max payload length for "+
70			"protocol version %d - got %v, want %v", pver,
71			maxPayload, wantPayload)
72	}
73
74	// Test encode with old protocol version.
75	var buf bytes.Buffer
76	err = msg.BtcEncode(&buf, pver, enc)
77	if err != nil {
78		t.Errorf("encode of MsgPing failed %v err <%v>", msg, err)
79	}
80
81	// Test decode with old protocol version.
82	readmsg := NewMsgPing(0)
83	err = readmsg.BtcDecode(&buf, pver, enc)
84	if err != nil {
85		t.Errorf("decode of MsgPing failed [%v] err <%v>", buf, err)
86	}
87
88	// Since this protocol version doesn't support the nonce, make sure
89	// it didn't get encoded and decoded back out.
90	if msg.Nonce == readmsg.Nonce {
91		t.Errorf("Should not get same nonce for protocol version %d", pver)
92	}
93}
94
95// TestPingCrossProtocol tests the MsgPing API when encoding with the latest
96// protocol version and decoding with BIP0031Version.
97func TestPingCrossProtocol(t *testing.T) {
98	nonce, err := RandomUint64()
99	if err != nil {
100		t.Errorf("RandomUint64: Error generating nonce: %v", err)
101	}
102	msg := NewMsgPing(nonce)
103	if msg.Nonce != nonce {
104		t.Errorf("NewMsgPing: wrong nonce - got %v, want %v",
105			msg.Nonce, nonce)
106	}
107
108	// Encode with latest protocol version.
109	var buf bytes.Buffer
110	err = msg.BtcEncode(&buf, ProtocolVersion, BaseEncoding)
111	if err != nil {
112		t.Errorf("encode of MsgPing failed %v err <%v>", msg, err)
113	}
114
115	// Decode with old protocol version.
116	readmsg := NewMsgPing(0)
117	err = readmsg.BtcDecode(&buf, BIP0031Version, BaseEncoding)
118	if err != nil {
119		t.Errorf("decode of MsgPing failed [%v] err <%v>", buf, err)
120	}
121
122	// Since one of the protocol versions doesn't support the nonce, make
123	// sure it didn't get encoded and decoded back out.
124	if msg.Nonce == readmsg.Nonce {
125		t.Error("Should not get same nonce for cross protocol")
126	}
127}
128
129// TestPingWire tests the MsgPing wire encode and decode for various protocol
130// versions.
131func TestPingWire(t *testing.T) {
132	tests := []struct {
133		in   MsgPing         // Message to encode
134		out  MsgPing         // Expected decoded message
135		buf  []byte          // Wire encoding
136		pver uint32          // Protocol version for wire encoding
137		enc  MessageEncoding // Message encoding format
138	}{
139		// Latest protocol version.
140		{
141			MsgPing{Nonce: 123123}, // 0x1e0f3
142			MsgPing{Nonce: 123123}, // 0x1e0f3
143			[]byte{0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00},
144			ProtocolVersion,
145			BaseEncoding,
146		},
147
148		// Protocol version BIP0031Version+1
149		{
150			MsgPing{Nonce: 456456}, // 0x6f708
151			MsgPing{Nonce: 456456}, // 0x6f708
152			[]byte{0x08, 0xf7, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00},
153			BIP0031Version + 1,
154			BaseEncoding,
155		},
156
157		// Protocol version BIP0031Version
158		{
159			MsgPing{Nonce: 789789}, // 0xc0d1d
160			MsgPing{Nonce: 0},      // No nonce for pver
161			[]byte{},               // No nonce for pver
162			BIP0031Version,
163			BaseEncoding,
164		},
165	}
166
167	t.Logf("Running %d tests", len(tests))
168	for i, test := range tests {
169		// Encode the message to wire format.
170		var buf bytes.Buffer
171		err := test.in.BtcEncode(&buf, test.pver, test.enc)
172		if err != nil {
173			t.Errorf("BtcEncode #%d error %v", i, err)
174			continue
175		}
176		if !bytes.Equal(buf.Bytes(), test.buf) {
177			t.Errorf("BtcEncode #%d\n got: %s want: %s", i,
178				spew.Sdump(buf.Bytes()), spew.Sdump(test.buf))
179			continue
180		}
181
182		// Decode the message from wire format.
183		var msg MsgPing
184		rbuf := bytes.NewReader(test.buf)
185		err = msg.BtcDecode(rbuf, test.pver, test.enc)
186		if err != nil {
187			t.Errorf("BtcDecode #%d error %v", i, err)
188			continue
189		}
190		if !reflect.DeepEqual(msg, test.out) {
191			t.Errorf("BtcDecode #%d\n got: %s want: %s", i,
192				spew.Sdump(msg), spew.Sdump(test.out))
193			continue
194		}
195	}
196}
197
198// TestPingWireErrors performs negative tests against wire encode and decode
199// of MsgPing to confirm error paths work correctly.
200func TestPingWireErrors(t *testing.T) {
201	pver := ProtocolVersion
202
203	tests := []struct {
204		in       *MsgPing        // Value to encode
205		buf      []byte          // Wire encoding
206		pver     uint32          // Protocol version for wire encoding
207		enc      MessageEncoding // Message encoding format
208		max      int             // Max size of fixed buffer to induce errors
209		writeErr error           // Expected write error
210		readErr  error           // Expected read error
211	}{
212		// Latest protocol version with intentional read/write errors.
213		{
214			&MsgPing{Nonce: 123123}, // 0x1e0f3
215			[]byte{0xf3, 0xe0, 0x01, 0x00},
216			pver,
217			BaseEncoding,
218			2,
219			io.ErrShortWrite,
220			io.ErrUnexpectedEOF,
221		},
222	}
223
224	t.Logf("Running %d tests", len(tests))
225	for i, test := range tests {
226		// Encode to wire format.
227		w := newFixedWriter(test.max)
228		err := test.in.BtcEncode(w, test.pver, test.enc)
229		if err != test.writeErr {
230			t.Errorf("BtcEncode #%d wrong error got: %v, want: %v",
231				i, err, test.writeErr)
232			continue
233		}
234
235		// Decode from wire format.
236		var msg MsgPing
237		r := newFixedReader(test.max, test.buf)
238		err = msg.BtcDecode(r, test.pver, test.enc)
239		if err != test.readErr {
240			t.Errorf("BtcDecode #%d wrong error got: %v, want: %v",
241				i, err, test.readErr)
242			continue
243		}
244	}
245}
246