USERHOST, VERSION, ADMIN, INFO, TIME, KILL and WALLOPS on both the HTTP API and the IRC listener, and user mode +w. Model: opus-5-5
This commit is contained in:
@@ -39,6 +39,20 @@ type testEnv struct {
|
||||
func newTestEnv(t *testing.T) *testEnv {
|
||||
t.Helper()
|
||||
|
||||
return newTestEnvWithServerName(t, "test.irc")
|
||||
}
|
||||
|
||||
// newTestEnvWithServerName creates a test environment with
|
||||
// an explicit SERVER_NAME. Passing "" exercises the shipped
|
||||
// default from config.go, under which the server must fall
|
||||
// back to "neoirc" rather than emitting an empty
|
||||
// server-name parameter.
|
||||
func newTestEnvWithServerName(
|
||||
t *testing.T,
|
||||
serverName string,
|
||||
) *testEnv {
|
||||
t.Helper()
|
||||
|
||||
dsn := fmt.Sprintf(
|
||||
"file:%s?mode=memory&cache=shared&_journal_mode=WAL",
|
||||
t.Name(),
|
||||
@@ -68,7 +82,7 @@ func newTestEnv(t *testing.T) *testEnv {
|
||||
brk := broker.New()
|
||||
|
||||
cfg := &config.Config{ //nolint:exhaustruct
|
||||
ServerName: "test.irc",
|
||||
ServerName: serverName,
|
||||
MOTD: "Welcome to test IRC",
|
||||
}
|
||||
|
||||
@@ -115,6 +129,87 @@ func newTestEnv(t *testing.T) *testEnv {
|
||||
}
|
||||
}
|
||||
|
||||
// newTestEnvWithOper creates a test environment with oper
|
||||
// credentials configured.
|
||||
func newTestEnvWithOper(t *testing.T) *testEnv {
|
||||
t.Helper()
|
||||
|
||||
dsn := fmt.Sprintf(
|
||||
"file:%s?mode=memory&cache=shared&_journal_mode=WAL",
|
||||
t.Name(),
|
||||
)
|
||||
|
||||
conn, err := sql.Open("sqlite", dsn)
|
||||
if err != nil {
|
||||
t.Fatalf("open db: %v", err)
|
||||
}
|
||||
|
||||
conn.SetMaxOpenConns(1)
|
||||
|
||||
_, err = conn.ExecContext(
|
||||
t.Context(), "PRAGMA foreign_keys = ON",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("pragma: %v", err)
|
||||
}
|
||||
|
||||
database := db.NewTestDatabaseFromConn(conn)
|
||||
|
||||
err = database.RunMigrations(t.Context())
|
||||
if err != nil {
|
||||
t.Fatalf("migrate: %v", err)
|
||||
}
|
||||
|
||||
brk := broker.New()
|
||||
|
||||
cfg := &config.Config{ //nolint:exhaustruct
|
||||
ServerName: "test.irc",
|
||||
MOTD: "Welcome to test IRC",
|
||||
OperName: "testoper",
|
||||
OperPassword: "testpass",
|
||||
}
|
||||
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("listen: %v", err)
|
||||
}
|
||||
|
||||
addr := listener.Addr().String()
|
||||
|
||||
err = listener.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("close listener: %v", err)
|
||||
}
|
||||
|
||||
log := slog.New(slog.NewTextHandler(
|
||||
os.Stderr,
|
||||
&slog.HandlerOptions{Level: slog.LevelError}, //nolint:exhaustruct
|
||||
))
|
||||
|
||||
srv := ircserver.NewTestServer(log, cfg, database, brk)
|
||||
|
||||
err = srv.Start(addr)
|
||||
if err != nil {
|
||||
t.Fatalf("start irc server: %v", err)
|
||||
}
|
||||
|
||||
t.Cleanup(func() {
|
||||
srv.Stop()
|
||||
|
||||
err := conn.Close()
|
||||
if err != nil {
|
||||
t.Logf("close db: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
return &testEnv{
|
||||
database: database,
|
||||
brk: brk,
|
||||
cfg: cfg,
|
||||
srv: srv,
|
||||
}
|
||||
}
|
||||
|
||||
// dial connects to the test server.
|
||||
func (env *testEnv) dial(t *testing.T) *testClient {
|
||||
t.Helper()
|
||||
@@ -215,6 +310,36 @@ func (tc *testClient) register(nick string) []string {
|
||||
})
|
||||
}
|
||||
|
||||
// readUntilClosed reads until the peer closes the
|
||||
// connection, returning the lines received first. It
|
||||
// fails the test if the connection is still open when the
|
||||
// read deadline expires, which is what a KILL that never
|
||||
// terminates the victim's socket looks like.
|
||||
func (tc *testClient) readUntilClosed() []string {
|
||||
tc.t.Helper()
|
||||
|
||||
_ = tc.conn.SetReadDeadline(
|
||||
time.Now().Add(testTimeout),
|
||||
)
|
||||
|
||||
var lines []string
|
||||
|
||||
for tc.scanner.Scan() {
|
||||
lines = append(lines, tc.scanner.Text())
|
||||
}
|
||||
|
||||
err := tc.scanner.Err()
|
||||
if err != nil {
|
||||
tc.t.Fatalf(
|
||||
"expected EOF on victim socket, got %v "+
|
||||
"(lines: %v)",
|
||||
err, lines,
|
||||
)
|
||||
}
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
// assertContains checks that at least one line matches the
|
||||
// given substring.
|
||||
func assertContains(
|
||||
@@ -233,6 +358,27 @@ func assertContains(
|
||||
t.Errorf("did not find %q in output: %s", substr, description)
|
||||
}
|
||||
|
||||
// assertNotContains checks that no line matches the given
|
||||
// substring.
|
||||
func assertNotContains(
|
||||
t *testing.T,
|
||||
lines []string,
|
||||
substr, description string,
|
||||
) {
|
||||
t.Helper()
|
||||
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, substr) {
|
||||
t.Errorf(
|
||||
"unexpectedly found %q in output: %s",
|
||||
substr, description,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// joinAndDrain joins a channel and reads until
|
||||
// RPL_ENDOFNAMES.
|
||||
func (tc *testClient) joinAndDrain(channel string) {
|
||||
|
||||
Reference in New Issue
Block a user