source: code/trunk/server_test.go@ 605

Last change on this file since 605 was 604, checked in by contact, 4 years ago

test: get rid of testUpstream

No need for this complexity.

File size: 4.5 KB
RevLine 
[600]1package soju
2
3import (
4 "net"
5 "testing"
6
7 "golang.org/x/crypto/bcrypt"
8 "gopkg.in/irc.v3"
9)
10
[602]11var testServerPrefix = &irc.Prefix{Name: "soju-test-server"}
12
[600]13const (
14 testUsername = "soju-test-user"
15 testPassword = testUsername
16)
17
18func createTempDB(t *testing.T) Database {
19 db, err := OpenSqliteDB("sqlite3", ":memory:")
20 if err != nil {
21 t.Fatalf("failed to create temporary SQLite database: %v", err)
22 }
23 // :memory: will open a separate database for each new connection. Make
24 // sure the sql package only uses a single connection. An alternative
25 // solution is to use "file::memory:?cache=shared".
26 db.(*SqliteDB).db.SetMaxOpenConns(1)
27 return db
28}
29
[602]30func createTestUser(t *testing.T, db Database) *User {
[600]31 hashed, err := bcrypt.GenerateFromPassword([]byte(testPassword), bcrypt.DefaultCost)
32 if err != nil {
33 t.Fatalf("failed to generate bcrypt hash: %v", err)
34 }
35
36 record := &User{Username: testUsername, Password: string(hashed)}
37 if err := db.StoreUser(record); err != nil {
38 t.Fatalf("failed to store test user: %v", err)
39 }
40
[602]41 return record
[600]42}
43
[603]44func createTestDownstream(t *testing.T, srv *Server) ircConn {
45 c1, c2 := net.Pipe()
46 go srv.handle(newNetIRCConn(c1))
47 return newNetIRCConn(c2)
48}
49
[604]50func createTestUpstream(t *testing.T, db Database, user *User) (*Network, net.Listener) {
[602]51 ln, err := net.Listen("tcp", "localhost:0")
52 if err != nil {
53 t.Fatalf("failed to create TCP listener: %v", err)
54 }
55
56 network := &Network{
57 Name: "testnet",
58 Addr: "irc+insecure://" + ln.Addr().String(),
59 Nick: user.Username,
60 Enabled: true,
61 }
62 if err := db.StoreNetwork(user.ID, network); err != nil {
63 t.Fatalf("failed to store test network: %v", err)
64 }
65
[604]66 return network, ln
[602]67}
68
[604]69func mustAccept(t *testing.T, ln net.Listener) ircConn {
70 c, err := ln.Accept()
71 if err != nil {
72 t.Fatalf("failed accepting connection: %v", err)
73 }
74 return newNetIRCConn(c)
75}
76
[600]77func expectMessage(t *testing.T, c ircConn, cmd string) *irc.Message {
78 msg, err := c.ReadMessage()
79 if err != nil {
80 t.Fatalf("failed to read IRC message (want %q): %v", cmd, err)
81 }
82 if msg.Command != cmd {
83 t.Fatalf("invalid message received: want %q, got: %v", cmd, msg)
84 }
85 return msg
86}
87
[602]88func registerDownstreamConn(t *testing.T, c ircConn, network *Network) {
[600]89 c.WriteMessage(&irc.Message{
90 Command: "PASS",
91 Params: []string{testPassword},
92 })
93 c.WriteMessage(&irc.Message{
94 Command: "NICK",
95 Params: []string{testUsername},
96 })
97 c.WriteMessage(&irc.Message{
98 Command: "USER",
[602]99 Params: []string{testUsername + "/" + network.Name, "0", "*", testUsername},
[600]100 })
101
102 expectMessage(t, c, irc.RPL_WELCOME)
103}
104
[602]105func registerUpstreamConn(t *testing.T, c ircConn) {
106 msg := expectMessage(t, c, "CAP")
107 if msg.Params[0] != "LS" {
108 t.Fatalf("invalid CAP LS: got: %v", msg)
109 }
110 msg = expectMessage(t, c, "NICK")
111 nick := msg.Params[0]
112 if nick != testUsername {
113 t.Fatalf("invalid NICK: want %q, got: %v", testUsername, msg)
114 }
115 expectMessage(t, c, "USER")
116
117 c.WriteMessage(&irc.Message{
118 Prefix: testServerPrefix,
119 Command: irc.RPL_WELCOME,
120 Params: []string{nick, "Welcome!"},
121 })
122 c.WriteMessage(&irc.Message{
123 Prefix: testServerPrefix,
124 Command: irc.RPL_YOURHOST,
125 Params: []string{nick, "Your host is soju-test-server"},
126 })
127 c.WriteMessage(&irc.Message{
128 Prefix: testServerPrefix,
129 Command: irc.RPL_CREATED,
130 Params: []string{nick, "Who cares when the server was created?"},
131 })
132 c.WriteMessage(&irc.Message{
133 Prefix: testServerPrefix,
134 Command: irc.RPL_MYINFO,
135 Params: []string{nick, testServerPrefix.Name, "soju", "aiwroO", "OovaimnqpsrtklbeI"},
136 })
137 c.WriteMessage(&irc.Message{
138 Prefix: testServerPrefix,
139 Command: irc.ERR_NOMOTD,
140 Params: []string{nick, "No MOTD"},
141 })
142}
143
[600]144func TestServer(t *testing.T) {
[602]145 db := createTempDB(t)
146 user := createTestUser(t, db)
147 network, upstream := createTestUpstream(t, db, user)
148 defer upstream.Close()
149
150 srv := NewServer(db)
[600]151 if err := srv.Start(); err != nil {
152 t.Fatalf("failed to start server: %v", err)
153 }
154 defer srv.Shutdown()
155
[604]156 uc := mustAccept(t, upstream)
[602]157 defer uc.Close()
158 registerUpstreamConn(t, uc)
[600]159
[602]160 dc := createTestDownstream(t, srv)
161 defer dc.Close()
[603]162 registerDownstreamConn(t, dc, network)
[602]163
[603]164 noticeText := "This is a very important server notice."
165 uc.WriteMessage(&irc.Message{
166 Prefix: testServerPrefix,
167 Command: "NOTICE",
168 Params: []string{testUsername, noticeText},
169 })
170
171 var msg *irc.Message
172 for {
173 var err error
174 msg, err = dc.ReadMessage()
175 if err != nil {
176 t.Fatalf("failed to read IRC message: %v", err)
177 }
178 if msg.Command == "NOTICE" {
179 break
180 }
181 }
182
183 if msg.Params[1] != noticeText {
184 t.Fatalf("invalid NOTICE text: want %q, got: %v", noticeText, msg)
185 }
[600]186}
Note: See TracBrowser for help on using the repository browser.