~samwhited/xmpp

ref: affc89735c067e99de17a291f216736adefd95df xmpp/component/component_test.go -rw-r--r-- 5.1 KiB
affc8973Sam Whited component: use a net.Pipe in tests 1 year, 1 month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright 2017 The Mellium Contributors.
// Use of this source code is governed by the BSD 2-clause
// license that can be found in the LICENSE file.

package component_test

import (
	"bytes"
	"context"
	"encoding/xml"
	"fmt"
	"io"
	"net"
	"reflect"
	"strings"
	"sync"
	"testing"

	"mellium.im/xmpp/component"
	"mellium.im/xmpp/jid"
	"mellium.im/xmpp/stream"
)

const header = `<?xml version="1.0" encoding="UTF-8"?>`

// some is a sentinal error that represents that some error must occur.
type some struct{}

func (some) Error() string { return "Anything" }

type componentClientTest struct {
	server string
	client string
	err    error
}

var componentClientTests = [...]componentClientTest{
	0: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net'>`,
		err:    some{}, // missing ID attr
	},
	1: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'>`,
		err:    &xml.SyntaxError{Line: 1, Msg: "unexpected EOF"},
	},
	2: {
		server: xml.Header + `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'><handshake></handshake>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>32532c0f7dbf1253c095b18b18e36d38d94c1256</handshake>`,
		err:    some{}, // don't allow whitespace
	},
	3: {
		server: header + header + `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'><handshake></handshake>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>32532c0f7dbf1253c095b18b18e36d38d94c1256</handshake>`,
		err:    some{}, // allow only a single XML header
	},
	4: {
		server: `<stream xmlns='jabber:component:accept' from='example.net' id='1234'><handshake></handshake>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>32532c0f7dbf1253c095b18b18e36d38d94c1256</handshake>`,
		err:    some{}, // must start with stream:stream
	},
	5: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'>test`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>32532c0f7dbf1253c095b18b18e36d38d94c1256</handshake>`,
		err:    some{}, // expect ack or error
	},
	6: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'><error></error>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>32532c0f7dbf1253c095b18b18e36d38d94c1256</handshake>`,
		err:    stream.NotAuthorized, // expect not authorized if error reported
	},
	7: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'><wrong/>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>32532c0f7dbf1253c095b18b18e36d38d94c1256</handshake>`,
		err:    some{}, // expect ack or error
	},
	8: {
		server: header + `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'><handshake></handshake>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>32532c0f7dbf1253c095b18b18e36d38d94c1256</handshake>`,
		err:    nil,
	},
	9: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'><handshake></handshake>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>32532c0f7dbf1253c095b18b18e36d38d94c1256</handshake>`,
		err:    nil,
	},
}

func TestComponent(t *testing.T) {
	addr := jid.MustParse("test@example.net")
	for i, tc := range componentClientTests {
		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
			ctx, cancel := context.WithCancel(context.Background())
			defer cancel()

			var outLock sync.Mutex
			out := new(bytes.Buffer)

			clientConn, serverConn := net.Pipe()

			go func() {
				io.Copy(serverConn, strings.NewReader(tc.server))
				serverConn.Close()
			}()

			outLock.Lock()
			go func() {
				defer outLock.Unlock()
				io.Copy(out, serverConn)
			}()

			_, err := component.NewClientSession(ctx, addr, []byte("secret"), clientConn, false)
			if _, ok := tc.err.(some); (ok && err == nil) || (!ok && !reflect.DeepEqual(err, tc.err)) {
				t.Fatalf("Unexpected error, got='%v' want='%v'", err, tc.err)
			}
			clientConn.Close()
			if err != nil {
				return
			}

			outLock.Lock()
			if o := out.String(); o[:len(tc.client)] != tc.client {
				t.Errorf("Unexpected output:\nGot:\n`%s`\nWant:\n`%s`\n", o, tc.client)
			}
		})
	}
}