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