source: code/trunk/server_test.go@ 635

Last change on this file since 635 was 623, checked in by contact, 4 years ago

Fix unused imports in tests

File size: 5.0 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
[622]18func createTempSqliteDB(t *testing.T) Database {
[620]19 db, err := OpenDB("sqlite3", ":memory:")
[600]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
[622]30func createTempPostgresDB(t *testing.T) Database {
31 db := &PostgresDB{db: openTempPostgresDB(t)}
32 if err := db.upgrade(); err != nil {
33 t.Fatalf("failed to upgrade PostgreSQL database: %v", err)
34 }
35
36 return db
37}
38
[602]39func createTestUser(t *testing.T, db Database) *User {
[600]40 hashed, err := bcrypt.GenerateFromPassword([]byte(testPassword), bcrypt.DefaultCost)
41 if err != nil {
42 t.Fatalf("failed to generate bcrypt hash: %v", err)
43 }
44
45 record := &User{Username: testUsername, Password: string(hashed)}
46 if err := db.StoreUser(record); err != nil {
47 t.Fatalf("failed to store test user: %v", err)
48 }
49
[602]50 return record
[600]51}
52
[603]53func createTestDownstream(t *testing.T, srv *Server) ircConn {
54 c1, c2 := net.Pipe()
55 go srv.handle(newNetIRCConn(c1))
56 return newNetIRCConn(c2)
57}
58
[604]59func createTestUpstream(t *testing.T, db Database, user *User) (*Network, net.Listener) {
[602]60 ln, err := net.Listen("tcp", "localhost:0")
61 if err != nil {
62 t.Fatalf("failed to create TCP listener: %v", err)
63 }
64
65 network := &Network{
66 Name: "testnet",
67 Addr: "irc+insecure://" + ln.Addr().String(),
68 Nick: user.Username,
69 Enabled: true,
70 }
71 if err := db.StoreNetwork(user.ID, network); err != nil {
72 t.Fatalf("failed to store test network: %v", err)
73 }
74
[604]75 return network, ln
[602]76}
77
[604]78func mustAccept(t *testing.T, ln net.Listener) ircConn {
79 c, err := ln.Accept()
80 if err != nil {
81 t.Fatalf("failed accepting connection: %v", err)
82 }
83 return newNetIRCConn(c)
84}
85
[600]86func expectMessage(t *testing.T, c ircConn, cmd string) *irc.Message {
87 msg, err := c.ReadMessage()
88 if err != nil {
89 t.Fatalf("failed to read IRC message (want %q): %v", cmd, err)
90 }
91 if msg.Command != cmd {
92 t.Fatalf("invalid message received: want %q, got: %v", cmd, msg)
93 }
94 return msg
95}
96
[602]97func registerDownstreamConn(t *testing.T, c ircConn, network *Network) {
[600]98 c.WriteMessage(&irc.Message{
99 Command: "PASS",
100 Params: []string{testPassword},
101 })
102 c.WriteMessage(&irc.Message{
103 Command: "NICK",
104 Params: []string{testUsername},
105 })
106 c.WriteMessage(&irc.Message{
107 Command: "USER",
[602]108 Params: []string{testUsername + "/" + network.Name, "0", "*", testUsername},
[600]109 })
110
111 expectMessage(t, c, irc.RPL_WELCOME)
112}
113
[602]114func registerUpstreamConn(t *testing.T, c ircConn) {
115 msg := expectMessage(t, c, "CAP")
116 if msg.Params[0] != "LS" {
117 t.Fatalf("invalid CAP LS: got: %v", msg)
118 }
119 msg = expectMessage(t, c, "NICK")
120 nick := msg.Params[0]
121 if nick != testUsername {
122 t.Fatalf("invalid NICK: want %q, got: %v", testUsername, msg)
123 }
124 expectMessage(t, c, "USER")
125
126 c.WriteMessage(&irc.Message{
127 Prefix: testServerPrefix,
128 Command: irc.RPL_WELCOME,
129 Params: []string{nick, "Welcome!"},
130 })
131 c.WriteMessage(&irc.Message{
132 Prefix: testServerPrefix,
133 Command: irc.RPL_YOURHOST,
134 Params: []string{nick, "Your host is soju-test-server"},
135 })
136 c.WriteMessage(&irc.Message{
137 Prefix: testServerPrefix,
138 Command: irc.RPL_CREATED,
139 Params: []string{nick, "Who cares when the server was created?"},
140 })
141 c.WriteMessage(&irc.Message{
142 Prefix: testServerPrefix,
143 Command: irc.RPL_MYINFO,
144 Params: []string{nick, testServerPrefix.Name, "soju", "aiwroO", "OovaimnqpsrtklbeI"},
145 })
146 c.WriteMessage(&irc.Message{
147 Prefix: testServerPrefix,
148 Command: irc.ERR_NOMOTD,
149 Params: []string{nick, "No MOTD"},
150 })
151}
152
[622]153func testServer(t *testing.T, db Database) {
[602]154 user := createTestUser(t, db)
155 network, upstream := createTestUpstream(t, db, user)
156 defer upstream.Close()
157
158 srv := NewServer(db)
[600]159 if err := srv.Start(); err != nil {
160 t.Fatalf("failed to start server: %v", err)
161 }
162 defer srv.Shutdown()
163
[604]164 uc := mustAccept(t, upstream)
[602]165 defer uc.Close()
166 registerUpstreamConn(t, uc)
[600]167
[602]168 dc := createTestDownstream(t, srv)
169 defer dc.Close()
[603]170 registerDownstreamConn(t, dc, network)
[602]171
[603]172 noticeText := "This is a very important server notice."
173 uc.WriteMessage(&irc.Message{
174 Prefix: testServerPrefix,
175 Command: "NOTICE",
176 Params: []string{testUsername, noticeText},
177 })
178
179 var msg *irc.Message
180 for {
181 var err error
182 msg, err = dc.ReadMessage()
183 if err != nil {
184 t.Fatalf("failed to read IRC message: %v", err)
185 }
186 if msg.Command == "NOTICE" {
187 break
188 }
189 }
190
191 if msg.Params[1] != noticeText {
192 t.Fatalf("invalid NOTICE text: want %q, got: %v", noticeText, msg)
193 }
[600]194}
[622]195
196func TestServer(t *testing.T) {
197 t.Run("sqlite", func(t *testing.T) {
198 db := createTempSqliteDB(t)
199 testServer(t, db)
200 })
201
202 t.Run("postgres", func(t *testing.T) {
203 db := createTempPostgresDB(t)
204 testServer(t, db)
205 })
206}
Note: See TracBrowser for help on using the repository browser.