forked from Unity-Technologies/go-ts3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmockserver_test.go
243 lines (212 loc) · 12.2 KB
/
mockserver_test.go
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
package ts3
import (
"bufio"
"io"
"net"
"strings"
"sync"
"testing"
"github.com/stretchr/testify/assert"
)
const (
cmdQuit = "quit"
banner = `Welcome to the TeamSpeak 3 ServerQuery interface, type "help" for a list of commands and "help <command>" for information on a specific command.`
errUnknownCmd = `error id=256 msg=command\snot\sfound`
errOK = `error id=0 msg=ok`
)
var (
commands = map[string]string{
"version": "version=3.0.12.2 build=1455547898 platform=FreeBSD",
"login": "",
"logout": "",
"use": "",
"serverlist": `virtualserver_id=1 virtualserver_port=10677 virtualserver_status=online virtualserver_clientsonline=1 virtualserver_queryclientsonline=1 virtualserver_maxclients=35 virtualserver_uptime=12345025 virtualserver_name=Server\s#1 virtualserver_autostart=1 virtualserver_machine_id=1 virtualserver_unique_identifier=uniq1|virtualserver_id=2 virtualserver_port=10617 virtualserver_status=online virtualserver_clientsonline=3 virtualserver_queryclientsonline=2 virtualserver_maxclients=10 virtualserver_uptime=3165117 virtualserver_name=Server\s#2 virtualserver_autostart=1 virtualserver_machine_id=1 virtualserver_unique_identifier=uniq2`,
"serverinfo": `virtualserver_antiflood_points_needed_command_block=150 virtualserver_antiflood_points_needed_ip_block=250 virtualserver_antiflood_points_tick_reduce=5 virtualserver_channel_temp_delete_delay_default=0 virtualserver_codec_encryption_mode=0 virtualserver_complain_autoban_count=5 virtualserver_complain_autoban_time=1200 virtualserver_complain_remove_time=3600 virtualserver_created=0 virtualserver_default_channel_admin_group=1 virtualserver_default_channel_group=4 virtualserver_default_server_group=5 virtualserver_download_quota=18446744073709551615 virtualserver_filebase=files virtualserver_flag_password=0 virtualserver_hostbanner_gfx_interval=0 virtualserver_hostbanner_gfx_url virtualserver_hostbanner_mode=0 virtualserver_hostbanner_url virtualserver_hostbutton_gfx_url virtualserver_hostbutton_tooltip=Multiplay\sGame\sServers virtualserver_hostbutton_url=http:\/\/www.multiplaygameservers.com virtualserver_hostmessage virtualserver_hostmessage_mode=0 virtualserver_icon_id=0 virtualserver_log_channel=0 virtualserver_log_client=0 virtualserver_log_filetransfer=0 virtualserver_log_permissions=1 virtualserver_log_query=0 virtualserver_log_server=0 virtualserver_max_download_total_bandwidth=18446744073709551615 virtualserver_max_upload_total_bandwidth=18446744073709551615 virtualserver_maxclients=32 virtualserver_min_android_version=0 virtualserver_min_client_version=0 virtualserver_min_clients_in_channel_before_forced_silence=100 virtualserver_min_ios_version=0 virtualserver_name=Test\sServer virtualserver_name_phonetic virtualserver_needed_identity_security_level=8 virtualserver_password virtualserver_priority_speaker_dimm_modificator=-18.0000 virtualserver_reserved_slots=0 virtualserver_status=template virtualserver_unique_identifier virtualserver_upload_quota=18446744073709551615 virtualserver_weblist_enabled=1 virtualserver_welcomemessage=Welcome\sto\sTeamSpeak,\scheck\s[URL]www.teamspeak.com[\/URL]\sfor\slatest\sinfos.`,
"servercreate": `sid=2 virtualserver_port=9988 token=eKnFZQ9EK7G7MhtuQB6+N2B1PNZZ6OZL3ycDp2OW`,
"serveridgetbyport": `server_id=1`,
"servergrouplist": `sgid=1 name=Guest\sServer\sQuery type=2 iconid=0 savedb=0 sortid=0 namemode=0 n_modifyp=0 n_member_addp=0 n_member_removep=0|sgid=2 name=Admin\sServer\sQuery type=2 iconid=500 savedb=1 sortid=0 namemode=0 n_modifyp=100 n_member_addp=100 n_member_removep=100`,
"privilegekeylist": `token=zTfamFVhiMEzhTl49KrOVYaMilHPDQEBQOJFh6qX token_type=0 token_id1=17395 token_id2=0 token_created=1499948005 token_description`,
"privilegekeyadd": `token=zTfamFVhiMEzhTl49KrOVYaMilHPgQEBQOJFh6qX`,
"serverdelete": "",
"serverstop": "",
"serverstart": "",
"serveredit": "",
"instanceinfo": "serverinstance_database_version=26 serverinstance_filetransfer_port=30033 serverinstance_max_download_total_bandwidth=18446744073709551615 serverinstance_max_upload_total_bandwidth=18446744073709551615 serverinstance_guest_serverquery_group=1 serverinstance_serverquery_flood_commands=50 serverinstance_serverquery_flood_time=3 serverinstance_serverquery_ban_time=600 serverinstance_template_serveradmin_group=3 serverinstance_template_serverdefault_group=5 serverinstance_template_channeladmin_group=1 serverinstance_template_channeldefault_group=4 serverinstance_permissions_version=19 serverinstance_pending_connections_per_ip=0",
"serverrequestconnectioninfo": "connection_filetransfer_bandwidth_sent=0 connection_filetransfer_bandwidth_received=0 connection_filetransfer_bytes_sent_total=617 connection_filetransfer_bytes_received_total=0 connection_packets_sent_total=926413 connection_bytes_sent_total=92911395 connection_packets_received_total=650335 connection_bytes_received_total=61940731 connection_bandwidth_sent_last_second_total=0 connection_bandwidth_sent_last_minute_total=0 connection_bandwidth_received_last_second_total=0 connection_bandwidth_received_last_minute_total=0 connection_connected_time=49408 connection_packetloss_total=0.0000 connection_ping=0.0000 connection_packets_sent_speech=320432180 connection_bytes_sent_speech=43805818511 connection_packets_received_speech=174885295 connection_bytes_received_speech=24127808273 connection_packets_sent_keepalive=55230363 connection_bytes_sent_keepalive=2264444883 connection_packets_received_keepalive=55149547 connection_bytes_received_keepalive=2316390993 connection_packets_sent_control=2376088 connection_bytes_sent_control=525691022 connection_packets_received_control=2376138 connection_bytes_received_control=227044870",
"channellist": "cid=499 pid=0 channel_order=0 channel_name=Default\\sChannel total_clients=1 channel_needed_subscribe_power=0",
"clientinfo": `cid=20 client_idle_time=28122 client_unique_identifier=P5H2hrN6+gpQI4n\/dXp3p17vtY0= client_nickname=Rabe85 client_version=3.0.0-alpha24\s[Build:\s8785]\s(UI:\s8785) client_platform=Windows client_input_muted=0 client_output_muted=0 client_outputonly_muted=0 client_input_hardware=1 client_output_hardware=1 client_default_channel=\/20 client_meta_data client_is_recording=0 client_version_sign=+\/BWvaeokGg4YkO1v3ouZB5vtIIgUZ5bM5cRfxBstfnHUdro2ja+5b+3sFUzEy8\/vvEISXVD6U95blTb638MCQ== client_security_hash client_login_name client_database_id=8 client_channel_group_id=8 client_servergroups=6,10 client_created=1503431624 client_lastconnected=1530383977 client_totalconnections=138 client_away=0 client_away_message client_type=0 client_flag_avatar=dd213abf2a94396ece544b22c4e56821 client_talk_power=75 client_talk_request=0 client_talk_request_msg client_description client_is_talker=0 client_month_bytes_uploaded=0 client_month_bytes_downloaded=0 client_total_bytes_uploaded=0 client_total_bytes_downloaded=3014720 client_is_priority_speaker=1 client_nickname_phonetic=rabeh client_needed_serverquery_view_power=75 client_default_token client_icon_id=0 client_is_channel_commander=1 client_country=DE client_channel_group_inherited_channel_id=20 client_badges=overwolf=0 client_base64HashClientUID=kdohhblmninnfhaecihcijemaigdnkdhgjllefed connection_filetransfer_bandwidth_sent=0 connection_filetransfer_bandwidth_received=0 connection_packets_sent_total=46880 connection_bytes_sent_total=6426774 connection_packets_received_total=14098 connection_bytes_received_total=1644574 connection_bandwidth_sent_last_second_total=81 connection_bandwidth_sent_last_minute_total=92 connection_bandwidth_received_last_second_total=83 connection_bandwidth_received_last_minute_total=97 connection_connected_time=2084247 connection_client_ip=83.123.45.6`,
"clientlist": "clid=5 cid=7 client_database_id=40 client_nickname=ScP client_type=0 client_away=1 client_away_message=not\\shere",
"clientdblist": "cldbid=7 client_unique_identifier=DZhdQU58qyooEK4Fr8Ly738hEmc= client_nickname=MuhChy client_created=1259147468 client_lastconnected=1259421233",
"whoami": "virtualserver_status=online virtualserver_id=18 virtualserver_unique_identifier=gNITtWtKs9+Uh3L4LKv8\\/YHsn5c= virtualserver_port=9987 client_id=94 client_channel_id=432 client_nickname=serveradmin\\sfrom\\s127.0.0.1:49725 client_database_id=1 client_login_name=serveradmin client_unique_identifier=serveradmin client_origin_server_id=0",
cmdQuit: "",
}
)
// newLockListener creates a new listener on the local IP.
func newLocalListener() (net.Listener, error) {
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
if l, err = net.Listen("tcp6", "[::1]:0"); err != nil {
return nil, err
}
}
return l, nil
}
// server is a mock TeamSpeak 3 server
type server struct {
Addr string
Listener net.Listener
t *testing.T
conns map[net.Conn]struct{}
done chan struct{}
wg sync.WaitGroup
noHeader bool
noBanner bool
failConn bool
badHeader bool
mtx sync.Mutex
}
// sconn represents a server connection
type sconn struct {
net.Conn
}
// newServer returns a running server or nil if an error occurred.
func newServer(t *testing.T) *server {
s := newServerStopped(t)
s.Start()
return s
}
// newServerStopped returns a stopped servers or nil if an error occurred.
func newServerStopped(t *testing.T) *server {
l, err := newLocalListener()
if !assert.NoError(t, err) {
return nil
}
s := &server{
Listener: l,
conns: make(map[net.Conn]struct{}),
done: make(chan struct{}),
t: t,
}
s.Addr = s.Listener.Addr().String()
return s
}
// Start starts the server.
func (s *server) Start() {
s.wg.Add(1)
go s.serve()
}
// server processes incoming requests until signaled to stop with Close.
func (s *server) serve() {
defer s.wg.Done()
for {
conn, err := s.Listener.Accept()
if err != nil {
if s.running() {
assert.NoError(s.t, err)
}
return
}
s.wg.Add(1)
go s.handle(conn)
}
}
// writeResponse writes the given msg followed by an error (ok) response.
// If msg is empty the only the error (ok) rsponse is sent.
func (s *server) writeResponse(c *sconn, msg string) error {
if msg != "" {
if err := s.write(c.Conn, msg); err != nil {
return err
}
}
return s.write(c.Conn, errOK)
}
// write writes msg to w.
func (s *server) write(w io.Writer, msg string) error {
_, err := w.Write([]byte(msg + "\n\r"))
if s.running() {
assert.NoError(s.t, err)
}
return err
}
// running returns true unless Close has been called, false otherwise.
func (s *server) running() bool {
select {
case <-s.done:
return false
default:
return true
}
}
// handle handles a client connection.
func (s *server) handle(conn net.Conn) {
s.mtx.Lock()
s.conns[conn] = struct{}{}
s.mtx.Unlock()
defer func() {
s.closeConn(conn)
s.wg.Done()
}()
if s.failConn {
return
}
sc := bufio.NewScanner(bufio.NewReader(conn))
sc.Split(bufio.ScanLines)
if !s.noHeader {
if s.badHeader {
if err := s.write(conn, "bad"); err != nil {
return
}
} else {
if err := s.write(conn, DefaultConnectHeader); err != nil {
return
}
}
if !s.noBanner {
if err := s.write(conn, banner); err != nil {
return
}
}
}
c := &sconn{Conn: conn}
for sc.Scan() {
l := sc.Text()
parts := strings.Split(l, " ")
resp, ok := commands[parts[0]]
var err error
switch {
case ok:
err = s.writeResponse(c, resp)
case parts[0] == "disconnect":
return
case strings.TrimSpace(parts[0]) != "":
err = s.write(c, errUnknownCmd)
}
if err != nil || parts[0] == cmdQuit {
return
}
}
if err := sc.Err(); err != nil && s.running() {
assert.NoError(s.t, err)
}
}
// closeConn closes a client connection and removes it from our map of connections.
func (s *server) closeConn(conn net.Conn) {
s.mtx.Lock()
defer s.mtx.Unlock()
conn.Close() // nolint: errcheck
delete(s.conns, conn)
}
// Close cleanly shuts down the server.
func (s *server) Close() error {
close(s.done)
err := s.Listener.Close()
s.mtx.Lock()
for c := range s.conns {
if err2 := c.Close(); err2 != nil && err == nil {
err = err2
}
}
s.mtx.Unlock()
s.wg.Wait()
return err
}