]> git.r.bdr.sh - rbdr/mobius/blame - hotline/server_blackbox_test.go
More cleanup
[rbdr/mobius] / hotline / server_blackbox_test.go
CommitLineData
6988a057
JH
1package hotline
2
625b0580
JH
3import (
4 "bytes"
5 "context"
6 "fmt"
7 "go.uber.org/zap"
8 "go.uber.org/zap/zapcore"
9 "net"
10 "os"
11 "reflect"
12 "testing"
13)
14
15type testCase struct {
16 name string // test case description
17 account Account // Account struct for a user that will test transaction will execute under
18 request *Transaction // transaction that will be sent by the client to the server
19 setup func() // Optional test-specific setup required for the scenario
20 teardown func() // Optional test-specific teardown for the scenario
21 mockHandler map[int]*mockClientHandler
22}
23
24func (tt *testCase) Setup(srv *Server) error {
b25c4a19 25 if err := srv.NewUser(tt.account.Login, tt.account.Name, string(negateString([]byte(tt.account.Password))), *tt.account.Access); err != nil {
625b0580
JH
26 return err
27 }
28
29 if tt.setup != nil {
30 tt.setup()
31 }
32
33 return nil
34}
35
36func (tt *testCase) Teardown(srv *Server) error {
37 if err := srv.DeleteUser(tt.account.Login); err != nil {
38 return err
39 }
40
41 if tt.teardown != nil {
42 tt.teardown()
43 }
44
45 return nil
46}
47
48func NewTestLogger() *zap.SugaredLogger {
49 encoderCfg := zap.NewProductionEncoderConfig()
50 encoderCfg.TimeKey = "timestamp"
51 encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder
52
53 core := zapcore.NewCore(
54 zapcore.NewConsoleEncoder(encoderCfg),
55 zapcore.Lock(os.Stdout),
56 zap.DebugLevel,
57 )
58
59 cores := []zapcore.Core{core}
60 l := zap.New(zapcore.NewTee(cores...))
61 defer func() { _ = l.Sync() }()
62 return l.Sugar()
63}
64
65func StartTestServer() (*Server, context.Context, context.CancelFunc) {
66 ctx, cancelRoot := context.WithCancel(context.Background())
67
68 srv, err := NewServer("test/config/", "localhost", 0, NewTestLogger())
69 if err != nil {
70 panic(err)
71 }
72
73 go func() {
74 err := srv.ListenAndServe(ctx, cancelRoot)
75 if err != nil {
76 panic(err)
77 }
78 }()
79
80 return srv, ctx, cancelRoot
81}
82
83func TestHandshake(t *testing.T) {
84 srv, _, cancelFunc := StartTestServer()
85 defer cancelFunc()
86
87 port := srv.APIListener.Addr().(*net.TCPAddr).Port
88
89 conn, err := net.Dial("tcp", fmt.Sprintf(":%v", port))
90 if err != nil {
91 t.Fatal(err)
92 }
93 defer conn.Close()
94
95 conn.Write([]byte{0x54, 0x52, 0x54, 0x50, 0x00, 0x01, 0x00, 0x00})
96
97 replyBuf := make([]byte, 8)
98 _, _ = conn.Read(replyBuf)
99
100 want := []byte{84, 82, 84, 80, 0, 0, 0, 0}
101 if bytes.Compare(replyBuf, want) != 0 {
102 t.Errorf("%q, want %q", replyBuf, want)
103 }
104
105}
106
107//func TestLogin(t *testing.T) {
6988a057 108//
625b0580
JH
109// tests := []struct {
110// name string
111// client *Client
112// }{
6988a057 113// {
625b0580
JH
114// name: "when login is successful",
115// client: NewClient("guest", NewTestLogger()),
6988a057 116// },
6988a057 117// }
6988a057
JH
118// for _, test := range tests {
119// t.Run(test.name, func(t *testing.T) {
6988a057 120//
6988a057
JH
121// })
122// }
123//}
625b0580 124
625b0580
JH
125func TestNewUser(t *testing.T) {
126 srv, _, _ := StartTestServer()
127
128 tests := []testCase{
129 //{
130 // name: "a valid new account",
131 // mockHandler: func() mockClientHandler {
132 // mh := mockClientHandler{}
133 // mh.On("Handle", mock.AnythingOfType("*hotline.Client"), mock.MatchedBy(func(t *Transaction) bool {
134 // println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@")
135 // spew.Dump(t.Type)
136 // spew.Dump(bytes.Equal(t.Type, []byte{0x01, 0x5e}))
137 // //if !bytes.Equal(t.GetField(fieldError).Data, []byte("You are not allowed to create new accounts.")) {
138 // // return false
139 // //}
140 // return bytes.Equal(t.Type, []byte{0x01, 0x5e},
141 // )
142 // })).Return(
143 // []Transaction{}, nil,
144 // )
145 //
146 // clientHandlers[tranNewUser] = mh
147 // return mh
148 // }(),
149 // client: func() *Client {
150 // c := NewClient("testUser", NewTestLogger())
151 // return c
152 // }(),
153 // teardown: func() {
154 // _ = srv.DeleteUser("testUser")
155 // },
156 // account: Account{
157 // Login: "test",
158 // Name: "unnamed",
159 // Password: "test",
160 // Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
161 // },
162 // request: NewTransaction(
163 // tranNewUser, nil,
164 // NewField(fieldUserLogin, []byte(NegatedUserString([]byte("testUser")))),
165 // NewField(fieldUserName, []byte("testUserName")),
166 // NewField(fieldUserPassword, []byte(NegatedUserString([]byte("testPw")))),
167 // NewField(fieldUserAccess, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
168 // ),
169 // want: &Transaction{
170 // Fields: []Field{},
171 // },
172 //},
173 //{
174 // name: "a newUser request from a user without the required access",
175 // mockHandler: func() *mockClientHandler {
176 // mh := mockClientHandler{}
177 // mh.On("Handle", mock.AnythingOfType("*hotline.Client"), mock.MatchedBy(func(t *Transaction) bool {
178 // if !bytes.Equal(t.GetField(fieldError).Data, []byte("You are not allowed to create new accounts.")) {
179 // return false
180 // }
181 // return bytes.Equal(t.Type, []byte{0x01, 0x5e})
182 // })).Return(
183 // []Transaction{}, nil,
184 // )
185 // return &mh
186 // }(),
187 // teardown: func() {
188 // _ = srv.DeleteUser("testUser")
189 // },
190 // account: Account{
191 // Login: "test",
192 // Name: "unnamed",
193 // Password: "test",
194 // Access: &[]byte{0, 0, 0, 0, 0, 0, 0, 0},
195 // },
196 // request: NewTransaction(
197 // tranNewUser, nil,
198 // NewField(fieldUserLogin, []byte(NegatedUserString([]byte("testUser")))),
199 // NewField(fieldUserName, []byte("testUserName")),
200 // NewField(fieldUserPassword, []byte(NegatedUserString([]byte("testPw")))),
201 // NewField(fieldUserAccess, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
202 // ),
203 //},
204 //{
205 // name: "when user does not have required permission",
206 // mockHandler: func() map[int]*mockClientHandler {
207 // mockHandlers := make(map[int]*mockClientHandler)
208 //
209 // mh := mockClientHandler{}
210 // mh.On("Handle", mock.AnythingOfType("*hotline.Client"), mock.MatchedBy(func(t *Transaction) bool {
211 // return t.equal(Transaction{
212 // Type: []byte{0x01, 0x5e},
213 // IsReply: 1,
214 // ErrorCode: []byte{0, 0, 0, 1},
215 // Fields: []Field{
216 // NewField(fieldError, []byte("You are not allowed to create new accounts.")),
217 // },
218 // })
219 // })).Return(
220 // []Transaction{}, nil,
221 // )
222 // mockHandlers[tranNewUser] = &mh
223 //
224 // return mockHandlers
225 // }(),
226 //
227 // teardown: func() {
228 // _ = srv.DeleteUser("testUser")
229 // },
230 // account: Account{
231 // Login: "test",
232 // Name: "unnamed",
233 // Password: "test",
234 // Access: &[]byte{0, 0, 0, 0, 0, 0, 0, 0},
235 // },
236 // request: NewTransaction(
237 // tranNewUser, nil,
238 // NewField(fieldUserLogin, []byte(NegatedUserString([]byte("testUser")))),
239 // NewField(fieldUserName, []byte("testUserName")),
240 // NewField(fieldUserPassword, []byte(NegatedUserString([]byte("testPw")))),
241 // NewField(fieldUserAccess, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
242 // ),
243 //},
244
245 //{
246 // name: "a request to create a user that already exists",
247 // setup: func() {
248 //
249 // },
250 // teardown: func() {
251 // _ = srv.DeleteUser("testUser")
252 // },
253 // account: Account{
254 // Login: "test",
255 // Name: "unnamed",
256 // Password: "test",
257 // Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
258 // },
259 // request: NewTransaction(
260 // tranNewUser, nil,
261 // NewField(fieldUserLogin, []byte(NegatedUserString([]byte("guest")))),
262 // NewField(fieldUserName, []byte("testUserName")),
263 // NewField(fieldUserPassword, []byte(NegatedUserString([]byte("testPw")))),
264 // NewField(fieldUserAccess, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
265 // ),
266 // want: &Transaction{
267 // Fields: []Field{
268 // NewField(fieldError, []byte("Cannot create account guest because there is already an account with that login.")),
269 // },
270 // },
271 //},
272 }
273
274 for _, test := range tests {
275 t.Run(test.name, func(t *testing.T) {
276 test.Setup(srv)
277
278 // move to Setup?
279 c := NewClient(test.account.Name, NewTestLogger())
280 err := c.JoinServer(fmt.Sprintf(":%v", srv.APIPort()), test.account.Login, test.account.Password)
281 if err != nil {
282 t.Errorf("login failed: %v", err)
283 }
284 // end move to Setup??
285
286 for key, value := range test.mockHandler {
287 c.Handlers[uint16(key)] = value
288 }
289
290 // send test case request
291 _ = c.Send(*test.request)
292
293 //time.Sleep(1 * time.Second)
294 // ===
295
296 transactions, _ := readN(c.Connection, 1)
297 for _, t := range transactions {
298 _ = c.HandleTransaction(&t)
299 }
300
301 // ===
302
303 for _, handler := range test.mockHandler {
304 handler.AssertExpectations(t)
305 }
306
307 test.Teardown(srv)
308 })
309 }
310}
311
625b0580
JH
312// equal is a utility function used only in tests that determines if transactions are equal enough
313func (t Transaction) equal(otherT Transaction) bool {
314 t.ID = []byte{0, 0, 0, 0}
315 otherT.ID = []byte{0, 0, 0, 0}
316
317 t.TotalSize = []byte{0, 0, 0, 0}
318 otherT.TotalSize = []byte{0, 0, 0, 0}
319
320 t.DataSize = []byte{0, 0, 0, 0}
321 otherT.DataSize = []byte{0, 0, 0, 0}
322
323 t.ParamCount = []byte{0, 0}
324 otherT.ParamCount = []byte{0, 0}
325
326 //spew.Dump(t)
327 //spew.Dump(otherT)
328
329 return reflect.DeepEqual(t, otherT)
330}