emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 922ad23840 17/25: Add user-oriented test scenarios for ERC


From: F. Jason Park
Subject: master 922ad23840 17/25: Add user-oriented test scenarios for ERC
Date: Thu, 30 Jun 2022 18:29:53 -0400 (EDT)

branch: master
commit 922ad238403d8d821bd696372ffe58572df12670
Author: F. Jason Park <jp@neverwas.me>
Commit: F. Jason Park <jp@neverwas.me>

    Add user-oriented test scenarios for ERC
    
    * test/lisp/erc/erc-scenarios-base-association-nick.el: New file.
    * test/lisp/erc/erc-scenarios-base-association-samenet.el: New file.
    * test/lisp/erc/erc-scenarios-base-association.el: New file.
    * test/lisp/erc/erc-scenarios-base-compat-rename-bouncer.el: New file.
    * test/lisp/erc/erc-scenarios-base-misc-regressions.el: New file.
    * test/lisp/erc/erc-scenarios-base-netid-bouncer-id.el: New file.
    * test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-base.el: New file.
    * test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-both.el: New file.
    * test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-id.el: New file.
    * test/lisp/erc/erc-scenarios-base-netid-bouncer.el: New file.
    * test/lisp/erc/erc-scenarios-base-netid-samenet.el: New file.
    * test/lisp/erc/erc-scenarios-base-reconnect.el: New file.
    * test/lisp/erc/erc-scenarios-base-renick.el: New file.
    * test/lisp/erc/erc-scenarios-base-reuse-buffers.el: New file.
    * test/lisp/erc/erc-scenarios-base-unstable.el: New file.
    * test/lisp/erc/erc-scenarios-base-upstream-recon-soju.el: New file.
    * test/lisp/erc/erc-scenarios-base-upstream-recon-znc.el: New file.
    * test/lisp/erc/erc-scenarios-misc.el: New file.
    * test/lisp/erc/erc-scenarios-services-misc.el: New file.
    * test/lisp/erc/resources/base/assoc/bouncer-history/barnet.eld: New file.
    * test/lisp/erc/resources/base/assoc/bouncer-history/foonet.eld: New file.
    * test/lisp/erc/resources/base/assoc/bumped/again.eld: New file.
    * test/lisp/erc/resources/base/assoc/bumped/foisted.eld: New file.
    * test/lisp/erc/resources/base/assoc/bumped/refoisted.eld: New file.
    * test/lisp/erc/resources/base/assoc/bumped/renicked.eld: New file.
    * test/lisp/erc/resources/base/assoc/multi-net/barnet.eld: New file.
    * test/lisp/erc/resources/base/assoc/multi-net/foonet.eld: New file.
    * test/lisp/erc/resources/base/assoc/reconplay/again.eld: New file.
    * test/lisp/erc/resources/base/assoc/reconplay/foonet.eld: New file.
    * test/lisp/erc/resources/base/assoc/samenet/chester.eld: New file.
    * test/lisp/erc/resources/base/assoc/samenet/tester.eld: New file.
    * test/lisp/erc/resources/base/assoc/samenet/tester2.eld: New file.
    * test/lisp/erc/resources/base/channel-buffer-revival/foonet.eld: New file.
    * test/lisp/erc/resources/base/flood/soju.eld: New file.
    * test/lisp/erc/resources/base/gapless-connect/barnet.eld: New file.
    * test/lisp/erc/resources/base/gapless-connect/foonet.eld: New file.
    * test/lisp/erc/resources/base/gapless-connect/pass-stub.eld: New file.
    * test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld: New file.
    * test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld: New file.
    * test/lisp/erc/resources/base/netid/bouncer/barnet.eld: New file.
    * test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld: New file.
    * test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld: New file.
    * test/lisp/erc/resources/base/netid/bouncer/foonet.eld: New file.
    * test/lisp/erc/resources/base/netid/bouncer/stub-again.eld: New file.
    * test/lisp/erc/resources/base/netid/samenet/chester.eld: New file.
    * test/lisp/erc/resources/base/netid/samenet/tester.eld: New file.
    * test/lisp/erc/resources/base/reconnect/aborted-dupe.eld: New file.
    * test/lisp/erc/resources/base/reconnect/aborted.eld: New file.
    * test/lisp/erc/resources/base/reconnect/options-again.eld: New file.
    * test/lisp/erc/resources/base/reconnect/options.eld: New file.
    * test/lisp/erc/resources/base/reconnect/timer-last.eld: New file.
    * test/lisp/erc/resources/base/reconnect/timer.eld: New file.
    * test/lisp/erc/resources/base/renick/queries/bouncer-barnet.eld: New file.
    * test/lisp/erc/resources/base/renick/queries/bouncer-foonet.eld: New file.
    * test/lisp/erc/resources/base/renick/queries/solo.eld: New file.
    * test/lisp/erc/resources/base/renick/self/auto.eld: New file.
    * test/lisp/erc/resources/base/renick/self/manual.eld: New file.
    * test/lisp/erc/resources/base/renick/self/qual-chester.eld: New file.
    * test/lisp/erc/resources/base/renick/self/qual-tester.eld: New file.
    * test/lisp/erc/resources/base/reuse-buffers/server/barnet.eld: New file.
    * test/lisp/erc/resources/base/reuse-buffers/server/foonet.eld: New file.
    * test/lisp/erc/resources/base/upstream-reconnect/soju-barnet.eld: New file.
    * test/lisp/erc/resources/base/upstream-reconnect/soju-foonet.eld: New file.
    * test/lisp/erc/resources/base/upstream-reconnect/znc-barnet.eld: New file.
    * test/lisp/erc/resources/base/upstream-reconnect/znc-foonet.eld: New file.
    * test/lisp/erc/resources/erc-scenarios-common.el: New file.
    * test/lisp/erc/resources/networks/announced-missing/foonet.eld: New file.
    * test/lisp/erc/resources/services/password/libera.eld: New file.
    
    Add test cases for locking down fundamental client behavior, much of
    it involving the relationship between buffers and connections.  Also
    add accompanying resources subdir containing canned dialog scripts and
    common code needed by various tests.  For test cases demoing the
    problematic behavior originally described in the initial report, see
    update #4 on the bug tracker thread for bug#48598.  Most reside in a
    file named test/lisp/erc/erc-scenarios-48598.el introduced by the
    patch "Add user-oriented test scenarios for ERC".
---
 .../erc/erc-scenarios-base-association-nick.el     | 163 +++++++++
 .../erc/erc-scenarios-base-association-samenet.el  | 144 ++++++++
 test/lisp/erc/erc-scenarios-base-association.el    | 192 ++++++++++
 .../erc-scenarios-base-compat-rename-bouncer.el    | 171 +++++++++
 .../erc/erc-scenarios-base-misc-regressions.el     | 126 +++++++
 .../erc/erc-scenarios-base-netid-bouncer-id.el     |  34 ++
 .../erc-scenarios-base-netid-bouncer-recon-base.el |  30 ++
 .../erc-scenarios-base-netid-bouncer-recon-both.el |  32 ++
 .../erc-scenarios-base-netid-bouncer-recon-id.el   |  35 ++
 test/lisp/erc/erc-scenarios-base-netid-bouncer.el  |  35 ++
 test/lisp/erc/erc-scenarios-base-netid-samenet.el  | 147 ++++++++
 test/lisp/erc/erc-scenarios-base-reconnect.el      | 226 ++++++++++++
 test/lisp/erc/erc-scenarios-base-renick.el         | 305 +++++++++++++++
 test/lisp/erc/erc-scenarios-base-reuse-buffers.el  | 110 ++++++
 test/lisp/erc/erc-scenarios-base-unstable.el       | 134 +++++++
 .../erc/erc-scenarios-base-upstream-recon-soju.el  |  43 +++
 .../erc/erc-scenarios-base-upstream-recon-znc.el   |  43 +++
 test/lisp/erc/erc-scenarios-misc.el                | 107 ++++++
 test/lisp/erc/erc-scenarios-services-misc.el       |  86 +++++
 .../base/assoc/bouncer-history/barnet.eld          |  44 +++
 .../base/assoc/bouncer-history/foonet.eld          |  48 +++
 .../lisp/erc/resources/base/assoc/bumped/again.eld |  30 ++
 .../erc/resources/base/assoc/bumped/foisted.eld    |  30 ++
 .../erc/resources/base/assoc/bumped/refoisted.eld  |  31 ++
 .../erc/resources/base/assoc/bumped/renicked.eld   |  30 ++
 .../erc/resources/base/assoc/multi-net/barnet.eld  |  42 +++
 .../erc/resources/base/assoc/multi-net/foonet.eld  |  45 +++
 .../erc/resources/base/assoc/reconplay/again.eld   |  42 +++
 .../erc/resources/base/assoc/reconplay/foonet.eld  |  52 +++
 .../erc/resources/base/assoc/samenet/chester.eld   |  40 ++
 .../erc/resources/base/assoc/samenet/tester.eld    |  42 +++
 .../erc/resources/base/assoc/samenet/tester2.eld   |  39 ++
 .../base/channel-buffer-revival/foonet.eld         |  45 +++
 test/lisp/erc/resources/base/flood/soju.eld        |  87 +++++
 .../erc/resources/base/gapless-connect/barnet.eld  |  40 ++
 .../erc/resources/base/gapless-connect/foonet.eld  |  41 +++
 .../resources/base/gapless-connect/pass-stub.eld   |   4 +
 .../resources/base/netid/bouncer/barnet-again.eld  |  50 +++
 .../resources/base/netid/bouncer/barnet-drop.eld   |  41 +++
 .../erc/resources/base/netid/bouncer/barnet.eld    |  41 +++
 .../resources/base/netid/bouncer/foonet-again.eld  |  50 +++
 .../resources/base/netid/bouncer/foonet-drop.eld   |  46 +++
 .../erc/resources/base/netid/bouncer/foonet.eld    |  46 +++
 .../resources/base/netid/bouncer/stub-again.eld    |   4 +
 .../erc/resources/base/netid/samenet/chester.eld   |  48 +++
 .../erc/resources/base/netid/samenet/tester.eld    |  52 +++
 .../erc/resources/base/reconnect/aborted-dupe.eld  |  28 ++
 test/lisp/erc/resources/base/reconnect/aborted.eld |  45 +++
 .../erc/resources/base/reconnect/options-again.eld |  45 +++
 test/lisp/erc/resources/base/reconnect/options.eld |  35 ++
 .../erc/resources/base/reconnect/timer-last.eld    |   6 +
 test/lisp/erc/resources/base/reconnect/timer.eld   |   6 +
 .../base/renick/queries/bouncer-barnet.eld         |  54 +++
 .../base/renick/queries/bouncer-foonet.eld         |  52 +++
 .../erc/resources/base/renick/queries/solo.eld     |  55 +++
 test/lisp/erc/resources/base/renick/self/auto.eld  |  46 +++
 .../lisp/erc/resources/base/renick/self/manual.eld |  50 +++
 .../resources/base/renick/self/qual-chester.eld    |  40 ++
 .../erc/resources/base/renick/self/qual-tester.eld |  46 +++
 .../resources/base/reuse-buffers/server/barnet.eld |  24 ++
 .../resources/base/reuse-buffers/server/foonet.eld |  24 ++
 .../base/upstream-reconnect/soju-barnet.eld        |  64 ++++
 .../base/upstream-reconnect/soju-foonet.eld        |  72 ++++
 .../base/upstream-reconnect/znc-barnet.eld         |  93 +++++
 .../base/upstream-reconnect/znc-foonet.eld         |  86 +++++
 test/lisp/erc/resources/erc-scenarios-common.el    | 407 +++++++++++++++++++++
 .../networks/announced-missing/foonet.eld          |   8 +
 .../erc/resources/services/password/libera.eld     |  49 +++
 68 files changed, 4608 insertions(+)

diff --git a/test/lisp/erc/erc-scenarios-base-association-nick.el 
b/test/lisp/erc/erc-scenarios-base-association-nick.el
new file mode 100644
index 0000000000..3e848be4df
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-association-nick.el
@@ -0,0 +1,163 @@
+;;; erc-scenarios-base-association-nick.el --- base assoc scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+;; You register a new nick, disconnect, and log back in, but your nick
+;; is not granted, so ERC obtains a backtick'd version.  You open a
+;; query buffer for NickServ, and ERC names it using the net-ID (which
+;; includes the backtick'd nick) as a suffix.  The original
+;; (disconnected) NickServ buffer gets renamed with *its* net-ID as
+;; well.  You then identify to NickServ, and the dead session is no
+;; longer considered distinct.
+
+(ert-deftest erc-scenarios-base-association-nick-bumped ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/assoc/bumped")
+       (dumb-server (erc-d-run "localhost" t 'renicked 'again))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-flood-penalty 0.5)
+       (erc-server-flood-margin 30))
+
+    (ert-info ("Connect to foonet with nick tester")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :full-name "tester")
+        (erc-scenarios-common-assert-initial-buf-name nil port)
+        (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
+
+    (ert-info ("Create an account for tester and quit")
+      (with-current-buffer "foonet"
+        (funcall expect 3 "debug mode")
+
+        (erc-cmd-QUERY "NickServ")
+        (with-current-buffer "NickServ"
+          (erc-scenarios-common-say "REGISTER changeme")
+          (funcall expect 5 "Account created")
+          (funcall expect 1 "You're now logged in as tester"))
+
+        (with-current-buffer "foonet"
+          (erc-cmd-QUIT "")
+          (erc-d-t-wait-for 4 (not (erc-server-process-alive)))
+          (funcall expect 5 "ERC finished"))))
+
+    (with-current-buffer "foonet"
+      (erc-cmd-RECONNECT))
+
+    (erc-d-t-wait-for 10 "Nick request rejection prevents reassociation (good)"
+      (get-buffer "foonet/tester`"))
+
+    (ert-info ("Ask NickServ to change nick")
+      (with-current-buffer "foonet/tester`"
+        (funcall expect 3 "already in use")
+        (funcall expect 3 "debug mode")
+        (erc-cmd-QUERY "NickServ"))
+
+      (erc-d-t-wait-for 1 "Dead NickServ query buffer renamed, now qualified"
+        (get-buffer "NickServ@foonet/tester"))
+
+      (with-current-buffer "NickServ@foonet/tester`" ; new one
+        (erc-scenarios-common-say "IDENTIFY tester changeme")
+        (funcall expect 5 "You're now logged in as tester")
+        (ert-info ("Original buffer found, reused")
+          (erc-d-t-wait-for 2 (equal (buffer-name) "NickServ")))))
+
+    (ert-info ("Ours is the only NickServ buffer that remains")
+      (should-not (cdr (erc-scenarios-common-buflist "NickServ"))))
+
+    (ert-info ("Visible network ID truncated to one component")
+      (should (not (get-buffer "foonet/tester`")))
+      (should (not (get-buffer "foonet/tester")))
+      (should (get-buffer "foonet")))))
+
+;; A less common variant is when your bouncer switches to an alternate
+;; nick while you're disconnected, and upon reconnecting, you get
+;; a new nick.
+
+(ert-deftest erc-scenarios-base-association-nick-bumped-mandated-renick ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/assoc/bumped")
+       (dumb-server (erc-d-run "localhost" t 'foisted 'refoisted))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-flood-penalty 0.5)
+       (erc-server-flood-margin 30))
+
+    (ert-info ("Connect to foonet with nick tester")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :full-name "tester")
+        (erc-scenarios-common-assert-initial-buf-name nil port)
+        (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
+
+    (ert-info ("Greet bob and quit")
+      (with-current-buffer "foonet"
+        (funcall expect 3 "debug mode")
+
+        (erc-cmd-QUERY "bob")
+        (with-current-buffer "bob"
+          (erc-scenarios-common-say "hi")
+          (funcall expect 5 "hola")
+          (funcall expect 1 "how r u?"))
+
+        (with-current-buffer "foonet"
+          (erc-cmd-QUIT "")
+          (erc-d-t-wait-for 4 (not (erc-server-process-alive)))
+          (funcall expect 5 "ERC finished"))))
+
+    ;; Since we use reconnect, a new buffer won't be created
+    ;; TODO add variant with clean `erc' invocation
+    (with-current-buffer "foonet"
+      (erc-cmd-RECONNECT))
+
+    (ert-info ("Server-initiated renick")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet/dummy"))
+        (should-not (get-buffer "foonet/tester"))
+        (funcall expect 15 "debug mode"))
+
+      (erc-d-t-wait-for 1 "Old query renamed, now qualified"
+        (get-buffer "bob@foonet/tester"))
+
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "bob@foonet/dummy"))
+        (erc-cmd-NICK "tester")
+        (ert-info ("Buffers combined")
+          (erc-d-t-wait-for 2 (equal (buffer-name) "bob")))))
+
+    (with-current-buffer "foonet"
+      (funcall expect 5 "You're now logged in as tester"))
+
+    (ert-info ("Ours is the only bob buffer that remains")
+      (should-not (cdr (erc-scenarios-common-buflist "bob"))))
+
+    (ert-info ("Visible network ID truncated to one component")
+      (should (not (get-buffer "foonet/dummy")))
+      (should (get-buffer "foonet")))))
+
+;;; erc-scenarios-base-association-nick.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-association-samenet.el 
b/test/lisp/erc/erc-scenarios-base-association-samenet.el
new file mode 100644
index 0000000000..b7c7079df3
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-association-samenet.el
@@ -0,0 +1,144 @@
+;;; erc-scenarios-base-association-samenet.el --- assoc samenet scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(declare-function erc-network-name "erc-networks")
+(declare-function erc-network "erc-networks")
+(defvar erc-autojoin-channels-alist)
+(defvar erc-network)
+
+;; One network, two simultaneous connections, no IDs.
+;; Reassociates on reconnect with and without server buffer.
+
+(defun erc-scenarios-common--base-association-samenet (after)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/assoc/samenet")
+       (dumb-server (erc-d-run "localhost" t 'tester 'chester 'tester2))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-flood-penalty 0.5)
+       (erc-server-flood-margin 30))
+
+    (ert-info ("Connect to foonet with nick tester")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :password "changeme"
+                                :full-name "tester")
+        (erc-scenarios-common-assert-initial-buf-name nil port)
+        (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
+
+    (ert-info ("Connect to foonet with nick chester")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "chester"
+                                :password "changeme"
+                                :full-name "chester")
+        (erc-scenarios-common-assert-initial-buf-name nil port)))
+
+    (erc-d-t-wait-for 3 "Dialed Buflist is Empty"
+      (not (erc-scenarios-common-buflist "127.0.0.1")))
+
+    (with-current-buffer "foonet/tester"
+      (funcall expect 3 "debug mode")
+      (erc-cmd-JOIN "#chan"))
+
+    (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/tester"))
+    (with-current-buffer "foonet/chester" (funcall expect 3 "debug mode"))
+    (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/chester"))
+
+    (ert-info ("Nick tester sees other nick chester in channel")
+      (with-current-buffer "#chan@foonet/tester"
+        (funcall expect 5 "chester")
+        (funcall expect 5 "find the forester")
+        (erc-cmd-QUIT "")))
+
+    (ert-info ("Nick chester sees other nick tester in same channel")
+      (with-current-buffer  "#chan@foonet/chester"
+        (funcall expect 5 "tester")
+        (funcall expect 5 "find the forester")))
+
+    (funcall after expect)))
+
+(ert-deftest erc-scenarios-base-association-samenet--reconnect-one ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-association-samenet
+   (lambda (expect)
+
+     (ert-info ("Connection tester reconnects")
+       (with-current-buffer "foonet/tester"
+         (erc-d-t-wait-for 10 (not (erc-server-process-alive)))
+         (funcall expect 10 "*** ERC finished")
+         (erc-cmd-RECONNECT)
+         (funcall expect 5 "debug mode")))
+
+     (ert-info ("Reassociated to same channel")
+       (with-current-buffer "#chan@foonet/tester"
+         (funcall expect 5 "chester")
+         (funcall expect 5 "welcome again")
+         (erc-cmd-QUIT "")))
+
+     (with-current-buffer "#chan@foonet/chester"
+       (funcall expect 5 "tester")
+       (funcall expect 5 "welcome again")
+       (funcall expect 5 "welcome again")
+       (erc-cmd-QUIT "")))))
+
+(ert-deftest erc-scenarios-base-association-samenet--new-buffer ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-association-samenet
+   (lambda (expect)
+
+     (ert-info ("Tester kills buffer and connects from scratch")
+
+       (let (port)
+         (with-current-buffer "foonet/tester"
+           (erc-d-t-wait-for 10 (not (erc-server-process-alive)))
+           (funcall expect 10 "*** ERC finished")
+           (setq port erc-session-port)
+           (kill-buffer))
+
+         (with-current-buffer (erc :server "127.0.0.1"
+                                   :port port
+                                   :nick "tester"
+                                   :password "changeme"
+                                   :full-name "tester")
+
+           (erc-d-t-wait-for 5 (eq erc-network 'foonet)))))
+
+     (with-current-buffer "foonet/tester" (funcall expect 3 "debug mode"))
+
+     (ert-info ("Reassociated to same channel")
+       (with-current-buffer "#chan@foonet/tester"
+         (funcall expect 5 "chester")
+         (funcall expect 5 "welcome again")
+         (erc-cmd-QUIT "")))
+
+     (with-current-buffer "#chan@foonet/chester"
+       (funcall expect 5 "tester")
+       (funcall expect 5 "welcome again")
+       (funcall expect 5 "welcome again")
+       (erc-cmd-QUIT "")))))
+
+;;; erc-scenarios-base-association-samenet.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-association.el 
b/test/lisp/erc/erc-scenarios-base-association.el
new file mode 100644
index 0000000000..83e5101e3a
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-association.el
@@ -0,0 +1,192 @@
+;;; erc-scenarios-base-association.el --- base assoc scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(declare-function erc-network-name "erc-networks")
+(declare-function erc-network "erc-networks")
+(defvar erc-autojoin-channels-alist)
+(defvar erc-network)
+
+;; Two networks, same channel name, no confusion (no bouncer).  Some
+;; of this draws from bug#47522 "foil-in-server-buf".  It shows that
+;; disambiguation-related changes added for bug#48598 are not specific
+;; to bouncers.
+
+(defun erc-scenarios-common--base-association-multi-net (second-join)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/assoc/multi-net")
+       (erc-server-flood-penalty 0.1)
+       (dumb-server-foonet-buffer (get-buffer-create "*server-foonet*"))
+       (dumb-server-barnet-buffer (get-buffer-create "*server-barnet*"))
+       (dumb-server-foonet (erc-d-run "localhost" t "server-foonet" 'foonet))
+       (dumb-server-barnet (erc-d-run "localhost" t "server-barnet" 'barnet))
+       (expect (erc-d-t-make-expecter)))
+
+    (ert-info ("Connect to foonet, join #chan")
+      (with-current-buffer
+          (erc :server "127.0.0.1"
+               :port (process-contact dumb-server-foonet :service)
+               :nick "tester"
+               :password "changeme"
+               :full-name "tester")
+        (funcall expect 3 "debug mode")
+        (erc-cmd-JOIN "#chan")))
+
+    (erc-d-t-wait-for 2 (get-buffer "#chan"))
+
+    (ert-info ("Connect to barnet, join #chan")
+      (with-current-buffer
+          (erc :server "127.0.0.1"
+               :port (process-contact dumb-server-barnet :service)
+               :nick "tester"
+               :password "changeme"
+               :full-name "tester")
+        (funcall expect 5 "debug mode")))
+
+    (funcall second-join)
+
+    (erc-d-t-wait-for 3 (get-buffer "#chan@barnet"))
+
+    (erc-d-t-wait-for 2 "Buf #chan now #chan@foonet"
+      (and (get-buffer "#chan@foonet") (not (get-buffer "#chan"))))
+
+    (ert-info ("All #chan@foonet output consumed")
+      (with-current-buffer "#chan@foonet"
+        (funcall expect 3 "bob")
+        (funcall expect 3 "was created on")
+        (funcall expect 3 "prosperous")))
+
+    (ert-info ("All #chan@barnet output consumed")
+      (with-current-buffer "#chan@barnet"
+        (funcall expect 3 "mike")
+        (funcall expect 3 "was created on")
+        (funcall expect 20 "ingenuous")))))
+
+(ert-deftest erc-scenarios-base-association-multi-net--baseline ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-association-multi-net
+   (lambda () (with-current-buffer "barnet" (erc-cmd-JOIN "#chan")))))
+
+;; The /join command only targets the current buffer's process.  This
+;; recasts scenario bug#48598 "ambiguous-join" (which was based on
+;; bug#47522) to show that issuing superfluous /join commands
+;; (apparently fairly common) is benign.
+
+(ert-deftest erc-scenarios-base-association-multi-net--ambiguous-join ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-association-multi-net
+   (lambda ()
+     (ert-info ("Nonsensical JOIN attempts silently dropped.")
+       (with-current-buffer "foonet" (erc-cmd-JOIN "#chan"))
+       (sit-for 0.1)
+       (with-current-buffer "#chan" (erc-cmd-JOIN "#chan"))
+       (sit-for 0.1)
+       (erc-d-t-wait-for 2 (get-buffer "#chan"))
+       (erc-d-t-wait-for 1 "Only one #chan buffer exists"
+         (should (equal (erc-scenarios-common-buflist "#chan")
+                        (list (get-buffer "#chan")))))
+       (with-current-buffer "*server-barnet*"
+         (erc-d-t-absent-for 0.1 "JOIN"))
+       (with-current-buffer "barnet" (erc-cmd-JOIN "#chan"))))))
+
+;; Playback for same channel on two networks routed correctly.
+;; Originally from Bug#48598: 28.0.50; buffer-naming collisions
+;; involving bouncers in ERC.
+
+(ert-deftest erc-scenarios-base-association-bouncer-history ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/assoc/bouncer-history")
+       (erc-d-t-cleanup-sleep-secs 1)
+       (dumb-server (erc-d-run "localhost" t 'foonet 'barnet))
+       (port (process-contact dumb-server :service))
+       (erc-server-flood-penalty 0.5)
+       (expect (erc-d-t-make-expecter))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo erc-server-process-foo
+       erc-server-buffer-bar erc-server-process-bar)
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer
+          (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "foonet:changeme"
+                                           :full-name "tester"))
+        (setq erc-server-process-foo erc-server-process)
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (funcall expect 5 "foonet")))
+
+    (erc-d-t-wait-for 5 (get-buffer "#chan"))
+
+    (ert-info ("Connect to barnet")
+      (with-current-buffer
+          (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "barnet:changeme"
+                                           :full-name "tester"))
+        (setq erc-server-process-bar erc-server-process)
+        (erc-d-t-wait-for 5 "Temporary name assigned"
+          (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (funcall expect 5 "barnet")))
+
+    (ert-info ("Server buffers are unique")
+      (should-not (eq erc-server-buffer-foo erc-server-buffer-bar)))
+
+    (ert-info ("Networks correctly determined and adopted as buffer names")
+      (with-current-buffer erc-server-buffer-foo
+        (erc-d-t-wait-for 3 "network name foonet becomes buffer name"
+          (and (eq (erc-network) 'foonet) (string= (buffer-name) "foonet"))))
+      (with-current-buffer erc-server-buffer-bar
+        (erc-d-t-wait-for 3 "network name barnet becomes buffer name"
+          (and (eq (erc-network) 'barnet) (string= (buffer-name) "barnet")))))
+
+    (erc-d-t-wait-for 5 (get-buffer "#chan@barnet"))
+
+    (ert-info ("Two channel buffers created, original #chan renamed")
+      (should (= 4 (length (erc-buffer-list))))
+      (should (equal (list (get-buffer "#chan@barnet")
+                           (get-buffer "#chan@foonet"))
+                     (erc-scenarios-common-buflist "#chan"))))
+
+    (ert-info ("#chan@foonet is exclusive, no cross-contamination")
+      (with-current-buffer "#chan@foonet"
+        (erc-d-t-search-for 1 "<bob>")
+        (erc-d-t-absent-for 0.1 "<joe>")
+        (should (eq erc-server-process erc-server-process-foo))))
+
+    (ert-info ("#chan@barnet is exclusive, no cross-contamination")
+      (with-current-buffer "#chan@barnet"
+        (erc-d-t-search-for 1 "<joe>")
+        (erc-d-t-absent-for 0.1 "<bob>")
+        (should (eq erc-server-process erc-server-process-bar))))
+
+    (ert-info ("All output sent")
+      (with-current-buffer "#chan@foonet"
+        (erc-d-t-search-for 10 "please your lordship"))
+      (with-current-buffer "#chan@barnet"
+        (erc-d-t-search-for 10 "I'll bid adieu")))))
+
+;;; erc-scenarios-base-association.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-compat-rename-bouncer.el 
b/test/lisp/erc/erc-scenarios-base-compat-rename-bouncer.el
new file mode 100644
index 0000000000..474739d01b
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-compat-rename-bouncer.el
@@ -0,0 +1,171 @@
+;;; erc-scenarios-compat-rename-bouncer.el --- compat-rename scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+;; Ensure deprecated option still respected when old default value
+;; explicitly set ("respected" in the sense of having names reflect
+;; dialed TCP endpoints with possible uniquifiers but without any of
+;; the old issues, pre-bug#48598).
+
+(defun erc-scenarios-common--base-compat-no-rename-bouncer (dialogs auto more)
+  (erc-scenarios-common-with-cleanup
+      ;; These actually *are* (assigned-)network-id related because
+      ;; our kludge assigns one after the fact.
+      ((erc-scenarios-common-dialog "base/netid/bouncer")
+       (erc-d-t-cleanup-sleep-secs 1)
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (apply #'erc-d-run "localhost" t dialogs))
+       (port (process-contact dumb-server :service))
+       (chan-buf-foo (format "#chan@127.0.0.1:%d" port))
+       (chan-buf-bar (format "#chan@127.0.0.1:%d<2>" port))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-auto-reconnect auto)
+       erc-server-buffer-foo erc-server-process-foo
+       erc-server-buffer-bar erc-server-process-bar)
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer
+          (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "foonet:changeme"
+                                           :full-name "tester"
+                                           :id nil))
+        (setq erc-server-process-foo erc-server-process)
+        (erc-d-t-wait-for 3 (eq (erc-network) 'foonet))
+        (erc-d-t-wait-for 3 "Final buffer name determined"
+          (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (funcall expect 5 "foonet")))
+
+    (ert-info ("Join #chan@foonet")
+      (with-current-buffer erc-server-buffer-foo (erc-cmd-JOIN "#chan"))
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+        (funcall expect 5 "<alice>")))
+
+    (ert-info ("Connect to barnet")
+      (with-current-buffer
+          (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "barnet:changeme"
+                                           :full-name "tester"
+                                           :id nil))
+        (setq erc-server-process-bar erc-server-process)
+        (erc-d-t-wait-for 3 (eq (erc-network) 'barnet))
+        (erc-d-t-wait-for 3 "Final buffer name determined"
+          (string= (buffer-name) (format "127.0.0.1:%d<2>" port)))
+        (funcall expect 5 "barnet")))
+
+    (ert-info ("Server buffers are unique, no names based on IPs")
+      (should-not (eq erc-server-buffer-foo erc-server-buffer-bar))
+      (should (equal (erc-scenarios-common-buflist "127.0.0.1")
+                     (list (get-buffer (format "127.0.0.1:%d<2>" port))
+                           (get-buffer (format "127.0.0.1:%d" port))))))
+
+    (ert-info ("Join #chan@barnet")
+      (with-current-buffer erc-server-buffer-bar (erc-cmd-JOIN "#chan")))
+
+    (erc-d-t-wait-for 5 "Exactly 2 #chan-prefixed buffers exist"
+      (equal (list (get-buffer chan-buf-bar)
+                   (get-buffer chan-buf-foo))
+             (erc-scenarios-common-buflist "#chan")))
+
+    (ert-info ("#chan@127.0.0.1:$port is exclusive to foonet")
+      (with-current-buffer chan-buf-foo
+        (erc-d-t-search-for 1 "<bob>")
+        (erc-d-t-absent-for 0.1 "<joe>")
+        (should (eq erc-server-process erc-server-process-foo))
+        (erc-d-t-search-for 10 "ape is dead")
+        (erc-d-t-wait-for 5 (not (erc-server-process-alive)))))
+
+    (ert-info ("#chan@127.0.0.1:$port<2> is exclusive to barnet")
+      (with-current-buffer chan-buf-bar
+        (erc-d-t-search-for 1 "<joe>")
+        (erc-d-t-absent-for 0.1 "<bob>")
+        (should (eq erc-server-process erc-server-process-bar))
+        (erc-d-t-search-for 10 "keeps you from dishonour")
+        (erc-d-t-wait-for 5 (not (erc-server-process-alive)))))
+
+    (when more (funcall more))))
+
+(ert-deftest erc-scenarios-base-compat-no-rename-bouncer--basic ()
+  :tags '(:expensive-test)
+  (with-suppressed-warnings ((obsolete erc-rename-buffers))
+    (let (erc-rename-buffers)
+      (erc-scenarios-common--base-compat-no-rename-bouncer
+       '(foonet barnet) nil nil))))
+
+(ert-deftest erc-scenarios-base-compat-no-rename-bouncer--reconnect ()
+  :tags '(:expensive-test)
+  (let ((erc-d-tmpl-vars '((token . (group (| "barnet" "foonet")))))
+        (erc-d-match-handlers
+         (list :pass #'erc-scenarios-common--clash-rename-pass-handler))
+        (dialogs '(foonet-drop barnet-drop stub-again stub-again
+                               foonet-again barnet-again))
+        (after
+         (lambda ()
+           (pcase-let* ((`(,barnet ,foonet)
+                         (erc-scenarios-common-buflist "127.0.0.1"))
+                        (port (process-contact (with-current-buffer foonet
+                                                 erc-server-process)
+                                               :service)))
+
+             (ert-info ("Sanity check: barnet retains uniquifying suffix")
+               (should (string-suffix-p "<2>" (buffer-name barnet))))
+
+             ;; Simulate disconnection and `erc-server-auto-reconnect'
+             (ert-info ("Reconnect to foonet and barnet back-to-back")
+               (with-current-buffer foonet
+                 (erc-d-t-wait-for 5 (erc-server-process-alive)))
+               (with-current-buffer barnet
+                 (erc-d-t-wait-for 5 (erc-server-process-alive))))
+
+             (ert-info ("#chan@127.0.0.1:<port> is exclusive to foonet")
+               (with-current-buffer  (format "#chan@127.0.0.1:%d" port)
+                 (erc-d-t-search-for 1 "<alice>")
+                 (erc-d-t-absent-for 0.1 "<joe>")
+                 (erc-d-t-search-for 10 "please your lordship")))
+
+             (ert-info ("#chan@barnet is exclusive to barnet")
+               (with-current-buffer  (format "#chan@127.0.0.1:%d<2>" port)
+                 (erc-d-t-search-for 1 "<joe>")
+                 (erc-d-t-absent-for 0.1 "<bob>")
+                 (erc-d-t-search-for 1 "much in private")))
+
+             ;; Ordering deterministic here even though not so for reconnect
+             (should (equal (list barnet foonet)
+                            (erc-scenarios-common-buflist "127.0.0.1")))
+             (should (equal (list
+                             (get-buffer (format "#chan@127.0.0.1:%d<2>" port))
+                             (get-buffer (format "#chan@127.0.0.1:%d" port)))
+                            (erc-scenarios-common-buflist "#chan")))))))
+
+    (with-suppressed-warnings ((obsolete erc-rename-buffers))
+      (let (erc-rename-buffers)
+        (erc-scenarios-common--base-compat-no-rename-bouncer dialogs
+                                                             'auto after)))))
+
+;;; erc-scenarios-compat-rename-bouncer.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-misc-regressions.el 
b/test/lisp/erc/erc-scenarios-base-misc-regressions.el
new file mode 100644
index 0000000000..8f5700df14
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-misc-regressions.el
@@ -0,0 +1,126 @@
+;;; erc-scenarios-base-misc-regressions.el --- misc regressions scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+(defun erc-scenarios--rebuffed-gapless-pass-handler (dialog exchange)
+  (when (eq (erc-d-dialog-name dialog) 'pass-stub)
+    (let* ((match (erc-d-exchange-match exchange 1))
+           (sym (if (string= match "foonet") 'foonet 'barnet)))
+      (should (member match (list "foonet" "barnet")))
+      (erc-d-load-replacement-dialog dialog sym 1))))
+
+(ert-deftest erc-scenarios-base-gapless-connect ()
+  "Back-to-back entry-point invocations happen successfully.
+Originally from scenario rebuffed/gapless as explained in Bug#48598:
+28.0.50; buffer-naming collisions involving bouncers in ERC."
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/gapless-connect")
+       (erc-server-flood-penalty 0.1)
+       (erc-server-flood-penalty erc-server-flood-penalty)
+       (erc-d-tmpl-vars '((token . (group (| "barnet" "foonet")))))
+       (erc-d-match-handlers
+        (list :pass #'erc-scenarios--rebuffed-gapless-pass-handler))
+       (dumb-server (erc-d-run "localhost" t
+                               'pass-stub 'pass-stub 'barnet 'foonet))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo
+       erc-server-buffer-bar)
+
+    (ert-info ("Connect twice to same endpoint without pausing")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "foonet:changeme"
+                                       :full-name "tester")
+            erc-server-buffer-bar (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "barnet:changeme"
+                                       :full-name "tester")))
+
+    (ert-info ("Returned server buffers are unique")
+      (should-not (eq erc-server-buffer-foo erc-server-buffer-bar)))
+
+    (ert-info ("Both connections still alive")
+      (should (get-process (format "erc-127.0.0.1-%d" port)))
+      (should (get-process (format "erc-127.0.0.1-%d<1>" port))))
+
+    (with-current-buffer erc-server-buffer-bar
+      (funcall expect 2 "marked as being away"))
+
+    (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#bar"))
+      (funcall expect 10 "was created on")
+      (funcall expect 2 "his second fit"))
+
+    (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#foo"))
+      (funcall expect 10 "was created on")
+      (funcall expect 2 "no use of him"))))
+
+;; This defends against a regression in `erc-server-PRIVMSG' caused by
+;; the removal of `erc-auto-query'.  When an active channel buffer is
+;; killed off and PRIVMSGs arrive targeting it, the buffer should be
+;; recreated.  See elsewhere for NOTICE logic, which is more complex.
+
+(ert-deftest erc-scenarios-base-channel-buffer-revival ()
+  :tags '(:expensive-test)
+
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/channel-buffer-revival")
+       (dumb-server (erc-d-run "localhost" t 'foonet))
+       (port (process-contact dumb-server :service))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (ert-info ("Server buffer is unique and temp name is absent")
+      (erc-d-t-wait-for 1 (get-buffer "FooNet"))
+      (should-not (erc-scenarios-common-buflist "127.0.0.1"))
+      (with-current-buffer erc-server-buffer-foo
+        (erc-cmd-JOIN "#chan")))
+
+    (ert-info ("Channel buffer #chan alive and well")
+      (with-current-buffer (erc-d-t-wait-for 8 (get-buffer "#chan"))
+        (erc-d-t-search-for 10 "Our queen and all her elves")
+        (kill-buffer)))
+
+    (should-not (get-buffer "#chan"))
+
+    (ert-info ("Channel buffer #chan revived")
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+        (erc-d-t-search-for 10 "and be prosperous")))))
+
+;;; erc-scenarios-base-misc-regressions.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-netid-bouncer-id.el 
b/test/lisp/erc/erc-scenarios-base-netid-bouncer-id.el
new file mode 100644
index 0000000000..6c6568cad6
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-netid-bouncer-id.el
@@ -0,0 +1,34 @@
+;;; erc-scenarios-base-netid-bouncer-id.el --- net-id bouncer ID scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--id-foo ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer '(:foo-id t) 'foonet 'barnet))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--id-bar ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer '(:bar-id t) 'foonet 'barnet))
+
+;;; erc-scenarios-base-netid-bouncer-id.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-base.el 
b/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-base.el
new file mode 100644
index 0000000000..f48e1ef394
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-base.el
@@ -0,0 +1,30 @@
+;;; erc-scenarios-base-netid-bouncer-recon-base.el --- net-id base scenarios 
-*- lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--recon-base ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer--reconnect nil nil))
+
+;;; erc-scenarios-base-netid-bouncer-recon-base.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-both.el 
b/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-both.el
new file mode 100644
index 0000000000..2f58c3269e
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-both.el
@@ -0,0 +1,32 @@
+;;; erc-scenarios-base-netid-bouncer-recon-both.el --- net-id both scenarios 
-*- lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(require 'erc-scenarios-common)
+
+(ert-deftest erc-scenarios-base-netid-bouncer--recon-both ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer--reconnect 'foo-id 'bar-id))
+
+;;; erc-scenarios-base-netid-bouncer-recon-both.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-id.el 
b/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-id.el
new file mode 100644
index 0000000000..72510809ab
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-id.el
@@ -0,0 +1,35 @@
+;;; erc-scenarios-base-netid-bouncer-recon-id.el --- recon ID scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--reconnect-id-foo ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer--reconnect 'foo-id nil))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--reconnect-id-bar ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer--reconnect nil 'bar-id))
+
+
+;;; erc-scenarios-base-netid-bouncer-recon-id.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-netid-bouncer.el 
b/test/lisp/erc/erc-scenarios-base-netid-bouncer.el
new file mode 100644
index 0000000000..d171e1f9f9
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-netid-bouncer.el
@@ -0,0 +1,35 @@
+;;; erc-scenarios-base-netid-bouncer.el --- net-id bouncer scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--base ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer () 'foonet 'barnet))
+
+(ert-deftest erc-scenarios-base-netid-bouncer--both ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-bouncer '(:foo-id t :bar-id t)
+                                                 'foonet 'barnet))
+
+;;; erc-scenarios-base-netid-bouncer.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-netid-samenet.el 
b/test/lisp/erc/erc-scenarios-base-netid-samenet.el
new file mode 100644
index 0000000000..248144d6f9
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-netid-samenet.el
@@ -0,0 +1,147 @@
+;;; erc-scenarios-base-network-id-samenet.el --- netid-id samenet scenarios 
-*- lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+(cl-defun erc-scenarios-common--base-network-id-same-network
+    ((&key nick id server chan
+           &aux (nick-a nick) (id-a id) (serv-buf-a server) (chan-buf-a chan))
+     (&key nick id server chan
+           &aux (nick-b nick) (id-b id) (serv-buf-b server) (chan-buf-b chan)))
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/netid/samenet")
+       (dumb-server (erc-d-run "localhost" t 'tester 'chester))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-flood-penalty 0.1)
+       (erc-server-flood-margin 30)
+       erc-serv-buf-a erc-serv-buf-b)
+
+    (ert-info ("Connect to foonet with nick tester")
+      (with-current-buffer
+          (setq erc-serv-buf-a (erc :server "127.0.0.1"
+                                    :port port
+                                    :nick nick-a
+                                    :password "changeme"
+                                    :full-name nick-a
+                                    :id id-a))
+        (erc-scenarios-common-assert-initial-buf-name id-a port)
+        (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
+
+    (ert-info ("Connect to foonet with nick chester")
+      (with-current-buffer
+          (setq erc-serv-buf-b (erc :server "127.0.0.1"
+                                    :port port
+                                    :nick nick-b
+                                    :password "changeme"
+                                    :full-name nick-b
+                                    :id id-b))
+        (erc-scenarios-common-assert-initial-buf-name id-b port)))
+
+    (erc-d-t-wait-for 3 (not (erc-scenarios-common-buflist "127.0.0.1")))
+
+    (with-current-buffer erc-serv-buf-a
+      (should (string= (buffer-name) serv-buf-a))
+      (funcall expect 8 "debug mode")
+      (erc-cmd-JOIN "#chan"))
+
+    (with-current-buffer erc-serv-buf-b
+      (should (string= (buffer-name) serv-buf-b))
+      (funcall expect 8 "debug mode")
+      (erc-cmd-JOIN "#chan"))
+
+    (erc-d-t-wait-for 10 (get-buffer chan-buf-a))
+    (erc-d-t-wait-for 10 (get-buffer chan-buf-b))
+
+    (ert-info ("Greets other nick in same channel")
+      (with-current-buffer chan-buf-a
+        (funcall expect 5 "chester")
+        (funcall expect 5 "find the forester")
+        (erc-cmd-MSG "#chan chester: hi")))
+
+    (ert-info ("Sees other nick in same channel")
+      (with-current-buffer chan-buf-b
+        (funcall expect 5 "tester")
+        (funcall expect 10 "<tester> chester: hi")
+        (funcall expect 5 "This was lofty")
+        (erc-cmd-MSG "#chan hi tester")))
+
+    (with-current-buffer chan-buf-a
+      (funcall expect 5 "To employ you towards")
+      (erc-cmd-QUIT ""))
+
+    (with-current-buffer chan-buf-b
+      (funcall expect 5 "To employ you towards")
+      (erc-cmd-QUIT ""))))
+
+(ert-deftest erc-scenarios-base-network-id-same-network--two-ids ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-same-network
+   (list :nick "tester"
+         :id 'tester/foonet
+         :server "tester/foonet"
+         :chan "#chan@tester/foonet")
+   (list :nick "chester"
+         :id 'chester/foonet
+         :server "chester/foonet"
+         :chan "#chan@chester/foonet")))
+
+(ert-deftest erc-scenarios-base-network-id-same-network--one-id-tester ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-same-network
+   (list :nick "tester"
+         :id 'tester/foonet
+         :server "tester/foonet"
+         :chan "#chan@tester/foonet")
+   (list :nick "chester"
+         :id nil
+         :server "foonet"
+         :chan "#chan@foonet")))
+
+(ert-deftest erc-scenarios-base-network-id-same-network--one-id-chester ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-same-network
+   (list :nick "tester"
+         :id nil
+         :server "foonet"
+         :chan "#chan@foonet")
+   (list :nick "chester"
+         :id 'chester/foonet
+         :server "chester/foonet"
+         :chan "#chan@chester/foonet")))
+
+(ert-deftest erc-scenarios-base-network-id-same-network--no-ids ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--base-network-id-same-network
+   (list :nick "tester"
+         :id nil
+         :server "foonet/tester"
+         :chan "#chan@foonet/tester") ; <- note net before nick
+   (list :nick "chester"
+         :id nil
+         :server "foonet/chester"
+         :chan "#chan@foonet/chester")))
+
+;;; erc-scenarios-base-network-id-samenet.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-reconnect.el 
b/test/lisp/erc/erc-scenarios-base-reconnect.el
new file mode 100644
index 0000000000..aeb59e1870
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-reconnect.el
@@ -0,0 +1,226 @@
+;;; erc-scenarios-base-reconnect.el --- Base-reconnect scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+;; This ensures we only reconnect `erc-server-reconnect-attempts'
+;; (rather than infinitely many) times, which can easily happen when
+;; tweaking code related to process sentinels in erc-backend.el.
+
+(ert-deftest erc-scenarios-base-reconnect-timer ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/reconnect")
+       (dumb-server (erc-d-run "localhost" t 'timer 'timer 'timer-last))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-auto-reconnect t)
+       erc-autojoin-channels-alist
+       erc-server-buffer)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer (erc :server "127.0.0.1"
+                                   :port port
+                                   :nick "tester"
+                                   :password "changeme"
+                                   :full-name "tester"))
+      (with-current-buffer erc-server-buffer
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (ert-info ("Server tries to connect thrice (including initial attempt)")
+      (with-current-buffer erc-server-buffer
+        (dotimes (n 3)
+          (ert-info ((format "Attempt %d" n))
+            (funcall expect 3 "Opening connection")
+            (funcall expect 2 "Password incorrect")
+            (funcall expect 2 "Connection failed!")
+            (funcall expect 2 "Re-establishing connection")))
+        (ert-info ("Prev attempt was final")
+          (erc-d-t-absent-for 1 "Opening connection" (point)))))
+
+    (ert-info ("Server buffer is unique and temp name is absent")
+      (should (equal (list (get-buffer (format "127.0.0.1:%d" port)))
+                     (erc-scenarios-common-buflist "127.0.0.1"))))))
+
+(defun erc-scenarios-common--base-reconnect-options (test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/reconnect")
+       (dumb-server (erc-d-run "localhost" t 'options 'options-again))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-flood-penalty 0.1)
+       (erc-server-auto-reconnect t)
+       erc-autojoin-channels-alist
+       erc-server-buffer)
+
+    (should (memq 'autojoin erc-modules))
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer (erc :server "127.0.0.1"
+                                   :port port
+                                   :nick "tester"
+                                   :password "changeme"
+                                   :full-name "tester"))
+      (with-current-buffer erc-server-buffer
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (funcall expect 10 "debug mode")))
+
+    (ert-info ("Wait for some output in channels")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+        (funcall expect 10 "welcome")))
+
+    (ert-info ("Server buffer shows connection failed")
+      (with-current-buffer erc-server-buffer
+        (funcall expect 10 "Connection failed!  Re-establishing")))
+
+    (should (equal erc-autojoin-channels-alist '(("foonet.org" "#chan"))))
+
+    (funcall test)
+
+    (with-current-buffer "FooNet" (erc-cmd-JOIN "#spam"))
+
+    (erc-d-t-wait-for 5 "Channel #spam shown when autojoined"
+      (eq (window-buffer) (get-buffer "#spam")))
+
+    (ert-info ("Wait for auto reconnect")
+      (with-current-buffer erc-server-buffer
+        (funcall expect 10 "still in debug mode")))
+
+    (ert-info ("Wait for activity to recommence in channels")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+        (funcall expect 10 "forest of Arden"))
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#spam"))
+        (funcall expect 10 "her elves come here anon")))))
+
+(ert-deftest erc-scenarios-base-reconnect-options--default ()
+  :tags '(:expensive-test)
+  (should (eq erc-join-buffer 'buffer))
+  (should-not erc-reconnect-display)
+
+  ;; FooNet (the server buffer) is not switched to because it's
+  ;; already current (but not shown) when `erc-open' is called.  See
+  ;; related conditional guard towards the end of that function.
+
+  (erc-scenarios-common--base-reconnect-options
+   (lambda ()
+     (pop-to-buffer-same-window "*Messages*")
+
+     (erc-d-t-ensure-for 1 "Server buffer not shown"
+       (not (eq (window-buffer) (get-buffer "FooNet"))))
+
+     (erc-d-t-wait-for 5 "Channel #chan shown when autojoined"
+       (eq (window-buffer) (get-buffer "#chan"))))))
+
+(ert-deftest erc-scenarios-base-reconnect-options--bury ()
+  :tags '(:expensive-test)
+  (should (eq erc-join-buffer 'buffer))
+  (should-not erc-reconnect-display)
+
+  (let ((erc-reconnect-display 'bury))
+    (erc-scenarios-common--base-reconnect-options
+
+     (lambda ()
+       (pop-to-buffer-same-window "*Messages*")
+
+       (erc-d-t-ensure-for 1 "Server buffer not shown"
+         (not (eq (window-buffer) (get-buffer "FooNet"))))
+
+       (erc-d-t-ensure-for 3 "Channel #chan not shown"
+         (not (eq (window-buffer) (get-buffer "#chan"))))
+
+       (eq (window-buffer) (messages-buffer))))))
+
+;; Upon reconnecting, playback for channel and target buffers is
+;; routed correctly.  Autojoin is irrelevant here, but for the
+;; skeptical, see `erc-scenarios-common--join-network-id', which
+;; overlaps with this and includes spurious JOINs ignored by the
+;; server.
+
+(ert-deftest erc-scenarios-base-association-reconnect-playback ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/assoc/reconplay")
+       (erc-server-flood-penalty 0.1)
+       (erc-server-flood-margin 30)
+       (dumb-server (erc-d-run "localhost" t 'foonet 'again))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (ert-info ("Setup")
+
+      (ert-info ("Server buffer is unique and temp name is absent")
+        (erc-d-t-wait-for 3 (get-buffer "foonet"))
+        (should-not (erc-scenarios-common-buflist "127.0.0.1")))
+
+      (ert-info ("Channel buffer #chan playback received")
+        (with-current-buffer (erc-d-t-wait-for 8 (get-buffer "#chan"))
+          (funcall expect 10 "But purgatory")))
+
+      (ert-info ("Ask for help from services or bouncer bot")
+        (with-current-buffer erc-server-buffer-foo
+          (erc-cmd-MSG "*status help")))
+
+      (ert-info ("Help received")
+        (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "*status"))
+          (funcall expect 10 "Rehash")))
+
+      (ert-info ("#chan convo done")
+        (with-current-buffer "#chan"
+          (funcall expect 10 "most egregious indignity"))))
+
+    ;; KLUDGE (see note above test)
+    (should erc-autojoin-channels-alist)
+    (setq erc-autojoin-channels-alist nil)
+
+    (with-current-buffer erc-server-buffer-foo
+      (erc-cmd-QUIT "")
+      (erc-d-t-wait-for 4 (not (erc-server-process-alive)))
+      (erc-cmd-RECONNECT))
+
+    (ert-info ("Channel buffer found and associated")
+      (with-current-buffer "#chan"
+        (funcall expect 10 "Wilt thou rest damned")))
+
+    (ert-info ("Help buffer found and associated")
+      (with-current-buffer "*status"
+        (erc-scenarios-common-say "help")
+        (funcall expect 10 "Restart ZNC")))
+
+    (ert-info ("#chan convo done")
+      (with-current-buffer "#chan"
+        (funcall expect 10 "here comes the lady")))))
+
+;;; erc-scenarios-base-reconnect.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-renick.el 
b/test/lisp/erc/erc-scenarios-base-renick.el
new file mode 100644
index 0000000000..bf27f61b3f
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-renick.el
@@ -0,0 +1,305 @@
+;;; erc-scenarios-base-renick.el --- Re-nicking scenarios -*- lexical-binding: 
t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+;; The server changes your nick just after registration.
+
+(ert-deftest erc-scenarios-base-renick-self-auto ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/renick/self")
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (erc-d-run "localhost" t 'auto))
+       (port (process-contact dumb-server :service))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "foonet:changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "foonet"))
+      (erc-d-t-search-for 10 "Your new nickname is dummy"))
+
+    (ert-info ("Joined by bouncer to #foo, own nick present")
+      (with-current-buffer (erc-d-t-wait-for 1 (get-buffer "#foo"))
+        (erc-d-t-search-for 10 "dummy")
+        (erc-d-t-search-for 10 "On Thursday")))))
+
+;; You change your nickname manually in a server buffer; a message is
+;; printed in channel buffers.
+
+(ert-deftest erc-scenarios-base-renick-self-manual ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/renick/self")
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (erc-d-run "localhost" t 'manual))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "foonet:changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (erc-d-t-wait-for 3 (get-buffer "foonet"))
+
+    (ert-info ("Joined by bouncer to #foo, own nick present")
+      (with-current-buffer (erc-d-t-wait-for 1 (get-buffer "#foo"))
+        (funcall expect 5 "tester")
+        (funcall expect 5 "On Thursday")
+        (erc-with-server-buffer (erc-cmd-NICK "dummy"))
+        (funcall expect 5 "Your new nickname is dummy")
+        (funcall expect 5 "<bob> dummy: Hi")
+        ;; Regression in which changing a nick would trigger #foo@foonet
+        (erc-d-t-ensure-for 0.4 (equal (buffer-name) "#foo"))))))
+
+;; You connect to the same network with two different nicks.  You
+;; manually change the first nick at some point, and buffer names are
+;; updated correctly.
+
+(ert-deftest erc-scenarios-base-renick-self-qualified ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/renick/self")
+       (dumb-server (erc-d-run "localhost" t 'qual-tester 'qual-chester))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-flood-penalty 0.1)
+       (erc-server-flood-margin 30)
+       erc-serv-buf-a erc-serv-buf-b)
+
+    (ert-info ("Connect to foonet with nick tester")
+      (with-current-buffer
+          (setq erc-serv-buf-a (erc :server "127.0.0.1"
+                                    :port port
+                                    :nick "tester"
+                                    :password "changeme"
+                                    :full-name "tester"))
+        (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
+
+    (ert-info ("Connect to foonet with nick chester")
+      (with-current-buffer
+          (setq erc-serv-buf-b (erc :server "127.0.0.1"
+                                    :port port
+                                    :nick "chester"
+                                    :password "changeme"
+                                    :full-name "chester"))))
+
+    (erc-d-t-wait-for 3 "Dialed Buflist is Empty"
+      (not (erc-scenarios-common-buflist "127.0.0.1")))
+
+    (with-current-buffer  "foonet/tester"
+      (funcall expect 3 "debug mode")
+      (erc-cmd-JOIN "#chan"))
+
+    (with-current-buffer  "foonet/chester"
+      (funcall expect 3 "debug mode")
+      (erc-cmd-JOIN "#chan"))
+
+    (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/tester"))
+    (erc-d-t-wait-for 10 (get-buffer "#chan@foonet/chester"))
+
+    (ert-info ("Greets other nick in same channel")
+      (with-current-buffer "#chan@foonet/tester"
+        (funcall expect 5 "<bob> chester, welcome!")
+        (erc-cmd-NICK "dummy")
+        (funcall expect 5 "Your new nickname is dummy")
+        (funcall expect 5 "find the forester")
+        (erc-d-t-wait-for 5 (string= (buffer-name) "#chan@foonet/dummy"))))
+
+    (ert-info ("Renick propagated throughout all buffers of process")
+      (should-not (get-buffer "#chan@foonet/tester"))
+      (should-not (get-buffer "foonet/tester"))
+      (should (get-buffer "foonet/dummy")))))
+
+;; When a channel user changes their nick, any query buffers for them
+;; are updated.
+
+(ert-deftest erc-scenarios-base-renick-queries-solo ()
+  :tags '(:expensive-test)
+
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/renick/queries")
+       (erc-server-flood-penalty 0.1)
+       (erc-server-flood-margin 20)
+       (dumb-server (erc-d-run "localhost" t 'solo))
+       (port (process-contact dumb-server :service))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "foonet:changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (erc-d-t-wait-for 1 (get-buffer "foonet"))
+
+    (ert-info ("Joined by bouncer to #foo, pal persent")
+      (with-current-buffer (erc-d-t-wait-for 1 (get-buffer "#foo"))
+        (erc-d-t-search-for 1 "On Thursday")
+        (erc-scenarios-common-say "hi")))
+
+    (erc-d-t-wait-for 10 "Query buffer appears with message from pal"
+      (get-buffer "Lal"))
+
+    (ert-info ("Chat with pal, who changes name")
+      (with-current-buffer "Lal"
+        (erc-d-t-search-for 3 "hello")
+        (erc-scenarios-common-say "hi")
+        (erc-d-t-search-for 10 "is now known as Linguo")
+        (should-not (search-forward "is now known as Linguo" nil t))))
+
+    (erc-d-t-wait-for 1 (get-buffer "Linguo"))
+    (should-not (get-buffer "Lal"))
+
+    (with-current-buffer "Linguo" (erc-scenarios-common-say "howdy Linguo"))
+
+    (with-current-buffer "#foo"
+      (erc-d-t-search-for 10 "is now known as Linguo")
+      (should-not (search-forward "is now known as Linguo" nil t))
+      (erc-cmd-PART ""))
+
+    (with-current-buffer "Linguo"
+      (erc-d-t-search-for 10 "get along"))))
+
+;; You share a channel and a query buffer with a user on two different
+;; networks (through a proxy).  The user changes their nick on both
+;; networks at the same time.  Query buffers are updated accordingly.
+
+(ert-deftest erc-scenarios-base-renick-queries-bouncer ()
+  :tags '(:expensive-test)
+
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/renick/queries")
+       (erc-server-flood-penalty 0.1)
+       (erc-server-flood-margin 30)
+       (dumb-server (erc-d-run "localhost" t 'bouncer-foonet 'bouncer-barnet))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       erc-accidental-paste-threshold-seconds
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo
+       erc-server-buffer-bar)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "foonet:changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (erc-d-t-wait-for 5 (get-buffer "foonet"))
+
+    (ert-info ("Connect to barnet")
+      (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "barnet:changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-bar
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (erc-d-t-wait-for 5 (get-buffer "barnet"))
+    (should-not (erc-scenarios-common-buflist "127.0.0.1"))
+
+    (ert-info ("Joined by bouncer to #chan@foonet, pal persent")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan@foonet"))
+        (funcall expect 1 "rando")
+        (funcall expect 1 "simply misused")))
+
+    (ert-info ("Joined by bouncer to #chan@barnet, pal persent")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan@barnet"))
+        (funcall expect 1 "rando")
+        (funcall expect 2 "come, sir, I am")))
+
+    (ert-info ("Query buffer exists for rando@foonet")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "rando@foonet"))
+        (funcall expect 1 "guess not")
+        (erc-scenarios-common-say "I here")))
+
+    (ert-info ("Query buffer exists for rando@barnet")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "rando@barnet"))
+        (funcall expect 2 "rentacop")
+        (erc-scenarios-common-say "Linda said you were gonna kill me.")))
+
+    (ert-info ("Sync convo for rando@foonet")
+      (with-current-buffer "rando@foonet"
+        (funcall expect 1 "u are dumb")
+        (erc-scenarios-common-say "not so")))
+
+    (ert-info ("Sync convo for rando@barnet")
+      (with-current-buffer "rando@barnet"
+        (funcall expect 3 "I never saw her before")
+        (erc-scenarios-common-say "You aren't with Wage?")))
+
+    (erc-d-t-wait-for 3 (get-buffer "frenemy@foonet"))
+    (erc-d-t-wait-for 3 (get-buffer "frenemy@barnet"))
+    (should-not (get-buffer "rando@foonet"))
+    (should-not (get-buffer "rando@barnet"))
+
+    (with-current-buffer "frenemy@foonet"
+      (funcall expect 1 "now known as")
+      (funcall expect 1 "doubly so"))
+
+    (with-current-buffer "frenemy@barnet"
+      (funcall expect 1 "now known as")
+      (funcall expect 1 "reality picture"))
+
+    (when noninteractive
+      (with-current-buffer "frenemy@barnet" (kill-buffer))
+      (erc-d-t-wait-for 2 (get-buffer "frenemy"))
+      (should-not (get-buffer "frenemy@foonet")))
+
+    (with-current-buffer "#chan@foonet"
+      (funcall expect 10 "is now known as frenemy")
+      (should-not (search-forward "now known as frenemy" nil t)) ; regression
+      (funcall expect 10 "words are razors"))
+
+    (with-current-buffer "#chan@barnet"
+      (funcall expect 10 "is now known as frenemy")
+      (should-not (search-forward "now known as frenemy" nil t))
+      (erc-d-t-search-for 25 "I have lost"))))
+
+;;; erc-scenarios-base-renick.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-reuse-buffers.el 
b/test/lisp/erc/erc-scenarios-base-reuse-buffers.el
new file mode 100644
index 0000000000..2e3ed9969f
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-reuse-buffers.el
@@ -0,0 +1,110 @@
+;;; erc-scenarios-base-reuse-buffers.el --- base-reuse-buffers scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+(defun erc-scenarios-common--base-reuse-buffers-server-buffers (&optional more)
+  "Show that `erc-reuse-buffers' doesn't affect server buffers.
+Overlaps some with `clash-of-chans/uniquify'.  Adapted from
+rebuffed/reuseless, described in Bug#48598: 28.0.50; buffer-naming
+collisions involving bouncers in ERC.  Run EXTRA."
+  (erc-scenarios-common-with-cleanup
+      ((dumb-server (erc-d-run "localhost" t 'foonet 'barnet))
+       (port (process-contact dumb-server :service))
+       erc-autojoin-channels-alist)
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :password "foonet:changeme"
+                                :full-name "tester")
+        (should (string= (buffer-name)
+                         (format "127.0.0.1:%d/127.0.0.1" port)))
+        (erc-d-t-search-for 12 "marked as being away")))
+
+    (ert-info ("Connect to barnet")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :password "barnet:changeme"
+                                :full-name "tester")
+        (should (string= (buffer-name)
+                         (format "127.0.0.1:%d/127.0.0.1<2>" port)))
+        (erc-d-t-search-for 45 "marked as being away")))
+
+    (erc-d-t-wait-for 2 (get-buffer (format "127.0.0.1:%d/127.0.0.1" port)))
+    (erc-d-t-wait-for 2 (get-buffer (format "127.0.0.1:%d/127.0.0.1<2>" port)))
+
+    (ert-info ("Server buffers are unique, no IP-based names")
+      (should (cdr (erc-scenarios-common-buflist "127.0.0.1"))))
+    (when more (funcall more port))))
+
+;; XXX maybe remove: already covered many times over by other scenarios
+(ert-deftest erc-scenarios-base-reuse-buffers-server-buffers--enabled ()
+  :tags '(:expensive-test)
+  (with-suppressed-warnings ((obsolete erc-reuse-buffers))
+    (should erc-reuse-buffers))
+  (let ((erc-scenarios-common-dialog "base/reuse-buffers/server"))
+    (erc-scenarios-common-with-cleanup
+        ((dumb-server (erc-d-run "localhost" t 'foonet 'barnet))
+         (port (process-contact dumb-server :service))
+         erc-autojoin-channels-alist)
+
+      (ert-info ("Connect to foonet")
+        (with-current-buffer (erc :server "127.0.0.1"
+                                  :port port
+                                  :nick "tester"
+                                  :password "foonet:changeme"
+                                  :full-name "tester")
+          (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+          (erc-d-t-search-for 12 "marked as being away")))
+
+      (ert-info ("Connect to barnet")
+        (with-current-buffer (erc :server "127.0.0.1"
+                                  :port port
+                                  :nick "tester"
+                                  :password "barnet:changeme"
+                                  :full-name "tester")
+          (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+          (erc-d-t-search-for 45 "marked as being away")))
+
+      (erc-d-t-wait-for 2 (get-buffer "foonet"))
+      (erc-d-t-wait-for 2 (get-buffer "barnet"))
+
+      (ert-info ("Server buffers are unique, no IP-based names")
+        (should-not (eq (get-buffer "foonet") (get-buffer "barnet")))
+        (should-not (erc-scenarios-common-buflist "127.0.0.1"))))))
+
+;; FIXME no sense in running this twice (JOIN variant includes this)
+(ert-deftest erc-scenarios-base-reuse-buffers-server-buffers--disabled ()
+  :tags '(:expensive-test)
+  (with-suppressed-warnings ((obsolete erc-reuse-buffers))
+    (should erc-reuse-buffers)
+    (let ((erc-scenarios-common-dialog "base/reuse-buffers/server")
+          erc-reuse-buffers)
+      (erc-scenarios-common--base-reuse-buffers-server-buffers nil))))
+
+;;; erc-scenarios-base-reuse-buffers.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-unstable.el 
b/test/lisp/erc/erc-scenarios-base-unstable.el
new file mode 100644
index 0000000000..2313a15842
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-unstable.el
@@ -0,0 +1,134 @@
+;;; erc-scenarios-base-unstable.el --- base unstable scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+;; Not unstable, but stashed here for now
+
+(ert-deftest erc-scenarios-aux-unix-socket ()
+  :tags '(:expensive-test)
+  (skip-unless (featurep 'make-network-process '(:family local)))
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/renick/self")
+       (erc-server-flood-penalty 0.1)
+       (sock (expand-file-name "erc-d.sock" temporary-file-directory))
+       (erc-scenarios-common-extra-teardown (lambda () (delete-file sock)))
+       (erc-server-connect-function
+        (lambda (n b _ p &rest r)
+          (apply #'make-network-process
+                 `(:name ,n :buffer ,b :service ,p :family local ,@r))))
+       (dumb-server (erc-d-run nil sock 'auto))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "fake"
+                                       :port sock
+                                       :nick "tester"
+                                       :password "foonet:changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "fake:%s" sock)))))
+
+    (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "foonet"))
+      (erc-d-t-search-for 10 "Your new nickname is dummy"))
+
+    (ert-info ("Joined by bouncer to #foo, own nick present")
+      (with-current-buffer (erc-d-t-wait-for 3 (get-buffer "#foo"))
+        (erc-d-t-search-for 10 "dummy")
+        (erc-d-t-search-for 10 "On Thursday")))))
+
+;; See `erc-networks--rename-server-buffer'.  A perceived loss in
+;; network connectivity turns out to be a false alarm, but the bouncer
+;; has already accepted the second connection
+
+(defun erc-scenarios--base-aborted-reconnect ()
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/reconnect")
+       (erc-d-t-cleanup-sleep-secs 1)
+       (dumb-server (erc-d-run "localhost" t 'aborted 'aborted-dupe))
+       (port (process-contact dumb-server :service))
+       erc-autojoin-channels-alist
+       erc-server-buffer-foo)
+
+    (ert-info ("Connect to foonet")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "changeme"
+                                       :full-name "tester"))
+      (with-current-buffer erc-server-buffer-foo
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))))
+
+    (ert-info ("Server buffer is unique and temp name is absent")
+      (erc-d-t-wait-for 10 (get-buffer "FooNet"))
+      (should-not (erc-scenarios-common-buflist "127.0.0.1"))
+      (with-current-buffer erc-server-buffer-foo
+        (erc-cmd-JOIN "#chan")))
+
+    (ert-info ("Channel buffer #chan alive and well")
+      (with-current-buffer (erc-d-t-wait-for 4 (get-buffer "#chan"))
+        (erc-d-t-search-for 10 "welcome")))
+
+    (ert-info ("Connect to foonet again")
+      (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                       :port port
+                                       :nick "tester"
+                                       :password "changeme"
+                                       :full-name "tester"))
+      (let ((inhibit-message noninteractive))
+        (with-current-buffer erc-server-buffer-foo
+          (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+          (erc-d-t-wait-for 5 (not (erc-server-process-alive)))
+          (erc-d-t-search-for 10 "FooNet still connected"))))
+
+    (ert-info ("Server buffer is unique and temp name is absent")
+      (should (equal (list (get-buffer "FooNet"))
+                     (erc-scenarios-common-buflist "FooNet")))
+      (should (equal (list (get-buffer (format "127.0.0.1:%d" port)))
+                     (erc-scenarios-common-buflist "127.0.0.1"))))
+
+    (ert-info ("Channel buffer #chan still going")
+      (with-current-buffer "#chan"
+        (erc-d-t-search-for 10 "and be prosperous")))))
+
+(ert-deftest erc-scenarios-base-aborted-reconnect ()
+  :tags '(:unstable)
+  (let ((tries 3)
+        (timeout 1)
+        failed)
+    (while (condition-case _err
+               (progn
+                 (erc-scenarios--base-aborted-reconnect)
+                 nil)
+             (ert-test-failed
+              (message "Test %S failed; %s attempt(s) remaining."
+                       (ert-test-name (ert-running-test))
+                       tries)
+              (sleep-for (cl-incf timeout))
+              (not (setq failed (zerop (cl-decf tries)))))))
+    (should-not failed)))
+
+;;; erc-scenarios-base-unstable.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-upstream-recon-soju.el 
b/test/lisp/erc/erc-scenarios-base-upstream-recon-soju.el
new file mode 100644
index 0000000000..5a5b363f31
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-upstream-recon-soju.el
@@ -0,0 +1,43 @@
+;;; erc-scenarios-upstream-recon-soju.el --- Upstream soju -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+;; Commentary:
+;;
+;; These concern the loss and recovery of a proxy's IRC-side connection.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-upstream-recon--soju ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--upstream-reconnect
+   (lambda ()
+     (with-current-buffer "foonet"
+       (erc-d-t-search-for 1 "disconnected from foonet")
+       (erc-d-t-search-for 1 "connected from foonet"))
+     (with-current-buffer "barnet"
+       (erc-d-t-search-for 1 "disconnected from barnet")
+       (erc-d-t-search-for 1 "connected from barnet")))
+   'soju-foonet
+   'soju-barnet))
+
+;;; erc-scenarios-upstream-recon-soju.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-upstream-recon-znc.el 
b/test/lisp/erc/erc-scenarios-base-upstream-recon-znc.el
new file mode 100644
index 0000000000..6e9a217245
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-upstream-recon-znc.el
@@ -0,0 +1,43 @@
+;;; erc-scenarios-upstream-recon-znc.el --- Upstream znc -*- lexical-binding: 
t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+;; Commentary:
+;;
+;; These concern the loss and recovery of a proxy's IRC-side connection.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-upstream-recon--znc ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common--upstream-reconnect
+   (lambda ()
+     (with-current-buffer "*status@foonet"
+       (erc-d-t-search-for 1 "Disconnected from IRC")
+       (erc-d-t-search-for 1 "Connected!"))
+     (with-current-buffer "*status@barnet"
+       (erc-d-t-search-for 1 "Disconnected from IRC")
+       (erc-d-t-search-for 1 "Connected!")))
+   'znc-foonet
+   'znc-barnet))
+
+;;; erc-scenarios-upstream-recon-znc.el ends here
diff --git a/test/lisp/erc/erc-scenarios-misc.el 
b/test/lisp/erc/erc-scenarios-misc.el
new file mode 100644
index 0000000000..86cfa8b10b
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-misc.el
@@ -0,0 +1,107 @@
+;;; erc-scenarios-misc.el --- Misc scenarios for ERC -*- lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join))
+
+(ert-deftest erc-scenarios-base-flood ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/flood")
+       (dumb-server (erc-d-run "localhost" t 'soju))
+       (port (process-contact dumb-server :service))
+       (erc-server-flood-penalty 0.5) ; this ratio MUST match
+       (erc-server-flood-margin 1.5) ;  the default of 3:10
+       (expect (erc-d-t-make-expecter))
+       erc-autojoin-channels-alist)
+
+    (ert-info ("Connect to bouncer")
+      (with-current-buffer
+          (erc :server "127.0.0.1"
+               :port port
+               :nick "tester"
+               :password "changeme"
+               :full-name "tester")
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (funcall expect 5 "Soju")))
+
+    (ert-info ("#chan@foonet exists")
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan/foonet"))
+        (erc-d-t-search-for 2 "<bob/foonet>")
+        (erc-d-t-absent-for 0.1 "<joe")
+        (funcall expect 3 "was created on")))
+
+    (ert-info ("#chan@barnet exists")
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan/barnet"))
+        (erc-d-t-search-for 2 "<joe/barnet>")
+        (erc-d-t-absent-for 0.1 "<bob")
+        (funcall expect 3 "was created on")
+        (funcall expect 5 "To get good guard")))
+
+    (ert-info ("Message not held in queue limbo")
+      (with-current-buffer "#chan/foonet"
+        ;; Without 'no-penalty param in `erc-server-send', should fail
+        ;; after ~10 secs with:
+        ;;
+        ;;   (erc-d-timeout "Timed out awaiting request: (:name ~privmsg
+        ;;    :pattern \\`PRIVMSG #chan/foonet :alice: hi :timeout 2
+        ;;    :dialog soju)")
+        ;;
+        ;; Try reversing commit and spying on queue interactively
+        (erc-cmd-MSG "#chan/foonet alice: hi")
+        (funcall expect 5 "tester: Good, very good")))
+
+    (ert-info ("All output sent")
+      (with-current-buffer "#chan/foonet"
+        (funcall expect 8 "Some man or other"))
+      (with-current-buffer "#chan/barnet"
+        (funcall expect 10 "That's he that was Othello")))))
+
+;; Corner case demoing fallback behavior for an absent 004 RPL but a
+;; present 422 or 375.  If this is unlikely enough, remove or guard
+;; with `ert-skip' plus some condition so it only runs when explicitly
+;; named via ERT specifier
+
+(ert-deftest erc-scenarios-networks-announced-missing ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "networks/announced-missing")
+       (expect (erc-d-t-make-expecter))
+       (dumb-server (erc-d-run "localhost" t 'foonet))
+       (port (process-contact dumb-server :service)))
+
+    (ert-info ("Connect without password")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :full-name "tester")
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (let ((err (should-error (sleep-for 1))))
+          (should (string-match-p "Failed to determine" (cadr err))))
+        (funcall expect 1 "Failed to determine")
+        (funcall expect 1 "Failed to determine")
+        (should-not erc-network)
+        (should (string= erc-server-announced-name "irc.foonet.org"))))))
+
+;;; erc-scenarios-misc.el ends here
diff --git a/test/lisp/erc/erc-scenarios-services-misc.el 
b/test/lisp/erc/erc-scenarios-services-misc.el
new file mode 100644
index 0000000000..cb1aa6ff32
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-services-misc.el
@@ -0,0 +1,86 @@
+;;; erc-scenarios-services-misc.el --- Services-misc scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(eval-when-compile (require 'erc-join)
+                   (require 'erc-services))
+
+(ert-deftest erc-scenarios-services-password ()
+  :tags '(:expensive-test)
+
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "services/password")
+       (erc-server-flood-penalty 0.1)
+       (erc-modules (cons 'services erc-modules))
+       (erc-nickserv-passwords '((Libera.Chat (("joe" . "bar")
+                                               ("tester" . "changeme")))))
+       (expect (erc-d-t-make-expecter))
+       (dumb-server (erc-d-run "localhost" t 'libera))
+       (port (process-contact dumb-server :service)))
+
+    (ert-info ("Connect without password")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :full-name "tester")
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (erc-d-t-wait-for 5 (eq erc-network 'Libera.Chat))
+        (funcall expect 5 "This nickname is registered.")
+        (funcall expect 2 "You are now identified")
+        (funcall expect 1 "Last login from")
+        (erc-cmd-QUIT "")))
+
+    (erc-services-mode -1)
+
+    (should-not (memq 'services erc-modules))))
+
+(ert-deftest erc-scenarios-services-prompt ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "services/password")
+       (erc-server-flood-penalty 0.1)
+       (inhibit-interaction nil)
+       (erc-modules (cons 'services erc-modules))
+       (expect (erc-d-t-make-expecter))
+       (dumb-server (erc-d-run "localhost" t 'libera))
+       (port (process-contact dumb-server :service)))
+
+    (ert-info ("Connect without password")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :full-name "tester")
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (ert-simulate-keys "changeme\r"
+          (erc-d-t-wait-for 10 (eq erc-network 'Libera.Chat))
+          (funcall expect 3 "This nickname is registered.")
+          (funcall expect 3 "You are now identified")
+          (funcall expect 3 "Last login from"))
+        (erc-cmd-QUIT "")))
+
+    (erc-services-mode -1)
+
+    (should-not (memq 'services erc-modules))))
+
+;;; erc-scenarios-services-misc.el ends here
diff --git a/test/lisp/erc/resources/base/assoc/bouncer-history/barnet.eld 
b/test/lisp/erc/resources/base/assoc/bouncer-history/barnet.eld
new file mode 100644
index 0000000000..4b6ccfff38
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/bouncer-history/barnet.eld
@@ -0,0 +1,44 @@
+;; -*- mode: lisp-data; -*-
+((pass 3 "PASS :barnet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Wed, 28 Apr 2021 
06:59:59 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ ;; No mode answer ^
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@xrir8fpe4d7ak.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :joe @mike tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:25] mike: Belike, for joy 
the emperor hath a son.")
+ (0 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:27] joe: Protest their 
first of manhood.")
+ (0 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:29] mike: As frozen water 
to a starved snake.")
+ (0 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:34] joe: My mirth it 
much displeas'd, but pleas'd my woe.")
+ (0 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:38] mike: Why, Marcus, no 
man should be mad but I.")
+ (0 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:44] joe: Faith, I have 
heard too much, for your words and performances are no kin together.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0 ":irc.barnet.org NOTICE tester :[07:00:01] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
+
+((mode 6 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1619593200")
+ (0.25 ":joe!~u@svpn88yjcdj42.irc PRIVMSG #chan :mike: But, in defence, by 
mercy, 'tis most just.")
+ (0.25 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :joe: The Marshal of France, 
Monsieur la Far.")
+ (0.25 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :mike: And bide the penance of 
each three years' day.")
+ (0.25 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :joe: Madam, within; but 
never man so chang'd.")
+ (0.25 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :mike: As much in private, and 
I'll bid adieu."))
diff --git a/test/lisp/erc/resources/base/assoc/bouncer-history/foonet.eld 
b/test/lisp/erc/resources/base/assoc/bouncer-history/foonet.eld
new file mode 100644
index 0000000000..58df79e19f
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/bouncer-history/foonet.eld
@@ -0,0 +1,48 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Wed, 28 Apr 2021 
07:00:00 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ ;; No mode answer ^
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@nvfhxvqm92rm6.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice @bob tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:02] alice: Here come the 
lovers, full of joy and mirth.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:07] bob: According to 
the fool's bolt, sir, and such dulcet diseases.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:10] alice: And hang 
himself. I pray you, do my greeting.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:18] bob: And you sat 
smiling at his cruel prey.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:21] alice: Or never after 
look me in the face.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:25] bob: If that may 
be, than all is well. Come, sit down, every mother's son, and rehearse your 
parts. Pyramus, you begin: when you have spoken your speech, enter into that 
brake; and so every one according to his cue.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:30] alice: Where I espied 
the panther fast asleep.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:32] bob: Alas! he is 
too young: yet he looks successfully.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:37] alice: Here, at your 
lordship's service.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:42] bob: By my troth, 
and in good earnest, and so God mend me, and by all pretty oaths that are not 
dangerous, if you break one jot of your promise or come one minute behind your 
hour, I will think you the most pathetical break-promise, and the most hollow 
lover, and the most unworthy of her you call Rosalind, that may be chosen out 
of the gross band of the unfaithful. Therefore, beware my censure, and keep 
your promise.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0 ":irc.foonet.org NOTICE tester :[07:00:32] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((mode 6 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1619593200")
+ (0.9 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: Grows, lives, and dies, 
in single blessedness.")
+ (0.25 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :alice: For these two hours, 
Rosalind, I will leave thee.")
+ (0.25 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: By this hand, it will 
not kill a fly. But come, now I will be your Rosalind in a more coming-on 
disposition; and ask me what you will, I will grant it.")
+ (0.25 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :alice: That I must love a 
loathed enemy.")
+ (0.25 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: As't please your 
lordship: I'll leave you."))
diff --git a/test/lisp/erc/resources/base/assoc/bumped/again.eld 
b/test/lisp/erc/resources/base/assoc/bumped/again.eld
new file mode 100644
index 0000000000..ab3c7b0621
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/bumped/again.eld
@@ -0,0 +1,30 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.0 ":irc.foonet.org 433 * tester :Nickname is reserved by a different 
account")
+ (0.0 ":irc.foonet.org FAIL NICK NICKNAME_RESERVED tester :Nickname is 
reserved by a different account"))
+
+((nick 3 "NICK tester`")
+ (0.1 ":irc.foonet.org 001 tester` :Welcome to the foonet IRC Network tester`")
+ (0.0 ":irc.foonet.org 002 tester` :Your host is irc.foonet.org, running 
version oragono-2.6.1-937b9b02368748e5")
+ (0.0 ":irc.foonet.org 003 tester` :This server was created Fri, 24 Sep 2021 
01:38:36 UTC")
+ (0.0 ":irc.foonet.org 004 tester` irc.foonet.org 
oragono-2.6.1-937b9b02368748e5 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.0 ":irc.foonet.org 005 tester` AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.1 ":irc.foonet.org 005 tester` MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.1 ":irc.foonet.org 005 tester` draft/CHATHISTORY=100 :are supported by 
this server")
+ (0.0 ":irc.foonet.org 251 tester` :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.0 ":irc.foonet.org 252 tester` 0 :IRC Operators online")
+ (0.0 ":irc.foonet.org 253 tester` 0 :unregistered connections")
+ (0.0 ":irc.foonet.org 254 tester` 1 :channels formed")
+ (0.0 ":irc.foonet.org 255 tester` :I have 3 clients and 0 servers")
+ (0.0 ":irc.foonet.org 265 tester` 3 3 :Current local users 3, max 3")
+ (0.2 ":irc.foonet.org 266 tester` 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.foonet.org 422 tester` :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester` +i")
+ (0.0 ":irc.foonet.org 221 tester` +i")
+ (0.0 ":irc.foonet.org NOTICE tester` :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((privmsg 42.6 "PRIVMSG NickServ :IDENTIFY tester changeme")
+ (0.01 ":tester`!~u@rpaau95je67ci.irc NICK tester")
+ (0.0 ":NickServ!NickServ@localhost NOTICE tester :You're now logged in as 
tester"))
diff --git a/test/lisp/erc/resources/base/assoc/bumped/foisted.eld 
b/test/lisp/erc/resources/base/assoc/bumped/foisted.eld
new file mode 100644
index 0000000000..5c36e58d9d
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/bumped/foisted.eld
@@ -0,0 +1,30 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running 
version oragono-2.6.1-937b9b02368748e5")
+ (0.0 ":irc.foonet.org 003 tester :This server was created Fri, 24 Sep 2021 
01:38:36 UTC")
+ (0.0 ":irc.foonet.org 004 tester irc.foonet.org 
oragono-2.6.1-937b9b02368748e5 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.01 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.01 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by 
this server")
+ (0.0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0.0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0.0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0.0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0.0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0.0 ":irc.foonet.org 221 tester +i")
+ (0.0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((privmsg 17.21 "PRIVMSG bob :hi")
+ (0.02 ":bob!~u@ecnnh95wr67pv.net PRIVMSG tester :hola")
+ (0.01 ":bob!~u@ecnnh95wr67pv.net PRIVMSG tester :how r u?"))
+
+((quit 18.19 "QUIT :" quit)
+ (0.01 ":tester!~u@rpaau95je67ci.irc QUIT :Quit: " quit))
+((drop 1 DROP))
diff --git a/test/lisp/erc/resources/base/assoc/bumped/refoisted.eld 
b/test/lisp/erc/resources/base/assoc/bumped/refoisted.eld
new file mode 100644
index 0000000000..33e4168ac4
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/bumped/refoisted.eld
@@ -0,0 +1,31 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.1 ":irc.foonet.org 001 dummy :Welcome to the foonet IRC Network dummy")
+ (0.0 ":irc.foonet.org 002 dummy :Your host is irc.foonet.org, running version 
oragono-2.6.1-937b9b02368748e5")
+ (0.0 ":irc.foonet.org 003 dummy :This server was created Fri, 24 Sep 2021 
01:38:36 UTC")
+ (0.0 ":irc.foonet.org 004 dummy irc.foonet.org oragono-2.6.1-937b9b02368748e5 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.0 ":irc.foonet.org 005 dummy AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.1 ":irc.foonet.org 005 dummy MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.1 ":irc.foonet.org 005 dummy draft/CHATHISTORY=100 :are supported by this 
server")
+ (0.0 ":irc.foonet.org 251 dummy :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.0 ":irc.foonet.org 252 dummy 0 :IRC Operators online")
+ (0.0 ":irc.foonet.org 253 dummy 0 :unregistered connections")
+ (0.0 ":irc.foonet.org 254 dummy 1 :channels formed")
+ (0.0 ":irc.foonet.org 255 dummy :I have 3 clients and 0 servers")
+ (0.0 ":irc.foonet.org 265 dummy 3 3 :Current local users 3, max 3")
+ (0.2 ":irc.foonet.org 266 dummy 3 3 :Current global users 3, max 3")
+ ;; Could arrive anytime around this point
+ (0.0 ":tester!~u@rpaau95je67ci.irc NICK :dummy")
+ (0.0 ":irc.foonet.org 422 dummy :MOTD File is missing")
+ ;; Playback
+ (0.01 ":bob!~u@ecnnh95wr67pv.net PRIVMSG dummy :back?")
+ )
+
+((mode-user 1.2 "MODE dummy +i")
+ (0.0 ":irc.foonet.org 221 dummy +i")
+ (0.0 ":irc.foonet.org NOTICE dummy :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((renick 42.6 "NICK tester")
+ (0.01 ":dummy!~u@rpaau95je67ci.irc NICK tester")
+ (0.0 ":NickServ!NickServ@localhost NOTICE dummy :You're now logged in as 
tester"))
diff --git a/test/lisp/erc/resources/base/assoc/bumped/renicked.eld 
b/test/lisp/erc/resources/base/assoc/bumped/renicked.eld
new file mode 100644
index 0000000000..4e96fd7304
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/bumped/renicked.eld
@@ -0,0 +1,30 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running 
version oragono-2.6.1-937b9b02368748e5")
+ (0.0 ":irc.foonet.org 003 tester :This server was created Fri, 24 Sep 2021 
01:38:36 UTC")
+ (0.0 ":irc.foonet.org 004 tester irc.foonet.org 
oragono-2.6.1-937b9b02368748e5 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.01 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.01 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by 
this server")
+ (0.0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0.0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0.0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0.0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0.0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 12 "MODE tester +i")
+ (0.0 ":irc.foonet.org 221 tester +i")
+ (0.0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((privmsg 17.21 "PRIVMSG NickServ :REGISTER changeme")
+ (0.02 ":NickServ!NickServ@localhost NOTICE tester :Account created")
+ (0.01 ":NickServ!NickServ@localhost NOTICE tester :You're now logged in as 
tester"))
+
+((quit 18.19 "QUIT :" quit)
+ (0.01 ":tester!~u@rpaau95je67ci.irc QUIT :Quit: " quit))
+((drop 1 DROP))
diff --git a/test/lisp/erc/resources/base/assoc/multi-net/barnet.eld 
b/test/lisp/erc/resources/base/assoc/multi-net/barnet.eld
new file mode 100644
index 0000000000..c62a22a11c
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/multi-net/barnet.eld
@@ -0,0 +1,42 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:19 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 8 "MODE tester +i")
+ (0 ":irc.barnet.org 221 tester +i")
+ (0 ":irc.barnet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 2 "JOIN #chan")
+ (0 ":tester!~u@jnu48g2wrycbw.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :@mike joe tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of NAMES list"))
+
+((mode 2 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1620104779")
+ (0.1 ":mike!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":joe!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":mike!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :joe: Whipp'd first, sir, and 
hang'd after.")
+ (0.1 ":joe!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :mike: We have yet many among 
us can gripe as hard as Cassibelan; I do not say I am one, but I have a hand. 
Why tribute ? why should we pay tribute ? If C sar can hide the sun from us 
with a blanket, or put the moon in his pocket, we will pay him tribute for 
light; else, sir, no more tribute, pray you now.")
+ (0.1 ":mike!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :joe: Double and treble 
admonition, and still forfeit in the same kind ? This would make mercy swear, 
and play the tyrant.")
+ (0.1 ":joe!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :mike: And secretly to greet 
the empress' friends.")
+ (0.1 ":mike!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :joe: You have not been 
inquired after: I have sat here all day.")
+ (0.1 ":joe!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :mike: That same Berowne I'll 
torture ere I go.")
+ (0.1 ":mike!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :joe: For mine own part,no 
offence to the general, nor any man of quality,I hope to be saved.")
+ (0.1 ":joe!~u@kd7gmjbnbkn8c.irc PRIVMSG #chan :mike: Mehercle! if their sons 
be ingenuous, they shall want no instruction; if their daughters be capable, I 
will put it to them. But, vir sapit qui pauca loquitur. A soul feminine 
saluteth us."))
diff --git a/test/lisp/erc/resources/base/assoc/multi-net/foonet.eld 
b/test/lisp/erc/resources/base/assoc/multi-net/foonet.eld
new file mode 100644
index 0000000000..f30b7deca1
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/multi-net/foonet.eld
@@ -0,0 +1,45 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 8 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 2 "JOIN #chan")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode 2 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: But, as it seems, did 
violence on herself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Well, this is the 
forest of Arden.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Signior Iachimo will 
not from it. Pray, let us follow 'em.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Our queen and all her 
elves come here anon.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: The ground is bloody; 
search about the churchyard.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: You have discharged 
this honestly: keep it to yourself. Many likelihoods informed me of this 
before, which hung so tottering in the balance that I could neither believe nor 
misdoubt. Pray you, leave me: stall this in your bosom; and I thank you for 
your honest care. I will speak with you further anon.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Give me that mattock, 
and the wrenching iron.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Stand you! You have 
land enough of your own; but he added to your having, gave you some ground.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Excellent workman! Thou 
canst not paint a man so bad as is thyself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: And will you, being a 
man of your breeding, be married under a bush, like a beggar ? Get you to 
church, and have a good priest that can tell you what marriage is: this fellow 
will but join you together as they join wainscot; then one of you will prove a 
shrunk panel, and like green timber, warp, warp.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Live, and be 
prosperous; and farewell, good fellow."))
diff --git a/test/lisp/erc/resources/base/assoc/reconplay/again.eld 
b/test/lisp/erc/resources/base/assoc/reconplay/again.eld
new file mode 100644
index 0000000000..4210c07e41
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/reconplay/again.eld
@@ -0,0 +1,42 @@
+;; -*- mode: lisp-data; -*-
+((pass 4.0 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running 
version oragono-2.6.0-7481bf0385b95b16")
+ (0.0 ":irc.foonet.org 003 tester :This server was created Wed, 16 Jun 2021 
04:15:00 UTC")
+ (0.0 ":irc.foonet.org 004 tester irc.foonet.org 
oragono-2.6.0-7481bf0385b95b16 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0.0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0.0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0.0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0.0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10 "MODE tester +i")
+ ;; No mode answer
+ (0.0 ":tester!~u@mw6kegwt77kwe.irc JOIN #chan")
+ (0.0 ":irc.foonet.org 353 tester = #chan :alice @bob tester")
+ (0.0 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0.0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0.0 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:37:52] bob: Thou pout'st 
upon thy fortune and thy love.")
+ (0.0 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:37:56] alice: With these 
mortals on the ground.")
+ (0.0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete."))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1623816901")
+ (0.1 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :alice: My name, my good lord, 
is Parolles.")
+ (0.1 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :bob: Wilt thou rest damned ? 
God help thee, shallow man! God make incision in thee! thou art raw."))
+
+((privmsg 3.0 "PRIVMSG *status :help")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :In the following list all 
occurrences of <#chan> support wildcards (* and ?) except ListNicks")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :\2Version\17: Print which version 
of ZNC this is")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :\2Shutdown [message]\17: Shut down 
ZNC completely")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :\2Restart [message]\17: Restart 
ZNC")
+ (0.1 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :alice: In that word's death; 
no words can that woe sound.")
+ (0.1 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :bob: Look, sir, here comes 
the lady towards my cell."))
diff --git a/test/lisp/erc/resources/base/assoc/reconplay/foonet.eld 
b/test/lisp/erc/resources/base/assoc/reconplay/foonet.eld
new file mode 100644
index 0000000000..6f50ecca4e
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/reconplay/foonet.eld
@@ -0,0 +1,52 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running 
version oragono-2.6.0-7481bf0385b95b16")
+ (0.0 ":irc.foonet.org 003 tester :This server was created Wed, 16 Jun 2021 
04:15:00 UTC")
+ (0.0 ":irc.foonet.org 004 tester irc.foonet.org 
oragono-2.6.0-7481bf0385b95b16 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0.0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0.0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0.0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0.0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 5 "MODE tester +i")
+ ;; No mode answer
+ (0.0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0.0 ":tester!~u@mw6kegwt77kwe.irc JOIN #chan")
+ (0.0 ":irc.foonet.org 353 tester = #chan :alice @bob tester")
+ (0.0 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0.0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0.0 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:35:50] bob: To Laced mon 
did my land extend.")
+ (0.0 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:35:55] alice: This is but 
a custom in your tongue; you bear a graver purpose, I hope.")
+ (0.0 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:37:16] bob: To imitate 
them; faults that are rich are fair.")
+ (0.0 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:37:18] alice: Our Romeo 
hath not been in bed to-night.")
+ (0.0 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:37:21] bob: But, in 
defence, by mercy, 'tis most just.")
+ (0.0 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :[10:37:25] alice: Younger than 
she are happy mothers made.")
+ (0.0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0.0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((mode 3 "MODE #chan")
+ (1.0 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1623816901")
+ (0.1 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :bob: At thy good heart's 
oppression.")
+ (0.1 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :alice: But purgatory, torture, 
hell itself."))
+
+((privmsg 3 "PRIVMSG *status :help")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :In the following list all 
occurrences of <#chan> support wildcards (* and ?) except ListNicks")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :\2AddPort <[+]port> <ipv4|ipv6|all> 
<web|irc|all> [bindhost [uriprefix]]\17: Add another port for ZNC to listen on")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :\2DelPort <port> <ipv4|ipv6|all> 
[bindhost]\17: Remove a port from ZNC")
+ (0.0 ":*status!znc@znc.in PRIVMSG tester :\2Rehash\17: Reload global 
settings, modules, and listeners from znc.conf")
+ (0.1 ":alice!~u@mw6kegwt77kwe.irc PRIVMSG #chan :bob: And at my suit, sweet, 
pardon what is past.")
+ (0.1 ":bob!~u@mw6kegwt77kwe.irc PRIVMSG #chan :alice: My lord, you give me 
most egregious indignity."))
+
+((quit 2 "QUIT :\2ERC\2"))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/assoc/samenet/chester.eld 
b/test/lisp/erc/resources/base/assoc/samenet/chester.eld
new file mode 100644
index 0000000000..f1aed2836c
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/samenet/chester.eld
@@ -0,0 +1,40 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK chester"))
+((user 1 "USER user 0 * :chester")
+ (0 ":irc.foonet.org 001 chester :Welcome to the foonet IRC Network chester")
+ (0 ":irc.foonet.org 002 chester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 chester :This server was created Sun, 13 Jun 2021 
05:45:20 UTC")
+ (0 ":irc.foonet.org 004 chester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 chester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 chester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 chester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 chester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 chester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 chester 1 :unregistered connections")
+ (0 ":irc.foonet.org 254 chester 1 :channels formed")
+ (0 ":irc.foonet.org 255 chester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 chester 3 4 :Current local users 3, max 4")
+ (0 ":irc.foonet.org 266 chester 3 4 :Current global users 3, max 4")
+ (0 ":irc.foonet.org 422 chester :MOTD File is missing"))
+
+((mode-user 12 "MODE chester +i")
+ (0 ":irc.foonet.org 221 chester +i")
+ (0 ":chester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 chester = #chan :tester chester @alice bob")
+ (0 ":irc.foonet.org 366 chester #chan :End of NAMES list")
+ (0 ":irc.foonet.org NOTICE chester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 chester #chan +nt")
+ (0.0 ":irc.foonet.org 329 chester #chan 1623563121")
+ (0.0 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Dispatch, I say, and 
find the forester.")
+ (0.0 ":tester!~u@yuvqisyu7m7qs.irc QUIT :Quit: " quit)
+ (0.5 ":tester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome again!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome again!"))
+
+((quit 20 "QUIT :" quit)
+ (0.0 ":chester!~u@yuvqisyu7m7qs.irc QUIT :Quit: " quit))
diff --git a/test/lisp/erc/resources/base/assoc/samenet/tester.eld 
b/test/lisp/erc/resources/base/assoc/samenet/tester.eld
new file mode 100644
index 0000000000..cd9cacbe5d
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/samenet/tester.eld
@@ -0,0 +1,42 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Sun, 13 Jun 2021 
05:45:20 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 12 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 15 "JOIN #chan")
+ (0 ":tester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :tester @alice bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1623563121")
+ (0.0 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome!")
+ (0.0 ":chester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Dispatch, I say, and 
find the forester."))
+
+((quit 4 "QUIT "))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/assoc/samenet/tester2.eld 
b/test/lisp/erc/resources/base/assoc/samenet/tester2.eld
new file mode 100644
index 0000000000..67c3a94a26
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/samenet/tester2.eld
@@ -0,0 +1,39 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Sun, 13 Jun 2021 
05:45:20 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 4.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect.")
+ (0 ":tester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :tester @alice bob chester")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((~useless-join 10 "JOIN #chan"))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1623563121")
+ (0.0 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome again!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome again!"))
+
+((quit 4 "QUIT :" quit)
+ (0 ":tester!~u@yuvqisyu7m7qs.irc QUIT :Quit: " quit))
+
+((linger 5 LINGER))
diff --git a/test/lisp/erc/resources/base/channel-buffer-revival/foonet.eld 
b/test/lisp/erc/resources/base/channel-buffer-revival/foonet.eld
new file mode 100644
index 0000000000..b09692327c
--- /dev/null
+++ b/test/lisp/erc/resources/base/channel-buffer-revival/foonet.eld
@@ -0,0 +1,45 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 12 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 6 "JOIN #chan")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode 8 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: But, as it seems, did 
violence on herself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Well, this is the 
forest of Arden.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Signior Iachimo will 
not from it. Pray, let us follow 'em.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Our queen and all her 
elves come here anon.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: The ground is bloody; 
search about the churchyard.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: You have discharged 
this honestly: keep it to yourself. Many likelihoods informed me of this 
before, which hung so tottering in the balance that I could neither believe nor 
misdoubt. Pray you, leave me: stall this in your bosom; and I thank you for 
your honest care. I will speak with you further anon.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Give me that mattock, 
and the wrenching iron.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Stand you! You have 
land enough of your own; but he added to your having, gave you some ground.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Excellent workman! Thou 
canst not paint a man so bad as is thyself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: And will you, being a 
man of your breeding, be married under a bush, like a beggar ? Get you to 
church, and have a good priest that can tell you what marriage is: this fellow 
will but join you together as they join wainscot; then one of you will prove a 
shrunk panel, and like green timber, warp, warp.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Live, and be 
prosperous; and farewell, good fellow."))
diff --git a/test/lisp/erc/resources/base/flood/soju.eld 
b/test/lisp/erc/resources/base/flood/soju.eld
new file mode 100644
index 0000000000..05266ca941
--- /dev/null
+++ b/test/lisp/erc/resources/base/flood/soju.eld
@@ -0,0 +1,87 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.13 ":soju.im 001 tester :Welcome to soju, tester")
+ (0.0 ":soju.im 002 tester :Your host is soju.im")
+ (0.0 ":soju.im 004 tester soju.im soju aiwroO OovaimnqpsrtklbeI")
+ (0.0 ":soju.im 005 tester CHATHISTORY=1000 CASEMAPPING=ascii NETWORK=Soju 
:are supported")
+ (0.0 ":soju.im 422 tester :No MOTD"))
+
+((mode 1 "MODE tester +i")
+ (0.0 ":tester!tester@10.0.2.100 JOIN #chan/foonet")
+ (0.25 ":soju.im 331 tester #chan/foonet :No topic is set")
+ (0.0 ":soju.im 353 tester = #chan/foonet :@bob/foonet alice/foonet tester")
+ (0.01 ":soju.im 366 tester #chan/foonet :End of /NAMES list")
+ (0.0 ":tester!tester@10.0.2.100 JOIN #chan/barnet")
+ (0.04 ":soju.im 331 tester #chan/barnet :No topic is set")
+ (0.0 ":soju.im 353 tester = #chan/barnet :tester @mike/barnet joe/barnet")
+ (0.01 ":soju.im 366 tester #chan/barnet :End of /NAMES list")
+ (0.01 ":bob/foonet PRIVMSG #chan/foonet :alice: Then this breaking of his has 
been but a try for his friends.")
+ (0.16 ":alice/foonet PRIVMSG #chan/foonet :bob: By my troth, I take my young 
lord to be a very melancholy man.")
+ (0.91 ":bob/foonet PRIVMSG #chan/foonet :alice: No, truly, for the truest 
poetry is the most feigning; and lovers are given to poetry, and what they 
swear in poetry may be said as lovers they do feign.")
+ (0.01 ":alice/foonet PRIVMSG #chan/foonet :bob: Sir, his wife some two months 
since fled from his house: her pretence is a pilgrimage to Saint Jaques le 
Grand; which holy undertaking with most austere sanctimony she accomplished; 
and, there residing, the tenderness of her nature became as a prey to her 
grief; in fine, made a groan of her last breath, and now she sings in heaven.")
+ (0.0 ":mike/barnet PRIVMSG #chan/barnet :joe: Who ? not the duke ? yes, your 
beggar of fifty, and his use was to put a ducat in her clack-dish; the duke had 
crotchets in him. He would be drunk too; that let me inform you.")
+ (0.01 ":joe/barnet PRIVMSG #chan/barnet :mike: Prove it before these varlets 
here, thou honourable man, prove it.")
+ (0.0 ":mike/barnet PRIVMSG #chan/barnet :joe: That my report is just and full 
of truth.")
+ (0.0 ":joe/barnet PRIVMSG #chan/barnet :mike: It is impossible they bear it 
out.")
+ ;; Expected, since we blindly send +i
+ (0.0 ":soju.im 501 tester :Cannot change user mode in multi-upstream mode"))
+
+((~mode-foonet 5 "MODE #chan/foonet")
+ (0.0 ":soju.im 324 tester #chan/foonet +nt")
+ (0.16 ":soju.im 329 tester #chan/foonet 1647158643")
+ ;; Start frantic pinging
+ (0.0 "PING :soju-msgid-1"))
+
+((~mode-barnet 5 "MODE #chan/barnet")
+ (0.0 ":soju.im 324 tester #chan/barnet +nt")
+ (0.0 ":soju.im 329 tester #chan/barnet 1647158643"))
+
+((pong-1 5 "PONG :soju-msgid-1")
+ (0.0 ":bob/foonet!~u@g56t7uz8xjj4e.irc PRIVMSG #chan/foonet :alice: The 
king's coming; I know by his trumpets. Sirrah, inquire further after me; I had 
talk of you last night: though you are a fool and a knave, you shall eat: go 
to, follow.")
+ (0.0 ":mike/barnet!~u@qsidzk5cytcai.irc PRIVMSG #chan/barnet :joe: Up: so. 
How is 't ? Feel you your legs ? You stand.")
+ (0.0 ":alice/foonet!~u@g56t7uz8xjj4e.irc PRIVMSG #chan/foonet :bob: Consider 
then we come but in despite.")
+ (0.1 "PING :soju-msgid-2"))
+
+((pong-2 2 "PONG :soju-msgid-2")
+ (0.1 ":joe/barnet!~u@qsidzk5cytcai.irc PRIVMSG #chan/barnet :mike: All hail, 
Macbeth! that shalt be king hereafter.")
+ (0.1 "PING :soju-msgid-3"))
+
+((pong-3 2 "PONG :soju-msgid-3")
+ (0.1 ":bob/foonet!~u@g56t7uz8xjj4e.irc PRIVMSG #chan/foonet :alice: And that 
at my bidding you could so stand up.")
+ (0.1 "PING :soju-msgid-4"))
+
+((pong-4 2 "PONG :soju-msgid-4")
+ (0.03 ":mike/barnet!~u@qsidzk5cytcai.irc PRIVMSG #chan/barnet :joe: Now he 
tells how she plucked him to my chamber. O! I see that nose of yours, but not 
the dog I shall throw it to.")
+ (0.1 "PING :soju-msgid-5"))
+
+((pong-5 2 "PONG :soju-msgid-5")
+ (0.1 ":alice/foonet!~u@g56t7uz8xjj4e.irc PRIVMSG #chan/foonet :bob: For 
policy sits above conscience.")
+ (0.1 "PING :soju-msgid-6"))
+
+((pong-6 2 "PONG :soju-msgid-6")
+ (0.0 ":joe/barnet!~u@qsidzk5cytcai.irc PRIVMSG #chan/barnet :mike: Take heed 
o' the foul fiend. Obey thy parents; keep thy word justly; swear not; commit 
not with man's sworn spouse; set not thy sweet heart on proud array. Tom's 
a-cold.")
+ (0.1 "PING :soju-msgid-7"))
+
+((pong-7 2 "PONG :soju-msgid-7")
+ (0.08 ":mike/barnet!~u@qsidzk5cytcai.irc PRIVMSG #chan/barnet :joe: To suffer 
with him. Good love, call him back.")
+ (0.1 "PING :soju-msgid-8"))
+
+((pong-9 2 "PONG :soju-msgid-8")
+ (0.1 ":bob/foonet!~u@g56t7uz8xjj4e.irc PRIVMSG #chan/foonet :alice: Be not 
obdurate, open thy deaf ears.")
+ (0.0 "PING :soju-msgid-9"))
+
+((pong-10 2 "PONG :soju-msgid-9")
+ (0.04 ":joe/barnet!~u@qsidzk5cytcai.irc PRIVMSG #chan/barnet :mike: To get 
good guard and go along with me.")
+ (0.1 "PING :soju-msgid-10"))
+
+((~privmsg 2 "PRIVMSG #chan/foonet :alice: hi")
+ (0.1 ":alice/foonet!~u@g56t7uz8xjj4e.irc PRIVMSG #chan/foonet :tester: Good, 
very good; it is so then: good, very good. Let it be concealed awhile."))
+
+((pong-11 2 "PONG :soju-msgid-10")
+ (0.1 ":alice/foonet!~u@g56t7uz8xjj4e.irc PRIVMSG #chan/foonet :bob: Some man 
or other must present Wall; and let him have some plaster, or some loam, or 
some rough-cast about him, to signify wall; and let him hold his fingers thus, 
and through that cranny shall Pyramus and Thisby whisper.")
+ (0.0 "PING :soju-msgid-11"))
+
+((pong-12 5 "PONG :soju-msgid-11")
+ (0.1 ":mike/barnet!~u@qsidzk5cytcai.irc PRIVMSG #chan/barnet :joe: That's he 
that was Othello; here I am."))
diff --git a/test/lisp/erc/resources/base/gapless-connect/barnet.eld 
b/test/lisp/erc/resources/base/gapless-connect/barnet.eld
new file mode 100644
index 0000000000..4e658802ef
--- /dev/null
+++ b/test/lisp/erc/resources/base/gapless-connect/barnet.eld
@@ -0,0 +1,40 @@
+;; -*- mode: lisp-data; -*-
+((pass 10 "PASS :barnet:changeme"))
+((nick 10 "NICK tester"))
+((user 0.2 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.5.1-4860c5cad0179db1")
+ (0 ":irc.barnet.org 003 tester :This server was created Fri, 19 Mar 2021 
10:23:19 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.5.1-4860c5cad0179db1 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m INVEX KICKLEN=390 MAXLIST=beI:60 :are supported by 
this server")
+ (0 ":irc.barnet.org 005 tester MAXTARGETS=4 MODES MONITOR=100 NETWORK=barnet 
NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX draft/CHATHISTORY=100 :are 
supported by this server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 1 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 0 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 1 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 1 1 :Current local users 1, max 1")
+ (0 ":irc.barnet.org 266 tester 1 1 :Current global users 1, max 1")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@8cgjyczyrjgby.irc JOIN #bar")
+ (0 ":irc.barnet.org 353 tester = #bar :@mike joe tester")
+ (0 ":irc.barnet.org 366 tester #bar :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #bar :Buffer Playback...")
+ (0 ":joe!~u@8cgjyczyrjgby.irc PRIVMSG #bar :[10:23:28] tester, welcome!")
+ (0 ":mike!~u@8cgjyczyrjgby.irc PRIVMSG #bar :[10:23:28] tester, welcome!")
+ (0 ":joe!~u@8cgjyczyrjgby.irc PRIVMSG #bar :[10:24:49] mike: Bid me farewell, 
and let me hear thee going.")
+ (0 ":mike!~u@8cgjyczyrjgby.irc PRIVMSG #bar :[10:24:54] joe: By heaven, thy 
love is black as ebony.")
+ (0 ":***!znc@znc.in PRIVMSG #bar :Playback Complete.")
+ (0 ":irc.barnet.org NOTICE tester :[10:23:22] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
+
+((mode 20 "MODE #bar")
+ (0 ":irc.barnet.org 324 tester #bar +nt")
+ (0 ":irc.barnet.org 329 tester #bar 1616149403")
+ (0.1 ":mike!~u@8cgjyczyrjgby.irc PRIVMSG #bar :joe: To ask of whence you are: 
report it.")
+ (0.1 ":joe!~u@8cgjyczyrjgby.irc PRIVMSG #bar :mike: Friar, thou knowest not 
the duke so well as I do: he's a better woodman than thou takest him for.")
+ (0.1 ":mike!~u@8cgjyczyrjgby.irc PRIVMSG #bar :joe: Like the sequel, I. 
Signior Costard, adieu.")
+ (0.1 ":joe!~u@8cgjyczyrjgby.irc PRIVMSG #bar :mike: This is his second fit; 
he had one yesterday."))
diff --git a/test/lisp/erc/resources/base/gapless-connect/foonet.eld 
b/test/lisp/erc/resources/base/gapless-connect/foonet.eld
new file mode 100644
index 0000000000..4ac4a3e596
--- /dev/null
+++ b/test/lisp/erc/resources/base/gapless-connect/foonet.eld
@@ -0,0 +1,41 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Sun, 25 Apr 2021 
11:28:28 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@xrir8fpe4d7ak.irc JOIN #foo")
+ (0 ":irc.foonet.org 353 tester = #foo :joe @mike tester")
+ (0 ":irc.foonet.org 366 tester #foo :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Buffer Playback...")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :[07:02:41] bob: To-morrow is 
the joyful day, Audrey; to-morrow will we be married.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :[07:02:44] alice: Why dost thou 
call them knaves ? thou know'st them not.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :[07:03:05] bob: Now, by the 
faith of my love, I will: tell me where it is.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :[07:03:09] alice: Give me the 
letter; I will look on it.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Playback Complete.")
+ (0 ":irc.foonet.org NOTICE tester :[11:29:00] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((mode 8 "MODE #foo")
+ (0 ":irc.foonet.org 324 tester #foo +nt")
+ (0 ":irc.foonet.org 329 tester #foo 1619593200")
+ (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :bob: By this hand, it will 
not kill a fly. But come, now I will be your Rosalind in a more coming-on 
disposition; and ask me what you will, I will grant it.")
+ (0.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :alice: That I must love a 
loathed enemy.")
+ (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :bob: His discretion, I am 
sure, cannot carry his valour, for the goose carries not the fox. It is well: 
leave it to his discretion, and let us listen to the moon.")
+ (0.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #foo :alice: As living here and you 
no use of him."))
diff --git a/test/lisp/erc/resources/base/gapless-connect/pass-stub.eld 
b/test/lisp/erc/resources/base/gapless-connect/pass-stub.eld
new file mode 100644
index 0000000000..0c8dfd19d0
--- /dev/null
+++ b/test/lisp/erc/resources/base/gapless-connect/pass-stub.eld
@@ -0,0 +1,4 @@
+;; -*- mode: lisp-data; -*-
+((pass 3 "PASS :" token ":changeme"))
+
+((fake 1 "FAKE no op"))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld 
b/test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld
new file mode 100644
index 0000000000..766035a524
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld
@@ -0,0 +1,50 @@
+;; -*- mode: lisp-data; -*-
+((pass 10 "PASS :barnet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Wed, 12 May 2021 
07:41:08 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer ^
+
+ (0 ":tester!~u@xrir8fpe4d7ak.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :joe @mike tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:25] mike: Belike, for joy 
the emperor hath a son.")
+ (0 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:27] joe: Protest their 
first of manhood.")
+ (0 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:29] mike: As frozen water 
to a starved snake.")
+ (0 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:34] joe: My mirth it 
much displeas'd, but pleas'd my woe.")
+ (0 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:38] mike: Why, Marcus, no 
man should be mad but I.")
+ (0 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :[07:04:44] joe: Faith, I have 
heard too much, for your words and performances are no kin together.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0 ":irc.barnet.org NOTICE tester :[07:00:01] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
+
+((~join 3 "JOIN #chan"))
+
+((mode 5 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1620805269")
+ (0.1 ":joe!~u@svpn88yjcdj42.irc PRIVMSG #chan :mike: But, in defence, by 
mercy, 'tis most just.")
+ (0.1 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :joe: The Marshal of France, 
Monsieur la Far.")
+ (0.1 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :mike: And bide the penance of 
each three years' day.")
+ (0.1 ":mike!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :joe: Madam, within; but never 
man so chang'd.")
+ (0.1 ":joe!~u@xrir8fpe4d7ak.irc PRIVMSG #chan :mike: As much in private, and 
I'll bid adieu."))
+
+((linger 10 LINGER))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld 
b/test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld
new file mode 100644
index 0000000000..2c3d297b9c
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/bouncer/barnet-drop.eld
@@ -0,0 +1,41 @@
+;; -*- mode: lisp-data; -*-
+((pass 10 "PASS :barnet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Wed, 12 May 2021 
07:41:08 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer ^
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
+
+((join 1 "JOIN #chan")
+ (0 ":tester!~u@awyxgybtkx7uq.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :@joe mike tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of NAMES list")
+ (0.1 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode 1 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1620805269")
+ (0.1 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :joe: But you have outfaced 
them all.")
+ (0.1 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :mike: Why, will shall break 
it; will, and nothing else.")
+ (0.1 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :joe: Yes, a dozen; and as 
many to the vantage, as would store the world they played for.")
+ (0.05 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :mike: As he regards his aged 
father's life.")
+ (0.05 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :joe: It is a rupture that 
you may easily heal; and the cure of it not only saves your brother, but keeps 
you from dishonour in doing it."))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/barnet.eld 
b/test/lisp/erc/resources/base/netid/bouncer/barnet.eld
new file mode 100644
index 0000000000..abfcc6ed48
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/bouncer/barnet.eld
@@ -0,0 +1,41 @@
+;; -*- mode: lisp-data; -*-
+((pass 3 "PASS :barnet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Wed, 12 May 2021 
07:41:08 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer ^
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
+
+((join 1 "JOIN #chan")
+ (0 ":tester!~u@awyxgybtkx7uq.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :@joe mike tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of NAMES list")
+ (0.1 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode 3 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1620805269")
+ (0.1 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :joe: But you have outfaced 
them all.")
+ (0.1 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :mike: Why, will shall break 
it; will, and nothing else.")
+ (0.1 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :joe: Yes, a dozen; and as 
many to the vantage, as would store the world they played for.")
+ (0.05 ":joe!~u@awyxgybtkx7uq.irc PRIVMSG #chan :mike: As he regards his aged 
father's life.")
+ (0.05 ":mike!~u@awyxgybtkx7uq.irc PRIVMSG #chan :joe: It is a rupture that 
you may easily heal; and the cure of it not only saves your brother, but keeps 
you from dishonour in doing it."))
+
+((linger 1 LINGER))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld 
b/test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld
new file mode 100644
index 0000000000..bf8712305a
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld
@@ -0,0 +1,50 @@
+;; -*- mode: lisp-data; -*-
+((pass 10 "PASS :foonet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Wed, 12 May 2021 
07:41:09 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer ^
+ (0 ":tester!~u@nvfhxvqm92rm6.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice @bob tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:02] alice: Here come the 
lovers, full of joy and mirth.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:07] bob: According to 
the fool's bolt, sir, and such dulcet diseases.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:10] alice: And hang 
himself. I pray you, do my greeting.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:18] bob: And you sat 
smiling at his cruel prey.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:21] alice: Or never after 
look me in the face.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:25] bob: If that may 
be, than all is well. Come, sit down, every mother's son, and rehearse your 
parts. Pyramus, you begin: when you have spoken your speech, enter into that 
brake; and so every one according to his cue.")
+ (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:30] alice: Where I espied 
the panther fast asleep.")
+ (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:32] bob: Alas! he is 
too young: yet he looks successfully.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+
+ (0 ":irc.foonet.org NOTICE tester :[07:00:32] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((~join 3 "JOIN #chan"))
+
+((mode 8 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620805271")
+ (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: Grows, lives, and dies, 
in single blessedness.")
+ (0.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :alice: For these two hours, 
Rosalind, I will leave thee.")
+ (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: By this hand, it will 
not kill a fly. But come, now I will be your Rosalind in a more coming-on 
disposition; and ask me what you will, I will grant it.")
+ (0.1 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :alice: That I must love a 
loathed enemy.")
+ (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: As't please your 
lordship: I'll leave you."))
+
+((linger 10 LINGER))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld 
b/test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld
new file mode 100644
index 0000000000..e3c41e2133
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/bouncer/foonet-drop.eld
@@ -0,0 +1,46 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Wed, 12 May 2021 
07:41:09 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer ^
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((join 1 "JOIN #chan")
+ (0 ":tester!~u@ertp7idh9jtgi.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :@alice bob tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode 1 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620805271")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: He cannot be heard of. 
Out of doubt he is transported.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: More evident than this; 
for this was stol'n.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: Sell when you can; you 
are not for all markets.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: There's the fool hangs 
on your back already.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: Why, if you have a 
stomach to't, monsieur, if you think your mystery in stratagem can bring this 
instrument of honour again into its native quarter, be magnanimous in the 
enterprise and go on; I will grace the attempt for a worthy exploit: if you 
speed well in it, the duke shall both speak of it, and extend to you what 
further becomes his greatness, even to the utmost syllable of your worthiness.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: For he hath still been 
tried a holy man.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: To have the touches 
dearest priz'd.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: And must advise the 
emperor for his good.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: Orlando, my liege; the 
youngest son of Sir Rowland de Boys.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: The ape is dead, and I 
must conjure him."))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/foonet.eld 
b/test/lisp/erc/resources/base/netid/bouncer/foonet.eld
new file mode 100644
index 0000000000..c241c59bb8
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/bouncer/foonet.eld
@@ -0,0 +1,46 @@
+;; -*- mode: lisp-data; -*-
+((pass 3 "PASS :foonet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Wed, 12 May 2021 
07:41:09 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 4.2 "MODE tester +i")
+ ;; No mode answer ^
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((join 1 "JOIN #chan")
+ (0 ":tester!~u@ertp7idh9jtgi.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :@alice bob tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode 3 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620805271")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: He cannot be heard of. 
Out of doubt he is transported.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: More evident than this; 
for this was stol'n.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: Sell when you can; you 
are not for all markets.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: There's the fool hangs 
on your back already.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: Why, if you have a 
stomach to't, monsieur, if you think your mystery in stratagem can bring this 
instrument of honour again into its native quarter, be magnanimous in the 
enterprise and go on; I will grace the attempt for a worthy exploit: if you 
speed well in it, the duke shall both speak of it, and extend to you what 
further becomes his greatness, even to the utmost syllable of your worthiness.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: For he hath still been 
tried a holy man.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: To have the touches 
dearest priz'd.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: And must advise the 
emperor for his good.")
+ (0.1 ":alice!~u@ertp7idh9jtgi.irc PRIVMSG #chan :bob: Orlando, my liege; the 
youngest son of Sir Rowland de Boys.")
+ (0.1 ":bob!~u@ertp7idh9jtgi.irc PRIVMSG #chan :alice: The ape is dead, and I 
must conjure him."))
+
+((linger 1 LINGER))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/stub-again.eld 
b/test/lisp/erc/resources/base/netid/bouncer/stub-again.eld
new file mode 100644
index 0000000000..c666ee4fa0
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/bouncer/stub-again.eld
@@ -0,0 +1,4 @@
+;; -*- mode: lisp-data; -*-
+((pass 10 "PASS :" token ":changeme"))
+
+((fake 1 "FAKE no op"))
diff --git a/test/lisp/erc/resources/base/netid/samenet/chester.eld 
b/test/lisp/erc/resources/base/netid/samenet/chester.eld
new file mode 100644
index 0000000000..8c2448733c
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/samenet/chester.eld
@@ -0,0 +1,48 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK chester"))
+((user 1 "USER user 0 * :chester")
+ (0 ":irc.foonet.org 001 chester :Welcome to the foonet IRC Network chester")
+ (0 ":irc.foonet.org 002 chester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 chester :This server was created Sun, 13 Jun 2021 
05:45:20 UTC")
+ (0 ":irc.foonet.org 004 chester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 chester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 chester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 chester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 chester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 chester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 chester 1 :unregistered connections")
+ (0 ":irc.foonet.org 254 chester 1 :channels formed")
+ (0 ":irc.foonet.org 255 chester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 chester 3 4 :Current local users 3, max 4")
+ (0 ":irc.foonet.org 266 chester 3 4 :Current global users 3, max 4")
+ (0 ":irc.foonet.org 422 chester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE chester +i")
+ (0 ":irc.foonet.org 221 chester +i")
+ (0 ":irc.foonet.org NOTICE chester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 14 "JOIN #chan")
+ (0 ":chester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 chester = #chan :tester chester @alice bob")
+ (0 ":irc.foonet.org 366 chester #chan :End of NAMES list"))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 chester #chan +nt")
+ (0.0 ":irc.foonet.org 329 chester #chan 1623563121")
+ (0.0 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: That ever eye with 
sight made heart lament.")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: The bitter past, more 
welcome is the sweet.")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Dispatch, I say, and 
find the forester.")
+ (0.1 ":tester!~u@yuvqisyu7m7qs.irc PRIVMSG #chan :chester: hi")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: This was lofty! Now 
name the rest of the players. This is Ercles' vein, a tyrant's vein; a lover is 
more condoling."))
+
+((privmsg 4 "PRIVMSG #chan :hi tester")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: As the ox hath his bow, 
sir, the horse his curb, and the falcon her bells, so man hath his desires; and 
as pigeons bill, so wedlock would be nibbling.")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: Most friendship is 
feigning, most loving mere folly.")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: To employ you towards 
this Roman. Come, our queen."))
+
+((quit 5 "QUIT :" quit)
+ (0.0 ":tester!~u@yuvqisyu7m7qs.irc QUIT :Quit: " quit)
+ (0.0 ":chester!~u@yuvqisyu7m7qs.irc QUIT :Quit: " quit))
diff --git a/test/lisp/erc/resources/base/netid/samenet/tester.eld 
b/test/lisp/erc/resources/base/netid/samenet/tester.eld
new file mode 100644
index 0000000000..76312a7a14
--- /dev/null
+++ b/test/lisp/erc/resources/base/netid/samenet/tester.eld
@@ -0,0 +1,52 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Sun, 13 Jun 2021 
05:45:20 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 15 "JOIN #chan")
+ (0 ":tester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :tester @alice bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1623563121")
+ (0.0 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Marry, that, I think, 
be young Petruchio.")
+ (0.4 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: You speak of him when 
he was less furnished than now he is with that which makes him both without and 
within.")
+ (0.2 ":chester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: That ever eye with 
sight made heart lament.")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: The bitter past, more 
welcome is the sweet.")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Dispatch, I say, and 
find the forester."))
+
+((privmsg 3 "PRIVMSG #chan :chester: hi")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: This was lofty! Now 
name the rest of the players. This is Ercles' vein, a tyrant's vein; a lover is 
more condoling.")
+ (0.1 ":chester!~u@yuvqisyu7m7qs.irc PRIVMSG #chan :hi tester")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: As the ox hath his bow, 
sir, the horse his curb, and the falcon her bells, so man hath his desires; and 
as pigeons bill, so wedlock would be nibbling.")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: Most friendship is 
feigning, most loving mere folly.")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: To employ you towards 
this Roman. Come, our queen."))
+
+((quit 4 "QUIT :" quit)
+ (0 ":tester!~u@yuvqisyu7m7qs.irc QUIT :Quit: " quit))
diff --git a/test/lisp/erc/resources/base/reconnect/aborted-dupe.eld 
b/test/lisp/erc/resources/base/reconnect/aborted-dupe.eld
new file mode 100644
index 0000000000..8e299ec44c
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/aborted-dupe.eld
@@ -0,0 +1,28 @@
+;; -*- mode: lisp-data; -*-
+((pass 3 "PASS :changeme"))
+((nick 1 "NICK tester"))
+
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (-0.02 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (-0.02 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (-0.02 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (-0.02 ":irc.foonet.org 254 tester 1 :channels formed")
+ (-0.02 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (-0.02 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (-0.02 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (-0.02 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((~mode-user 3.2 "MODE tester +i")
+ (-0.02 ":irc.foonet.org 221 tester +i")
+ (-0.02 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((~join 10 "JOIN #chan"))
+((eof 5 EOF))
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/reconnect/aborted.eld 
b/test/lisp/erc/resources/base/reconnect/aborted.eld
new file mode 100644
index 0000000000..5c32070d85
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/aborted.eld
@@ -0,0 +1,45 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 12 "JOIN #chan")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode 10 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: But, as it seems, did 
violence on herself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Well, this is the 
forest of Arden.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Signior Iachimo will 
not from it. Pray, let us follow 'em.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Our queen and all her 
elves come here anon.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: The ground is bloody; 
search about the churchyard.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: You have discharged 
this honestly: keep it to yourself. Many likelihoods informed me of this 
before, which hung so tottering in the balance that I could neither believe nor 
misdoubt. Pray you, leave me: stall this in your bosom; and I thank you for 
your honest care. I will speak with you further anon.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Give me that mattock, 
and the wrenching iron.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Stand you! You have 
land enough of your own; but he added to your having, gave you some ground.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Excellent workman! Thou 
canst not paint a man so bad as is thyself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: And will you, being a 
man of your breeding, be married under a bush, like a beggar ? Get you to 
church, and have a good priest that can tell you what marriage is: this fellow 
will but join you together as they join wainscot; then one of you will prove a 
shrunk panel, and like green timber, warp, warp.")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Live, and be 
prosperous; and farewell, good fellow."))
diff --git a/test/lisp/erc/resources/base/reconnect/options-again.eld 
b/test/lisp/erc/resources/base/reconnect/options-again.eld
new file mode 100644
index 0000000000..f1fcc439cc
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/options-again.eld
@@ -0,0 +1,45 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is still in debug mode."))
+
+((~join-chan 12 "JOIN #chan")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((~join-spam 12 "JOIN #spam")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #spam")
+ (0 ":irc.foonet.org 353 tester = #spam :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #spam :End of NAMES list"))
+
+((~mode-chan 4 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: But, as it seems, did 
violence on herself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Well, this is the 
forest of Arden."))
+
+((mode-spam 4 "MODE #spam")
+ (0 ":irc.foonet.org 324 tester #spam +nt")
+ (0 ":irc.foonet.org 329 tester #spam 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #spam :alice: Signior Iachimo will 
not from it. Pray, let us follow 'em.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #spam :bob: Our queen and all her 
elves come here anon."))
diff --git a/test/lisp/erc/resources/base/reconnect/options.eld 
b/test/lisp/erc/resources/base/reconnect/options.eld
new file mode 100644
index 0000000000..3b305d8559
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/options.eld
@@ -0,0 +1,35 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode.")
+
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode-chan 4 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!"))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/reconnect/timer-last.eld 
b/test/lisp/erc/resources/base/reconnect/timer-last.eld
new file mode 100644
index 0000000000..23849bc1ba
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/timer-last.eld
@@ -0,0 +1,6 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.znc.in 464 tester :Invalid Password"))
+((linger 1 LINGER))
diff --git a/test/lisp/erc/resources/base/reconnect/timer.eld 
b/test/lisp/erc/resources/base/reconnect/timer.eld
new file mode 100644
index 0000000000..95c6af8d88
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/timer.eld
@@ -0,0 +1,6 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.znc.in 464 tester :Invalid Password"))
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/renick/queries/bouncer-barnet.eld 
b/test/lisp/erc/resources/base/renick/queries/bouncer-barnet.eld
new file mode 100644
index 0000000000..fc6cdaafe9
--- /dev/null
+++ b/test/lisp/erc/resources/base/renick/queries/bouncer-barnet.eld
@@ -0,0 +1,54 @@
+;; -*- mode: lisp-data; -*-
+((pass 3 "PASS :barnet:changeme"))
+((nick 3 "NICK tester"))
+((user 3 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Tue, 01 Jun 2021 
07:49:23 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 3.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@286u8jcpis84e.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :@joe mike rando tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":joe!~u@286u8jcpis84e.irc PRIVMSG #chan :[09:19:19] mike: Chi non te 
vede, non te pretia.")
+ (0 ":mike!~u@286u8jcpis84e.irc PRIVMSG #chan :[09:19:28] joe: The valiant 
heart's not whipt out of his trade.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0 ":rando!~u@95i756tt32ym8.irc PRIVMSG tester :[09:18:20] Why'd you pull 
that scene at the arcade?")
+ (0 ":rando!~u@95i756tt32ym8.irc PRIVMSG tester :[09:18:32] I had to mess up 
this rentacop came after me with nunchucks.")
+ (0 ":irc.barnet.org NOTICE tester :[09:13:24] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
+
+((mode 5 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1622538742")
+ (0.1 ":joe!~u@286u8jcpis84e.irc PRIVMSG #chan :mike: By favours several which 
they did bestow.")
+ (0.1 ":mike!~u@286u8jcpis84e.irc PRIVMSG #chan :joe: You, Roderigo! come, 
sir, I am for you."))
+
+((privmsg-a 5 "PRIVMSG rando :Linda said you were gonna kill me.")
+ (0.1 ":joe!~u@286u8jcpis84e.irc PRIVMSG #chan :mike: Play, music, then! Nay, 
you must do it soon.")
+ (0.1 ":rando!~u@95i756tt32ym8.irc PRIVMSG tester :Linda said? I never saw her 
before I came up here.")
+ (0.1 ":mike!~u@286u8jcpis84e.irc PRIVMSG #chan :joe: Of arts inhibited and 
out of warrant."))
+
+((privmsg-b 3 "PRIVMSG rando :You aren't with Wage?")
+ (0.1 ":joe!~u@286u8jcpis84e.irc PRIVMSG #chan :mike: But most of all, 
agreeing with the proclamation.")
+ (0.1 ":rando!~u@95i756tt32ym8.irc PRIVMSG tester :I think you screwed up, 
Case.")
+ (0.1 ":mike!~u@286u8jcpis84e.irc PRIVMSG #chan :joe: Good gentleman, go your 
gait, and let poor volk pass. An chud ha' bin zwaggered out of my life, 'twould 
not ha' bin zo long as 'tis by a vortnight. Nay, come not near th' old man; 
keep out, che vor ye, or ise try whether your costard or my ballow be the 
harder. Chill be plain with you.")
+ ;; Nick change
+ (0.1 ":rando!~u@95i756tt32ym8.irc NICK frenemy")
+ (0.1 ":joe!~u@286u8jcpis84e.irc PRIVMSG #chan :mike: Till time beget some 
careful remedy.")
+ (0.1 ":frenemy!~u@95i756tt32ym8.irc PRIVMSG tester :I showed up and you just 
fit me right into your reality picture.")
+ (0.1 ":mike!~u@286u8jcpis84e.irc PRIVMSG #chan :joe: For I have lost him on a 
dangerous sea."))
diff --git a/test/lisp/erc/resources/base/renick/queries/bouncer-foonet.eld 
b/test/lisp/erc/resources/base/renick/queries/bouncer-foonet.eld
new file mode 100644
index 0000000000..162e8bf965
--- /dev/null
+++ b/test/lisp/erc/resources/base/renick/queries/bouncer-foonet.eld
@@ -0,0 +1,52 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 01 Jun 2021 
07:49:22 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 5.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@u4mvbswyw8gbg.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice @bob rando tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":bob!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :[09:19:28] alice: Great men 
should drink with harness on their throats.")
+ (0 ":alice!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :[09:19:31] bob: Your lips will 
feel them the sooner: shallow again. A more sounder instance; come.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0 ":rando!~u@bivkhq8yav938.irc PRIVMSG tester :[09:17:51] u thur?")
+ (0 ":rando!~u@bivkhq8yav938.irc PRIVMSG tester :[09:17:58] guess not")
+ (0 ":irc.foonet.org NOTICE tester :[09:12:53] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((mode 10 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1622538742")
+ (0.1 ":bob!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :alice: When there is nothing 
living but thee, thou shalt be welcome. I had rather be a beggar's dog than 
Apemantus.")
+ (0.1 ":alice!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :bob: You have simply misused 
our sex in your love-prate: we must have your doublot and hose plucked over 
your head, and show the world what the bird hath done to her own nest."))
+
+((privmsg-a 6 "PRIVMSG rando :I here")
+ (0.1 ":bob!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :alice: And I will make thee 
think thy swan a crow.")
+ (0.1 ":rando!~u@bivkhq8yav938.irc PRIVMSG tester :u are dumb")
+ (0.1 ":alice!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :bob: Lie not, to say mine 
eyes are murderers."))
+
+((privmsg-b 3 "PRIVMSG rando :not so")
+ (0.1 ":bob!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :alice: Commit myself, my 
person, and the cause.")
+ ;; Nick change
+ (0.1 ":rando!~u@bivkhq8yav938.irc NICK frenemy")
+ (0.1 ":alice!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :bob: Of raging waste! It 
cannot hold; it will not.")
+ (0.1 ":frenemy!~u@bivkhq8yav938.irc PRIVMSG tester :doubly so")
+ (0.1 ":bob!~u@u4mvbswyw8gbg.irc PRIVMSG #chan :alice: These words are razors 
to my wounded heart."))
diff --git a/test/lisp/erc/resources/base/renick/queries/solo.eld 
b/test/lisp/erc/resources/base/renick/queries/solo.eld
new file mode 100644
index 0000000000..12fa7d264e
--- /dev/null
+++ b/test/lisp/erc/resources/base/renick/queries/solo.eld
@@ -0,0 +1,55 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Mon, 31 May 2021 
09:56:24 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 2 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 8 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc JOIN #foo")
+ (0 ":irc.foonet.org 353 tester = #foo :alice @bob Lal tester")
+ (0 ":irc.foonet.org 366 tester #foo :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Buffer Playback...")
+ (0 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :[10:00:02] bob: All that he is 
hath reference to your highness.")
+ (0 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :[10:00:06] alice: Excellent 
workman! Thou canst not paint a man so bad as is thyself.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Playback Complete.")
+ (0 ":irc.foonet.org NOTICE tester :[09:56:57] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((mode 1 "MODE #foo")
+ (0 ":irc.foonet.org 324 tester #foo +nt")
+ (0 ":irc.foonet.org 329 tester #foo 1622454985")
+ (0.1 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :bob: Farewell, pretty lady: 
you must hold the credit of your father.")
+ (0.1 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :alice: On Thursday, sir ? the 
time is very short."))
+
+((privmsg-a 10 "PRIVMSG #foo :hi")
+ (0.2 ":Lal!~u@b82mytupn2t5k.irc PRIVMSG tester :hello")
+ (0.2 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :alice: And brought to yoke, the 
enemies of Rome.")
+ (0.2 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :bob: Thou art thy father's 
daughter; there's enough."))
+
+((privmsg-b 10 "PRIVMSG Lal :hi")
+ (0.2 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :alice: Here are the beetle 
brows shall blush for me.")
+ (0.2 ":Lal!~u@b82mytupn2t5k.irc NICK Linguo")
+ (0.2 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :bob: He hath abandoned his 
physicians, madam; under whose practices he hath persecuted time with hope, and 
finds no other advantage in the process but only the losing of hope by time."))
+
+((privmsg-c 10 "PRIVMSG Linguo :howdy Linguo")
+ (0.1 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :alice: And brought to yoke, the 
enemies of Rome.")
+ (0.2 ":Linguo!~u@b82mytupn2t5k.irc PART #foo"))
+
+((part 10 "PART #foo :\2ERC\2")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc PART #foo :\2ERC\2")
+ (0.1 ":Linguo!~u@b82mytupn2t5k.irc PRIVMSG tester :get along little doggie"))
diff --git a/test/lisp/erc/resources/base/renick/self/auto.eld 
b/test/lisp/erc/resources/base/renick/self/auto.eld
new file mode 100644
index 0000000000..851db7f1cf
--- /dev/null
+++ b/test/lisp/erc/resources/base/renick/self/auto.eld
@@ -0,0 +1,46 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the FooNet Internet Relay Chat 
Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is 
irc.foonet.org[188.240.145.101/6697], running version solanum-1.0-dev")
+ (0 ":irc.foonet.org 003 tester :This server was created Sat May 22 2021 at 
19:04:17 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org solanum-1.0-dev 
DGQRSZaghilopsuwz CFILMPQSbcefgijklmnopqrstuvz bkloveqjfI")
+ (0 ":irc.foonet.org 005 tester WHOX FNC KNOCK SAFELIST ELIST=CTU CALLERID=g 
MONITOR=100 ETRACE CHANTYPES=# EXCEPTS INVEX 
CHANMODES=eIbq,k,flj,CFLMPQScgimnprstuz :are supported by this server")
+ (0 ":irc.foonet.org 005 tester CHANLIMIT=#:250 PREFIX=(ov)@+ MAXLIST=bqeI:100 
MODES=4 NETWORK=foonet STATUSMSG=@+ CASEMAPPING=rfc1459 NICKLEN=16 
MAXNICKLEN=16 CHANNELLEN=50 TOPICLEN=390 DEAF=D :are supported by this server")
+ (0 ":irc.foonet.org 005 tester 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:4,NOTICE:4,ACCEPT:,MONITOR: 
EXTBAN=$,ajrxz CLIENTVER=3.0 :are supported by this server")
+ (0 ":irc.foonet.org 251 tester :There are 33 users and 14113 invisible on 17 
servers")
+ (0 ":irc.foonet.org 252 tester 34 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 12815 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 726 clients and 1 servers")
+ (0 ":irc.foonet.org 265 tester 726 739 :Current local users 726, max 739")
+ (0 ":irc.foonet.org 266 tester 14146 14541 :Current global users 14146, max 
14541")
+ (0 ":irc.foonet.org 250 tester :Highest connection count: 740 (739 clients) 
(3790 connections received)")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc NICK :dummy")
+ (0 ":irc.foonet.org 375 dummy :- irc.foonet.org Message of the Day - ")
+ (0 ":irc.foonet.org 372 dummy :- This server provided by NORDUnet/SUNET")
+ (0 ":irc.foonet.org 372 dummy :- Welcome to foonet, the IRC network for free 
& open-source software")
+ (0 ":irc.foonet.org 372 dummy :- and peer directed projects.")
+ (0 ":irc.foonet.org 372 dummy :-  ")
+ (0 ":irc.foonet.org 372 dummy :- Please visit us in #libera for questions and 
support.")
+ (0 ":irc.foonet.org 376 dummy :End of /MOTD command."))
+
+((mode-user 10.2 "MODE dummy +i")
+ (0 ":dummy!~u@gq7yjr7gsu7nn.irc MODE dummy :+RZi")
+ (0 ":irc.znc.in 306 dummy :You have been marked as being away")
+ (0 ":dummy!~u@gq7yjr7gsu7nn.irc JOIN #foo")
+
+ (0 ":irc.foonet.org 353 dummy = #foo :alice @bob Lal dummy")
+ (0 ":irc.foonet.org 366 dummy #foo :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Buffer Playback...")
+ (0 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :[10:00:02] bob: All that he is 
hath reference to your highness.")
+ (0 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :[10:00:06] alice: Excellent 
workman! Thou canst not paint a man so bad as is thyself.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Playback Complete.")
+ (0 ":irc.foonet.org NOTICE dummy :[09:56:57] This server is in debug mode and 
is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 dummy :You are no longer marked as being away"))
+
+((mode 10 "MODE #foo")
+ (0 ":irc.foonet.org 324 dummy #foo +nt")
+ (0 ":irc.foonet.org 329 dummy #foo 1622454985")
+ (0.1 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :bob: Farewell, pretty lady: 
you must hold the credit of your father.")
+ (0.1 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :alice: On Thursday, sir ? the 
time is very short."))
diff --git a/test/lisp/erc/resources/base/renick/self/manual.eld 
b/test/lisp/erc/resources/base/renick/self/manual.eld
new file mode 100644
index 0000000000..dd107b806d
--- /dev/null
+++ b/test/lisp/erc/resources/base/renick/self/manual.eld
@@ -0,0 +1,50 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the FooNet Internet Relay Chat 
Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is 
irc.foonet.org[188.240.145.101/6697], running version solanum-1.0-dev")
+ (0 ":irc.foonet.org 003 tester :This server was created Sat May 22 2021 at 
19:04:17 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org solanum-1.0-dev 
DGQRSZaghilopsuwz CFILMPQSbcefgijklmnopqrstuvz bkloveqjfI")
+ (0 ":irc.foonet.org 005 tester WHOX FNC KNOCK SAFELIST ELIST=CTU CALLERID=g 
MONITOR=100 ETRACE CHANTYPES=# EXCEPTS INVEX 
CHANMODES=eIbq,k,flj,CFLMPQScgimnprstuz :are supported by this server")
+ (0 ":irc.foonet.org 005 tester CHANLIMIT=#:250 PREFIX=(ov)@+ MAXLIST=bqeI:100 
MODES=4 NETWORK=foonet STATUSMSG=@+ CASEMAPPING=rfc1459 NICKLEN=16 
MAXNICKLEN=16 CHANNELLEN=50 TOPICLEN=390 DEAF=D :are supported by this server")
+ (0 ":irc.foonet.org 005 tester 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:4,NOTICE:4,ACCEPT:,MONITOR: 
EXTBAN=$,ajrxz CLIENTVER=3.0 :are supported by this server")
+ (0 ":irc.foonet.org 251 tester :There are 33 users and 14113 invisible on 17 
servers")
+ (0 ":irc.foonet.org 252 tester 34 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 12815 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 726 clients and 1 servers")
+ (0 ":irc.foonet.org 265 tester 726 739 :Current local users 726, max 739")
+ (0 ":irc.foonet.org 266 tester 14146 14541 :Current global users 14146, max 
14541")
+ (0 ":irc.foonet.org 250 tester :Highest connection count: 740 (739 clients) 
(3790 connections received)")
+ (0 ":irc.foonet.org 375 tester :- irc.foonet.org Message of the Day - ")
+ (0 ":irc.foonet.org 372 tester :- This server provided by NORDUnet/SUNET")
+ (0 ":irc.foonet.org 372 tester :- Welcome to foonet, the IRC network for free 
& open-source software")
+ (0 ":irc.foonet.org 372 tester :- and peer directed projects.")
+ (0 ":irc.foonet.org 372 tester :-  ")
+ (0 ":irc.foonet.org 372 tester :- Please visit us in #libera for questions 
and support.")
+ (0 ":irc.foonet.org 376 tester :End of /MOTD command."))
+
+((mode-user 1.2 "MODE tester +i")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc MODE tester :+RZi")
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc JOIN #foo")
+
+ (0 ":irc.foonet.org 353 tester = #foo :alice @bob Lal tester")
+ (0 ":irc.foonet.org 366 tester #foo :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Buffer Playback...")
+ (0 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :[10:00:02] bob: All that he is 
hath reference to your highness.")
+ (0 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :[10:00:06] alice: Excellent 
workman! Thou canst not paint a man so bad as is thyself.")
+ (0 ":***!znc@znc.in PRIVMSG #foo :Playback Complete.")
+ (0 ":irc.foonet.org NOTICE tester :[09:56:57] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((mode 1 "MODE #foo")
+ (0 ":irc.foonet.org 324 tester #foo +nt")
+ (0 ":irc.foonet.org 329 tester #foo 1622454985")
+ (0.1 ":alice!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :bob: Farewell, pretty lady: 
you must hold the credit of your father.")
+ (0.1 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :alice: On Thursday, sir ? the 
time is very short."))
+
+((nick 2 "NICK dummy")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc NICK :dummy")
+ (0.1 ":dummy!~u@gq7yjr7gsu7nn.irc MODE dummy :+RZi")
+ (0.1 ":bob!~u@gq7yjr7gsu7nn.irc PRIVMSG #foo :dummy: Hi."))
diff --git a/test/lisp/erc/resources/base/renick/self/qual-chester.eld 
b/test/lisp/erc/resources/base/renick/self/qual-chester.eld
new file mode 100644
index 0000000000..75b50fe68b
--- /dev/null
+++ b/test/lisp/erc/resources/base/renick/self/qual-chester.eld
@@ -0,0 +1,40 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK chester"))
+((user 1 "USER user 0 * :chester")
+ (0 ":irc.foonet.org 001 chester :Welcome to the foonet IRC Network chester")
+ (0 ":irc.foonet.org 002 chester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 chester :This server was created Sun, 13 Jun 2021 
05:45:20 UTC")
+ (0 ":irc.foonet.org 004 chester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 chester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 chester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 chester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 chester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 chester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 chester 1 :unregistered connections")
+ (0 ":irc.foonet.org 254 chester 1 :channels formed")
+ (0 ":irc.foonet.org 255 chester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 chester 3 4 :Current local users 3, max 4")
+ (0 ":irc.foonet.org 266 chester 3 4 :Current global users 3, max 4")
+ (0 ":irc.foonet.org 422 chester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE chester +i")
+ (0 ":irc.foonet.org 221 chester +i")
+ (0 ":irc.foonet.org NOTICE chester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 14 "JOIN #chan")
+ (0 ":chester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 chester = #chan :tester chester @alice bob")
+ (0 ":irc.foonet.org 366 chester #chan :End of NAMES list"))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 chester #chan +nt")
+ (0.0 ":irc.foonet.org 329 chester #chan 1623563121")
+ (0.0 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc NICK :dummy")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: That ever eye with 
sight made heart lament.")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: The bitter past, more 
welcome is the sweet.")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Dispatch, I say, and 
find the forester."))
+
+((linger 10 LINGER))
diff --git a/test/lisp/erc/resources/base/renick/self/qual-tester.eld 
b/test/lisp/erc/resources/base/renick/self/qual-tester.eld
new file mode 100644
index 0000000000..2519922665
--- /dev/null
+++ b/test/lisp/erc/resources/base/renick/self/qual-tester.eld
@@ -0,0 +1,46 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Sun, 13 Jun 2021 
05:45:20 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 15 "JOIN #chan")
+ (0 ":tester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :tester @alice bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode 10 "MODE #chan")
+ (0.0 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1623563121")
+ (0.0 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome!")
+ (0.0 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Marry, that, I think, 
be young Petruchio.")
+ (0.4 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: You speak of him when 
he was less furnished than now he is with that which makes him both without and 
within.")
+ (0.2 ":chester!~u@yuvqisyu7m7qs.irc JOIN #chan")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :chester, welcome!"))
+
+((nick 5 "NICK dummy")
+ (0 ":tester!~u@gq7yjr7gsu7nn.irc NICK :dummy")
+ (0.1 ":dummy!~u@gq7yjr7gsu7nn.irc MODE dummy :+RZi")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: That ever eye with 
sight made heart lament.")
+ (0.1 ":alice!~u@wyb9b355rgzi8.irc PRIVMSG #chan :bob: The bitter past, more 
welcome is the sweet.")
+ (0.1 ":bob!~u@wyb9b355rgzi8.irc PRIVMSG #chan :alice: Dispatch, I say, and 
find the forester."))
diff --git a/test/lisp/erc/resources/base/reuse-buffers/server/barnet.eld 
b/test/lisp/erc/resources/base/reuse-buffers/server/barnet.eld
new file mode 100644
index 0000000000..cc7aff1007
--- /dev/null
+++ b/test/lisp/erc/resources/base/reuse-buffers/server/barnet.eld
@@ -0,0 +1,24 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :barnet:changeme"))
+((nick 1 "NICK tester"))
+((user 2 "USER user 0 * :tester")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Sun, 25 Apr 2021 
11:28:28 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":irc.barnet.org NOTICE tester :[11:29:00] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
diff --git a/test/lisp/erc/resources/base/reuse-buffers/server/foonet.eld 
b/test/lisp/erc/resources/base/reuse-buffers/server/foonet.eld
new file mode 100644
index 0000000000..3a84610846
--- /dev/null
+++ b/test/lisp/erc/resources/base/reuse-buffers/server/foonet.eld
@@ -0,0 +1,24 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Sun, 25 Apr 2021 
11:28:28 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10.2 "MODE tester +i")
+ ;; No mode answer
+ (0 ":irc.znc.in 306 tester :You have been marked as being away")
+ (0 ":irc.foonet.org NOTICE tester :[11:29:00] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
diff --git a/test/lisp/erc/resources/base/upstream-reconnect/soju-barnet.eld 
b/test/lisp/erc/resources/base/upstream-reconnect/soju-barnet.eld
new file mode 100644
index 0000000000..b8fc45e57b
--- /dev/null
+++ b/test/lisp/erc/resources/base/upstream-reconnect/soju-barnet.eld
@@ -0,0 +1,64 @@
+;; -*- mode: lisp-data; -*-
+((pass 6 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER tester@vanilla/barnet 0 * :tester")
+ (0.01 ":soju.im 001 tester :Welcome to soju, tester")
+ (0.01 ":soju.im 002 tester :Your host is soju.im")
+ (0.00 ":soju.im 004 tester soju.im soju aiwroO OovaimnqpsrtklbeI")
+ (0.53 ":soju.im 005 tester CHATHISTORY=1000 CASEMAPPING=ascii BOUNCER_NETID=2 
AWAYLEN=390 CHANLIMIT=#:100 INVEX NETWORK=barnet NICKLEN=32 WHOX MODES BOT=B 
ELIST=U MAXLIST=beI:60 :are supported")
+ (0.01 ":soju.im 005 tester TOPICLEN=390 CHANMODES=Ibe,k,fl,CEMRUimnstu 
CHANNELLEN=64 EXCEPTS EXTBAN=,m KICKLEN=390 
TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 MAXTARGETS=4 MONITOR=100 CHANTYPES=# PREFIX=(qaohv)~&@%+ UTF8ONLY :are 
supported")
+ (0.22 ":soju.im 221 tester +Zi")
+ (0.00 ":soju.im 422 tester :Use /motd to read the message of the day"))
+
+((mode 5 "MODE tester +i")
+ (0.00 ":tester!tester@10.0.2.100 JOIN #chan")
+ (0.06 ":soju.im 353 tester = #chan :tester @mike joe")
+ (0.01 ":soju.im 366 tester #chan :End of /NAMES list")
+ (0.23 ":irc.barnet.org 221 tester +Zi"))
+
+((mode 5 "MODE #chan")
+ (0.00 ":soju.im 324 tester #chan +tn")
+ (0.01 ":soju.im 329 tester #chan 1652878846")
+ (0.01 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: There is five in the 
first show.")
+ (0.00 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Sir, I was an inward of 
his. A shy fellow was the duke; and, I believe I know the cause of his 
withdrawing.")
+ (0.00 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Proud of employment, 
willingly I go.")
+ (0.09 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Dull not device by 
coldness and delay.")
+ (0.09 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Our states are forfeit: 
seek not to undo us.")
+ (0.06 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Come, you are too 
severe a moraler. As the time, the place, and the condition of this country 
stands, I could heartily wish this had not befallen, but since it is as it is, 
mend it for your own good.")
+ (0.06 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Who hath upon him still 
that natural stamp.")
+ (0.07 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Arraign her first; 'tis 
Goneril. I here take my oath before this honourable assembly, she kicked the 
poor king her father.")
+ (0.06 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Lady, I will commend 
you to mine own heart.")
+ (0.08 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Look, what I will not, 
that I cannot do.")
+ (0.08 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: That he would wed me, 
or else die my lover.")
+ (0.08 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Come your way, sir. 
Bless you, good father friar.")
+ (0.08 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Under correction, sir, 
we know whereuntil it doth amount.")
+ (0.08 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: For I am nothing if not 
critical.")
+ (0.06 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Once more I'll read the 
ode that I have writ.")
+ (0.06 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: This is the foul fiend 
Flibbertigibbet: he begins at curfew, and walks till the first cock; he gives 
the web and the pin, squints the eye, and makes the harelip; mildews the white 
wheat, and hurts the poor creature of earth.")
+ (0.06 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Sir, I praise the Lord 
for you, and so may my parishioners; for their sons are well tutored by you, 
and their daughters profit very greatly under you: you are a good member of the 
commonwealth.")
+ (0.08 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: If it please your 
honour, I know not well what they are; but precise villains they are, that I am 
sure of, and void of all profanation in the world that good Christians ought to 
have.")
+ ;; Unexpected disconnect
+ (0.03 ":BouncerServ!BouncerServ@BouncerServ NOTICE tester :disconnected from 
barnet: failed to handle messages: failed to read IRC command: read tcp 
[::1]:54990->[::1]:6668: read: software caused connection abort")
+ ;; Eventual reconnect
+ (0.79 ":BouncerServ!BouncerServ@BouncerServ NOTICE tester :connected to 
barnet")
+ ;; No MOTD or other numerics
+ (0.01 ":soju.im 005 tester AWAYLEN=390 BOT=B CHANLIMIT=#:100 
CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# ELIST=U EXCEPTS 
EXTBAN=,m INVEX KICKLEN=390 :are supported")
+ (0.01 ":soju.im 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8ONLY WHOX :are supported")
+ (0.22 ":irc.barnet.org 221 tester +Zi")
+ (0.01 ":irc.barnet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect.")
+ ;; Server-initialed join
+ (0.01 ":tester!tester@10.0.2.100 JOIN #chan"))
+
+((mode 5 "MODE #chan")
+ (0.22 ":soju.im 353 tester = #chan :@mike joe tester")
+ (0.00 ":soju.im 366 tester #chan :End of /NAMES list")
+ (0.00 ":soju.im 324 tester #chan +nt")
+ (0.00 ":soju.im 329 tester #chan 1652878846")
+ (0.00 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :tester, welcome!")
+ (0.00 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :tester, welcome!")
+ (0.06 ":soju.im 324 tester #chan +nt")
+ (0.00 ":soju.im 329 tester #chan 1652878846")
+ (0.62 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: Thou art my brother; so 
we'll hold thee ever.")
+ (0.00 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Very well! go to! I 
cannot go to, man; nor 'tis not very well: by this hand, I say, it is very 
scurvy, and begin to find myself fobbed in it.")
+ (0.00 ":joe!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :mike: The heir of Alen on, 
Katharine her name.")
+ (0.09 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Go to; farewell! put 
money enough in your purse."))
diff --git a/test/lisp/erc/resources/base/upstream-reconnect/soju-foonet.eld 
b/test/lisp/erc/resources/base/upstream-reconnect/soju-foonet.eld
new file mode 100644
index 0000000000..63dfcb184c
--- /dev/null
+++ b/test/lisp/erc/resources/base/upstream-reconnect/soju-foonet.eld
@@ -0,0 +1,72 @@
+;; -*- mode: lisp-data; -*-
+((pass 5 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER tester@vanilla/foonet 0 * :tester")
+ (0.01 ":soju.im 001 tester :Welcome to soju, tester")
+ (0.02 ":soju.im 002 tester :Your host is soju.im")
+ (0.01 ":soju.im 004 tester soju.im soju aiwroO OovaimnqpsrtklbeI")
+ (0.00 ":soju.im 005 tester CHATHISTORY=1000 CASEMAPPING=ascii BOUNCER_NETID=1 
CHANTYPES=# PREFIX=(qaohv)~&@%+ UTF8ONLY AWAYLEN=390 NICKLEN=32 WHOX 
CHANLIMIT=#:100 INVEX NETWORK=foonet MODES :are supported")
+ (0.00 ":soju.im 005 tester TOPICLEN=390 BOT=B ELIST=U MAXLIST=beI:60 
CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 
TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 EXCEPTS EXTBAN=,m KICKLEN=390 MAXTARGETS=4 MONITOR=100 :are supported")
+ (0.00 ":soju.im 221 tester +Zi")
+ (0.00 ":soju.im 422 tester :Use /motd to read the message of the day"))
+
+((mode 5 "MODE tester +i")
+ (0.2 ":irc.foonet.org 221 tester +Zi")
+ (0.0 ":tester!tester@10.0.2.100 JOIN #chan")
+ (0.0 ":soju.im 353 tester = #chan :tester @alice bob")
+ (0.1 ":soju.im 366 tester #chan :End of /NAMES list")
+ (0.0 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: Princely shall be thy 
usage every way.")
+ (0.1 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: Tell me thy reason why 
thou wilt marry."))
+
+((mode 5 "MODE #chan")
+ (0.00 ":soju.im 324 tester #chan +nt")
+ (0.01 ":soju.im 329 tester #chan 1652878847")
+ (0.02 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: There is no leprosy 
but what thou speak'st.")
+ (0.09 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: For I upon this bank 
will rest my head.")
+ (0.01 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: To ruffle in the 
commonwealth of Rome.")
+ (0.08 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: For I can nowhere find 
him like a man.")
+ (0.09 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: Ay, sir; but she will 
none, she gives you thanks.")
+ (0.05 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: That man should be at 
woman's command, and yet no hurt done! Though honesty be no puritan, yet it 
will do no hurt; it will wear the surplice of humility over the black gown of a 
big heart. I am going, forsooth: the business is for Helen to come hither.")
+ (0.07 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: Indeed, I should have 
asked you that before.")
+ (0.09 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: Faith, we met, and 
found the quarrel was upon the seventh cause.")
+ (0.05 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: And then, I hope, thou 
wilt be satisfied.")
+ (0.06 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: Well, I will forget 
the condition of my estate, to rejoice in yours.")
+ (0.05 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: Ah! sirrah, this 
unlook'd-for sport comes well.")
+ (0.01 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: Mayst thou inherit 
too! Welcome to Paris.")
+ (0.04 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: That I would choose, 
were I to choose anew.")
+ (0.08 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: Good Tom Drum, lend me 
a handkercher: so, I thank thee. Wait on me home, I'll make sport with thee: 
let thy curtsies alone, they are scurvy ones.")
+ (0.06 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: Excellent workman! 
Thou canst not paint a man so bad as is thyself.")
+ (0.07 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: That every braggart 
shall be found an ass.")
+ (0.07 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: This is but a custom 
in your tongue; you bear a graver purpose, I hope.")
+ (0.02 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: Well, we will have 
such a prologue, and it shall be written in eight and six.")
+ (0.01 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: Tell me thy reason why 
thou wilt marry.")
+ (0.06 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: According to the 
measure of their states.")
+
+ ;; Unexpected disconnect
+ (0.07 ":BouncerServ!BouncerServ@BouncerServ NOTICE tester :disconnected from 
foonet: failed to handle messages: failed to read IRC command: read tcp 
[::1]:57224->[::1]:6667: read: software caused connection abort")
+ ;; Eventual reconnect
+ (1.02 ":BouncerServ!BouncerServ@BouncerServ NOTICE tester :connected to 
foonet")
+ ;; No MOTD or other numerics
+ (0.01 ":soju.im 005 tester AWAYLEN=390 BOT=B CHANLIMIT=#:100 
CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# ELIST=U EXCEPTS 
EXTBAN=,m INVEX KICKLEN=390 :are supported")
+ (0.02 ":soju.im 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8ONLY WHOX :are supported")
+ (0.02 ":irc.foonet.org 221 tester +Zi")
+ (0.23 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect.")
+ ;; Server-initialed join
+ (0.02 ":tester!tester@10.0.2.100 JOIN #chan"))
+
+((mode 5 "MODE #chan")
+ (0.03 ":soju.im 353 tester = #chan :@alice bob tester")
+ (0.03 ":soju.im 366 tester #chan :End of /NAMES list")
+ (0.00 ":soju.im 324 tester #chan +nt")
+ (0.00 ":soju.im 329 tester #chan 1652878847")
+ (0.00 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :tester, welcome!")
+ (0.00 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :tester, welcome!")
+ (0.46 ":soju.im 324 tester #chan +nt")
+ (0.01 ":soju.im 329 tester #chan 1652878847")
+ (0.00 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: Thou desirest me to 
stop in my tale against the hair.")
+ (0.07 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: But my intents are 
fix'd and will not leave me.")
+ (0.09 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: That last is true; the 
sweeter rest was mine.")
+ (0.09 ":alice!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :bob: No matter whither, so 
you come not here.")
+ (0.09 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: My lord, in heart; and 
let the health go round."))
+
+((linger 12 LINGER))
diff --git a/test/lisp/erc/resources/base/upstream-reconnect/znc-barnet.eld 
b/test/lisp/erc/resources/base/upstream-reconnect/znc-barnet.eld
new file mode 100644
index 0000000000..bf5c2b5a74
--- /dev/null
+++ b/test/lisp/erc/resources/base/upstream-reconnect/znc-barnet.eld
@@ -0,0 +1,93 @@
+;; -*- mode: lisp-data; -*-
+((pass 6 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER tester@vanilla/barnet 0 * :tester")
+ (0.00 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0.01 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running 
version ergo-v2.8.0")
+ (0.01 ":irc.barnet.org 003 tester :This server was created Thu, 19 May 2022 
05:33:02 UTC")
+ (0.00 ":irc.barnet.org 004 tester irc.barnet.org ergo-v2.8.0 BERTZios 
CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.00 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.01 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.01 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by 
this server")
+ (0.00 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.00 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0.11 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0.00 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0.00 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.00 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.00 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode 5 "MODE tester +i")
+ (0.0 ":tester!~u@fsr9fwzfeeybc.irc JOIN #chan")
+ (0.05 ":irc.barnet.org 353 tester = #chan :@joe mike tester")
+ (0.01 ":irc.barnet.org 366 tester #chan :End of /NAMES list.")
+ (0.0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0.0 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:13] mike: But send the 
midwife presently to me.")
+ (0.01 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:18] joe: Alas! poor 
rogue, I think, i' faith, she loves me.")
+ (0.01 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:20] mike: They did not 
bless us with one happy word.")
+ (0.01 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:24] joe: And hear the 
sentence of your moved prince.")
+ (0.21 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:29] mike: Swear me to 
this, and I will ne'er say no.")
+ (0.01 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:32] joe: As they had 
seen me with these hangman's hands.")
+ (0.01 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:34] mike: Boyet, 
prepare: I will away to-night.")
+ (0.01 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :[05:48:36] joe: For being a 
little bad: so may my husband.")
+ (0.04 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0.0 ":irc.barnet.org 221 tester +Zi")
+ (2.55 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: And whirl along with 
thee about the globe."))
+
+((mode 5 "MODE #chan")
+ (0.00 ":irc.barnet.org 324 tester #chan +nt")
+ (0.00 ":irc.barnet.org 329 tester #chan 1652938384")
+ (0.06 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Unless good-counsel may 
the cause remove.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: Thyself domestic 
officers thine enemy.")
+ (0.01 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Go after her: she's 
desperate; govern her.")
+ (0.30 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: Or else to heaven she 
heaves them for revenge.")
+ (0.01 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Keep up your bright 
swords, for the dew will rust them.")
+ (0.04 ":*status!znc@znc.in PRIVMSG tester :Disconnected from IRC (Connection 
aborted). Reconnecting...")
+ (0.41 ":*status!znc@znc.in PRIVMSG tester :Disconnected from IRC. 
Reconnecting...")
+ (0.59 ":*status!znc@znc.in PRIVMSG tester :Connected!")
+ (0.02 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0.01 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running 
version ergo-v2.8.0")
+ (0.01 ":irc.barnet.org 003 tester :This server was created Thu, 19 May 2022 
05:33:02 UTC")
+ (0.01 ":irc.barnet.org 004 tester irc.barnet.org ergo-v2.8.0 BERTZios 
CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.01 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.01 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.22 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by 
this server")
+ (0.00 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.01 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0.00 ":irc.barnet.org 253 tester 0 :unregistered connections")
+ (0.00 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0.00 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0.00 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.17 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.00 ":irc.barnet.org 422 tester :MOTD File is missing")
+ (0.01 ":irc.barnet.org 221 tester +Zi")
+ (0.00 ":irc.barnet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect.")
+ (0.05 ":irc.barnet.org 352 tester * ~u fsr9fwzfeeybc.irc irc.barnet.org 
tester H :0 ZNC - https://znc.in";)
+ (0.02 ":irc.barnet.org 315 tester tester!*@* :End of WHO list")
+ (0.08 ":tester!~u@fsr9fwzfeeybc.irc JOIN #chan"))
+
+((mode 5 "MODE #chan")
+ (0.05 ":irc.barnet.org 353 tester = #chan :mike tester @joe")
+ (0.01 ":irc.barnet.org 366 tester #chan :End of NAMES list")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :tester, welcome!")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :tester, welcome!")
+ (0.02 ":irc.barnet.org 324 tester #chan +nt")
+ (0.01 ":irc.barnet.org 329 tester #chan 1652938384")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: See, here he comes, and 
I must ply my theme.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Confine yourself but in 
a patient list.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: And bide the penance of 
each three years' day.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Bid me farewell, and 
let me hear thee going.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: Nor shall not, if I do 
as I intend.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Our corn's to reap, for 
yet our tithe's to sow.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: And almost broke my 
heart with extreme laughter.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Of modern seeming do 
prefer against him.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: Like humble-visag'd 
suitors, his high will.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: But yet, poor Claudio! 
There's no remedy.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: Let him make treble 
satisfaction.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: He's that he is; I may 
not breathe my censure.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: To check their folly, 
passion's solemn tears.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: Villain, I have done 
thy mother.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: Please you, therefore, 
draw nigh, and take your places.")
+ (0.00 ":mike!~u@6t6jcije78we2.irc PRIVMSG #chan :joe: You shall not be 
admitted to his sight.")
+ (0.00 ":joe!~u@6t6jcije78we2.irc PRIVMSG #chan :mike: Sir, you shall present 
before her the Nine Worthies. Sir Nathaniel, as concerning some entertainment 
of time, some show in the posterior of this day, to be rendered by our 
assistance, at the king's command, and this most gallant, illustrate, and 
learned gentleman, before the princess; I say, none so fit as to present the 
Nine Worthies.")
+ (0.00 ":mike!~u@6d9pasqcqwb2s.irc PRIVMSG #chan :joe: Go to; farewell! put 
money enough in your purse."))
diff --git a/test/lisp/erc/resources/base/upstream-reconnect/znc-foonet.eld 
b/test/lisp/erc/resources/base/upstream-reconnect/znc-foonet.eld
new file mode 100644
index 0000000000..39c2950aa0
--- /dev/null
+++ b/test/lisp/erc/resources/base/upstream-reconnect/znc-foonet.eld
@@ -0,0 +1,86 @@
+;; -*- mode: lisp-data; -*-
+((pass 6 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER tester@vanilla/foonet 0 * :tester")
+ (0.16 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.00 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running 
version ergo-v2.8.0")
+ (0.00 ":irc.foonet.org 003 tester :This server was created Thu, 19 May 2022 
05:33:02 UTC")
+ (0.00 ":irc.foonet.org 004 tester irc.foonet.org ergo-v2.8.0 BERTZios 
CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.00 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.01 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.01 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by 
this server")
+ (0.00 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.00 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0.00 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0.00 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0.00 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.00 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.00 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode 6 "MODE tester +i")
+ (0.00 ":tester!~u@rmtvrz9zcwbdq.irc JOIN #chan")
+ (0.09 ":irc.foonet.org 353 tester = #chan :@alice bob tester")
+ (0.00 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0.00 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0.00 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:11] alice: And be 
aveng'd on cursed Tamora.")
+ (0.00 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:13] bob: The 
stronger part of it by her own letters, which make her story true, even to the 
point of her death: her death itself, which could not be her office to say is 
come, was faithfully confirmed by the rector of the place.")
+ (0.01 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:15] alice: The ape is 
dead, and I must conjure him.")
+ (0.00 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:17] bob: Not so; but 
I answer you right painted cloth, from whence you have studied your questions.")
+ (0.01 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:21] alice: The valiant 
Paris seeks you for his love.")
+ (0.00 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:26] bob: To prison 
with her; and away with him.")
+ (0.00 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:30] alice: Tell them 
there I have gold; look, so I have.")
+ (0.00 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :[05:48:35] bob: Will even 
weigh, and both as light as tales.")
+ (0.00 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")
+ (0.00 ":irc.foonet.org 221 tester +Zi")
+ (0.08 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :alice: By some vile forfeit 
of untimely death."))
+
+((mode 3.51 "MODE #chan")
+ (0.1 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1652938384")
+ (0.0 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :bob: What does this knave 
here ? Get you gone, sirrah: the complaints I have heard of you I do not all 
believe: 'tis my slowness that I do not; for I know you lack not folly to 
commit them, and have ability enough to make such knaveries yours.")
+ (0.0 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :alice: When sects and factions 
were newly born.")
+ (0.1 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :bob: Fall, when Love please! 
marry, to each, but one.")
+ (0.1 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :alice: For I ne'er saw true 
beauty till this night.")
+ (0.1 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :bob: Or say, sweet love, 
what thou desir'st to eat.")
+ (0.1 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :alice: Yes, and will nobly him 
remunerate.")
+ (0.1 ":*status!znc@znc.in PRIVMSG tester :Disconnected from IRC (Connection 
aborted). Reconnecting...")
+ (0.4 ":*status!znc@znc.in PRIVMSG tester :Disconnected from IRC. 
Reconnecting...")
+ (0.9 ":*status!znc@znc.in PRIVMSG tester :Connected!")
+ (0.0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running 
version ergo-v2.8.0")
+ (0.0 ":irc.foonet.org 003 tester :This server was created Thu, 19 May 2022 
05:33:02 UTC")
+ (0.0 ":irc.foonet.org 004 tester irc.foonet.org ergo-v2.8.0 BERTZios 
CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.1 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES 
MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0.0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0.0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0.0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0.1 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0.0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0.0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0.0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0.0 ":irc.foonet.org 422 tester :MOTD File is missing")
+ (0.0 ":irc.foonet.org 221 tester +Zi")
+ (0.0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect.")
+ (0.6 ":irc.foonet.org 352 tester * ~u rmtvrz9zcwbdq.irc irc.foonet.org tester 
H :0 ZNC - https://znc.in";)
+ (0.0 ":irc.foonet.org 315 tester tester!*@* :End of WHO list")
+ (0.0 ":tester!~u@rmtvrz9zcwbdq.irc JOIN #chan"))
+
+((mode 6 "MODE #chan")
+ (0.0 ":irc.foonet.org 353 tester = #chan :@alice bob tester")
+ (0.0 ":irc.foonet.org 366 tester #chan :End of NAMES list")
+ (0.0 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :tester, welcome!")
+ (0.0 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :tester, welcome!")
+ (0.0 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :bob: Being of no power to 
make his wishes good.")
+ (0.0 ":irc.foonet.org 324 tester #chan +nt")
+ (0.0 ":irc.foonet.org 329 tester #chan 1652938384")
+ (0.0 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :alice: In everything I wait 
upon his will.")
+ (0.0 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :bob: Make choice of which 
your highness will see first.")
+ (0.0 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :alice: We waste our lights in 
vain, like lamps by day.")
+ (0.0 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :bob: No, I know that; but it 
is fit I should commit offence to my inferiors.")
+ (0.1 ":bob!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :alice: By my head, here come 
the Capulets.")
+ (0.0 ":alice!~u@rmtvrz9zcwbdq.irc PRIVMSG #chan :bob: Well, I will forget the 
condition of my estate, to rejoice in yours.")
+ (0.0 ":bob!~u@h35cf3bf7rbt4.irc PRIVMSG #chan :alice: My lord, in heart; and 
let the health go round."))
+
+((linger 12 LINGER))
diff --git a/test/lisp/erc/resources/erc-scenarios-common.el 
b/test/lisp/erc/resources/erc-scenarios-common.el
new file mode 100644
index 0000000000..6b380772fe
--- /dev/null
+++ b/test/lisp/erc/resources/erc-scenarios-common.el
@@ -0,0 +1,407 @@
+;;; erc-scenarios-common.el --- Common helpers for ERC scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; These are e2e-ish test cases primarily intended to assert core,
+;; fundamental behavior expected of any modern IRC client.  Tests may
+;; also simulate specific scenarios drawn from bug reports.  Incoming
+;; messages are provided by playback scripts resembling I/O logs.  In
+;; place of time stamps, they have time deltas, which are used to
+;; govern the test server in a fashion reminiscent of music rolls (or
+;; the script(1) UNIX program).  These scripts can be found in the
+;; other directories under test/lisp/erc/resources.
+;;
+;; Isolation:
+;;
+;; The set of enabled modules is shared among all tests.  The function
+;; `erc-update-modules' activates them (as minor modes), but it never
+;; deactivates them.  So there's no going back, and let-binding
+;; `erc-modules' is useless.  The safest route is therefore to (1)
+;; assume the set of default modules is already activated or will be
+;; over the course of the test session and (2) let-bind relevant user
+;; options as needed.  For example, to limit the damage of
+;; `erc-autojoin-channels-alist' to a given test, assume the
+;; `erc-join' library has already been loaded or will be on the next
+;; call to `erc-open'.  And then just let-bind
+;; `erc-autojoin-channels-alist' for the duration of the test.
+;;
+;; Playing nice:
+;;
+;; Right now, these tests all rely on an ugly fixture macro named
+;; `erc-scenarios-common-with-cleanup', which is defined just below.
+;; It helps restore (but not really prepare) the environment by
+;; destroying any stray processes or buffers named in the first
+;; argument, a `let*'-style VAR-LIST.  Relying on such a macro is
+;; unfortunate because in many ways it actually hampers readability by
+;; favoring magic over verbosity.  But without it (or something
+;; similar), any failing test would cause all subsequent tests in this
+;; file to fail like dominoes (making all but the first backtrace
+;; useless).
+;;
+;; Misc:
+;;
+;; Note that in the following examples, nicknames Alice and Bob are
+;; always associated with the fake network FooNet, while nicks Joe and
+;; Mike are always on BarNet.  (Networks are sometimes downcased.)
+;;
+;; XXX This file should *not* contain any test cases.
+
+;;; Code:
+
+(require 'ert-x) ; cl-lib
+(eval-and-compile
+  (let* ((d (expand-file-name ".." (ert-resource-directory)))
+         (load-path (cons (concat d "/erc-d") load-path)))
+    (require 'erc-d-t)
+    (require 'erc-d)))
+
+(require 'erc-backend)
+
+(eval-when-compile (require 'erc-join)
+                   (require 'erc-services))
+
+(declare-function erc-network "erc-networks")
+(defvar erc-network)
+
+(defvar erc-scenarios-common--resources-dir
+  (expand-file-name "../" (ert-resource-directory)))
+
+;; Teardown is already inhibited when running interactively, which
+;; prevents subsequent tests from succeeding, so we might as well
+;; treat inspection as the goal.
+(unless noninteractive
+  (setq erc-server-auto-reconnect nil))
+
+(defvar erc-scenarios-common-dialog nil)
+(defvar erc-scenarios-common-extra-teardown nil)
+
+(defun erc-scenarios-common--add-silence ()
+  (advice-add #'erc-login :around #'erc-d-t-silence-around)
+  (advice-add #'erc-handle-login :around #'erc-d-t-silence-around)
+  (advice-add #'erc-server-connect :around #'erc-d-t-silence-around))
+
+(defun erc-scenarios-common--remove-silence ()
+  (advice-remove #'erc-login #'erc-d-t-silence-around)
+  (advice-remove #'erc-handle-login #'erc-d-t-silence-around)
+  (advice-remove #'erc-server-connect #'erc-d-t-silence-around))
+
+(defun erc-scenarios-common--print-trace ()
+  (when (and (boundp 'trace-buffer) (get-buffer trace-buffer))
+    (with-current-buffer trace-buffer
+      (message "%S" (buffer-string))
+      (kill-buffer))))
+
+(eval-and-compile
+  (defun erc-scenarios-common--make-bindings (bindings)
+    `((erc-d-u-canned-dialog-dir (expand-file-name
+                                  (or erc-scenarios-common-dialog
+                                      (cadr (assq 'erc-scenarios-common-dialog
+                                                  ',bindings)))
+                                  erc-scenarios-common--resources-dir))
+      (erc-d-tmpl-vars `(,@erc-d-tmpl-vars
+                         (quit . ,(erc-quit/part-reason-default))
+                         (erc-version . ,erc-version)))
+      (erc-modules (copy-sequence erc-modules))
+      (inhibit-interaction t)
+      (auth-source-do-cache nil)
+      (erc-autojoin-channels-alist nil)
+      (erc-server-auto-reconnect nil)
+      (erc-d-linger-secs 10)
+      ,@bindings)))
+
+(defmacro erc-scenarios-common-with-cleanup (bindings &rest body)
+  "Provide boilerplate cleanup tasks after calling BODY with BINDINGS.
+
+If an `erc-d' process exists, wait for it to start before running BODY.
+If `erc-autojoin-mode' mode is bound, restore it during cleanup if
+disabled by BODY.  Other defaults common to these test cases are added
+below and can be overridden, except when wanting the \"real\" default
+value, which must be looked up or captured outside of the calling form.
+
+Dialog resource directories are located by expanding the variable
+`erc-scenarios-common-dialog' or its value in BINDINGS."
+  (declare (indent 1))
+
+  (let* ((orig-autojoin-mode (make-symbol "orig-autojoin-mode"))
+         (combind `((,orig-autojoin-mode (bound-and-true-p erc-autojoin-mode))
+                    ,@(erc-scenarios-common--make-bindings bindings))))
+
+    `(erc-d-t-with-cleanup (,@combind)
+
+         (ert-info ("Restore autojoin, etc., kill ERC buffers")
+           (dolist (buf (buffer-list))
+             (when-let ((erc-d-u--process-buffer)
+                        (proc (get-buffer-process buf)))
+               (delete-process proc)))
+
+           (erc-scenarios-common--remove-silence)
+
+           (when erc-scenarios-common-extra-teardown
+             (ert-info ("Running extra teardown")
+               (funcall erc-scenarios-common-extra-teardown)))
+
+           (when (and (boundp 'erc-autojoin-mode)
+                      (not (eq erc-autojoin-mode ,orig-autojoin-mode)))
+             (erc-autojoin-mode (if ,orig-autojoin-mode +1 -1)))
+
+           (when noninteractive
+             (erc-scenarios-common--print-trace)
+             (erc-d-t-kill-related-buffers)
+             (delete-other-windows)))
+
+       (erc-scenarios-common--add-silence)
+
+       (ert-info ("Wait for dumb server")
+         (dolist (buf (buffer-list))
+           (with-current-buffer buf
+             (when erc-d-u--process-buffer
+               (erc-d-t-search-for 3 "Starting")))))
+
+       (ert-info ("Activate erc-debug-irc-protocol")
+         (unless (and noninteractive (not erc-debug-irc-protocol))
+           (erc-toggle-debug-irc-protocol)))
+
+       ,@body)))
+
+(defun erc-scenarios-common-assert-initial-buf-name (id port)
+  ;; Assert no limbo period when explicit ID given
+  (should (string= (if id
+                       (symbol-name id)
+                     (format "127.0.0.1:%d" port))
+                   (buffer-name))))
+
+(defun erc-scenarios-common-buflist (prefix)
+  "Return list of buffers with names sharing PREFIX."
+  (let (case-fold-search)
+    (erc-networks--id-sort-buffers
+     (delq nil
+           (mapcar (lambda (b)
+                     (when (string-prefix-p prefix (buffer-name b)) b))
+                   (buffer-list))))))
+
+;; This is more realistic than `erc-send-message' because it runs
+;; `erc-pre-send-functions', etc.  Keyboard macros may be preferable,
+;; but they sometimes experience complications when an earlier test
+;; has failed.
+(defun erc-scenarios-common-say (str)
+  (let (erc-accidental-paste-threshold-seconds)
+    (goto-char erc-input-marker)
+    (insert str)
+    (erc-send-current-line)))
+
+
+;;;; Fixtures
+
+(cl-defun erc-scenarios-common--base-network-id-bouncer
+    ((&key autop foo-id bar-id after
+           &aux
+           (foo-id (and foo-id 'oofnet))
+           (bar-id (and bar-id 'rabnet))
+           (serv-buf-foo (if foo-id "oofnet" "foonet"))
+           (serv-buf-bar (if bar-id "rabnet" "barnet"))
+           (chan-buf-foo (if foo-id "#chan@oofnet" "#chan@foonet"))
+           (chan-buf-bar (if bar-id "#chan@rabnet" "#chan@barnet")))
+     &rest dialogs)
+  "Ensure retired option `erc-rename-buffers' is now the default behavior.
+The option `erc-rename-buffers' is now deprecated and on by default, so
+this now just asserts baseline behavior.  Originally from scenario
+clash-of-chans/rename-buffers as explained in Bug#48598: 28.0.50;
+buffer-naming collisions involving bouncers in ERC."
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/netid/bouncer")
+       (erc-d-t-cleanup-sleep-secs 1)
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (apply #'erc-d-run "localhost" t dialogs))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-auto-reconnect autop)
+       erc-server-buffer-foo erc-server-process-foo
+       erc-server-buffer-bar erc-server-process-bar)
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer
+          (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "foonet:changeme"
+                                           :full-name "tester"
+                                           :id foo-id))
+        (setq erc-server-process-foo erc-server-process)
+        (erc-scenarios-common-assert-initial-buf-name foo-id port)
+        (erc-d-t-wait-for 3 (eq (erc-network) 'foonet))
+        (erc-d-t-wait-for 3 (string= (buffer-name) serv-buf-foo))
+        (funcall expect 5 "foonet")))
+
+    (ert-info ("Join #chan@foonet")
+      (with-current-buffer erc-server-buffer-foo (erc-cmd-JOIN "#chan"))
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+        (funcall expect 5 "<alice>")))
+
+    (ert-info ("Connect to barnet")
+      (with-current-buffer
+          (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "barnet:changeme"
+                                           :full-name "tester"
+                                           :id bar-id))
+        (setq erc-server-process-bar erc-server-process)
+        (erc-scenarios-common-assert-initial-buf-name bar-id port)
+        (erc-d-t-wait-for 6 (eq (erc-network) 'barnet))
+        (erc-d-t-wait-for 3 (string= (buffer-name) serv-buf-bar))
+        (funcall expect 5 "barnet")))
+
+    (ert-info ("Server buffers are unique, no names based on IPs")
+      (should-not (eq erc-server-buffer-foo erc-server-buffer-bar))
+      (should-not (erc-scenarios-common-buflist "127.0.0.1")))
+
+    (ert-info ("Join #chan@barnet")
+      (with-current-buffer erc-server-buffer-bar (erc-cmd-JOIN "#chan")))
+
+    (erc-d-t-wait-for 5 "Exactly 2 #chan-prefixed buffers exist"
+      (equal (list (get-buffer chan-buf-bar)
+                   (get-buffer chan-buf-foo))
+             (erc-scenarios-common-buflist "#chan")))
+
+    (ert-info ("#chan@<esid> is exclusive to foonet")
+      (with-current-buffer chan-buf-foo
+        (erc-d-t-search-for 1 "<bob>")
+        (erc-d-t-absent-for 0.1 "<joe>")
+        (should (eq erc-server-process erc-server-process-foo))
+        (erc-d-t-search-for 10 "ape is dead")
+        (erc-d-t-wait-for 5 (not (erc-server-process-alive)))))
+
+    (ert-info ("#chan@<esid> is exclusive to barnet")
+      (with-current-buffer chan-buf-bar
+        (erc-d-t-search-for 1 "<joe>")
+        (erc-d-t-absent-for 0.1 "<bob>")
+        (erc-d-t-wait-for 5 (eq erc-server-process erc-server-process-bar))
+        (erc-d-t-search-for 15 "keeps you from dishonour")
+        (erc-d-t-wait-for 5 (not (erc-server-process-alive)))))
+
+    (when after (funcall after))))
+
+(defun erc-scenarios-common--clash-rename-pass-handler (dialog exchange)
+  (when (eq (erc-d-dialog-name dialog) 'stub-again)
+    (let* ((match (erc-d-exchange-match exchange 1))
+           (sym (if (string= match "foonet") 'foonet-again 'barnet-again)))
+      (should (member match (list "foonet" "barnet")))
+      (erc-d-load-replacement-dialog dialog sym 1))))
+
+(defun erc-scenarios-common--base-network-id-bouncer--reconnect (foo-id bar-id)
+  (let ((erc-d-tmpl-vars '((token . (group (| "barnet" "foonet")))))
+        (erc-d-match-handlers
+         ;; Auto reconnect is nondeterministic, so let computer decide
+         (list :pass #'erc-scenarios-common--clash-rename-pass-handler))
+        (after
+         (lambda ()
+           ;; Simulate disconnection and `erc-server-auto-reconnect'
+           (ert-info ("Reconnect to foonet and barnet back-to-back")
+             (with-current-buffer (if foo-id "oofnet" "foonet")
+               (erc-d-t-wait-for 10 (erc-server-process-alive)))
+             (with-current-buffer (if bar-id "rabnet" "barnet")
+               (erc-d-t-wait-for 10 (erc-server-process-alive))))
+
+           (ert-info ("#chan@foonet is exclusive to foonet")
+             (with-current-buffer (if foo-id "#chan@oofnet" "#chan@foonet")
+               (erc-d-t-search-for 1 "<alice>")
+               (erc-d-t-absent-for 0.1 "<joe>")
+               (erc-d-t-search-for 20 "please your lordship")))
+
+           (ert-info ("#chan@barnet is exclusive to barnet")
+             (with-current-buffer (if bar-id "#chan@rabnet" "#chan@barnet")
+               (erc-d-t-search-for 1 "<joe>")
+               (erc-d-t-absent-for 0.1 "<bob>")
+               (erc-d-t-search-for 20 "much in private")))
+
+           ;; XXX this is important (reconnects overlapped, so we'd get
+           ;; chan@127.0.0.1:6667)
+           (should-not (erc-scenarios-common-buflist "127.0.0.1"))
+           ;; Reconnection order doesn't matter here because session objects
+           ;; are persisted, meaning original timestamps preserved.
+           (should (equal (list (get-buffer (if bar-id "#chan@rabnet"
+                                              "#chan@barnet"))
+                                (get-buffer (if foo-id "#chan@oofnet"
+                                              "#chan@foonet")))
+                          (erc-scenarios-common-buflist "#chan"))))))
+    (erc-scenarios-common--base-network-id-bouncer
+     (list :autop t :foo-id foo-id :bar-id bar-id :after after)
+     'foonet-drop 'barnet-drop
+     'stub-again 'stub-again
+     'foonet-again 'barnet-again)))
+
+(defun erc-scenarios-common--upstream-reconnect (test &rest dialogs)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/upstream-reconnect")
+       (erc-d-t-cleanup-sleep-secs 1)
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (apply #'erc-d-run "localhost" t dialogs))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter)))
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :user "tester@vanilla/foonet"
+                                :password "changeme"
+                                :full-name "tester")
+        (erc-scenarios-common-assert-initial-buf-name nil port)
+        (erc-d-t-wait-for 3 (eq (erc-network) 'foonet))
+        (erc-d-t-wait-for 3 (string= (buffer-name) "foonet"))
+        (funcall expect 5 "foonet")))
+
+    (ert-info ("Join #chan@foonet")
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+        (funcall expect 5 "<alice>")))
+
+    (ert-info ("Connect to barnet")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :user "tester@vanilla/barnet"
+                                :password "changeme"
+                                :full-name "tester")
+        (erc-scenarios-common-assert-initial-buf-name nil port)
+        (erc-d-t-wait-for 10 (eq (erc-network) 'barnet))
+        (erc-d-t-wait-for 3 (string= (buffer-name) "barnet"))
+        (funcall expect 5 "barnet")))
+
+    (ert-info ("Server buffers are unique, no names based on IPs")
+      (should-not (erc-scenarios-common-buflist "127.0.0.1")))
+
+    (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan@foonet"))
+      (funcall expect 5 "#chan was created on ")
+      (ert-info ("Joined again #chan@foonet")
+        (funcall expect 10 "#chan was created on "))
+      (funcall expect 10 "My lord, in heart"))
+
+    (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan@barnet"))
+      (funcall expect 5 "#chan was created on ")
+      (ert-info ("Joined again #chan@barnet")
+        (funcall expect 10 "#chan was created on "))
+      (funcall expect 10 "Go to; farewell"))
+
+    (funcall test)))
+
+(provide 'erc-scenarios-common)
+
+;;; erc-scenarios-common.el ends here
diff --git a/test/lisp/erc/resources/networks/announced-missing/foonet.eld 
b/test/lisp/erc/resources/networks/announced-missing/foonet.eld
new file mode 100644
index 0000000000..79b0fb462a
--- /dev/null
+++ b/test/lisp/erc/resources/networks/announced-missing/foonet.eld
@@ -0,0 +1,8 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the FooNet Internet Relay Chat 
Network tester")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 1.2 "MODE tester +i")
+ (0 ":tester MODE tester :+Zi"))
diff --git a/test/lisp/erc/resources/services/password/libera.eld 
b/test/lisp/erc/resources/services/password/libera.eld
new file mode 100644
index 0000000000..c8dbc9d425
--- /dev/null
+++ b/test/lisp/erc/resources/services/password/libera.eld
@@ -0,0 +1,49 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0.26 ":zirconium.libera.chat NOTICE * :*** Checking Ident")
+ (0.01 ":zirconium.libera.chat NOTICE * :*** Looking up your hostname...")
+ (0.01 ":zirconium.libera.chat NOTICE * :*** No Ident response")
+ (0.02 ":zirconium.libera.chat NOTICE * :*** Found your hostname: 
static-198-54-131-100.cust.tzulo.com")
+ (0.02 ":zirconium.libera.chat 001 tester :Welcome to the Libera.Chat Internet 
Relay Chat Network tester")
+ (0.01 ":zirconium.libera.chat 002 tester :Your host is 
zirconium.libera.chat[46.16.175.175/6697], running version solanum-1.0-dev")
+ (0.03 ":zirconium.libera.chat 003 tester :This server was created Wed Jun 9 
2021 at 01:38:28 UTC")
+ (0.02 ":zirconium.libera.chat 004 tester zirconium.libera.chat 
solanum-1.0-dev DGQRSZaghilopsuwz CFILMPQSbcefgijklmnopqrstuvz bkloveqjfI")
+ (0.00 ":zirconium.libera.chat 005 tester ETRACE WHOX FNC MONITOR=100 SAFELIST 
ELIST=CTU CALLERID=g KNOCK CHANTYPES=# EXCEPTS INVEX 
CHANMODES=eIbq,k,flj,CFLMPQScgimnprstuz :are supported by this server")
+ (0.03 ":zirconium.libera.chat 005 tester CHANLIMIT=#:250 PREFIX=(ov)@+ 
MAXLIST=bqeI:100 MODES=4 NETWORK=Libera.Chat STATUSMSG=@+ CASEMAPPING=rfc1459 
NICKLEN=16 MAXNICKLEN=16 CHANNELLEN=50 TOPICLEN=390 DEAF=D :are supported by 
this server")
+ (0.02 ":zirconium.libera.chat 005 tester 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:4,NOTICE:4,ACCEPT:,MONITOR: 
EXTBAN=$,ajrxz CLIENTVER=3.0 :are supported by this server")
+ (0.02 ":zirconium.libera.chat 251 tester :There are 68 users and 37640 
invisible on 25 servers")
+ (0.00 ":zirconium.libera.chat 252 tester 36 :IRC Operators online")
+ (0.01 ":zirconium.libera.chat 253 tester 5 :unknown connection(s)")
+ (0.00 ":zirconium.libera.chat 254 tester 19341 :channels formed")
+ (0.01 ":zirconium.libera.chat 255 tester :I have 3321 clients and 1 servers")
+ (0.01 ":zirconium.libera.chat 265 tester 3321 4289 :Current local users 3321, 
max 4289")
+ (0.00 ":zirconium.libera.chat 266 tester 37708 38929 :Current global users 
37708, max 38929")
+ (0.01 ":zirconium.libera.chat 250 tester :Highest connection count: 4290 
(4289 clients) (38580 connections received)")
+ (0.21 ":zirconium.libera.chat 375 tester :- zirconium.libera.chat Message of 
the Day - ")
+ (0.00 ":zirconium.libera.chat 372 tester :- This server provided by Seeweb 
<https://www.seeweb.it/>")
+ (0.01 ":zirconium.libera.chat 372 tester :- Welcome to Libera Chat, the IRC 
network for")
+ (0.01 ":zirconium.libera.chat 372 tester :- free & open-source software and 
peer directed projects.")
+ (0.00 ":zirconium.libera.chat 372 tester :-  ")
+ (0.00 ":zirconium.libera.chat 372 tester :- Use of Libera Chat is governed by 
our network policies.")
+ (0.00 ":zirconium.libera.chat 372 tester :-  ")
+ (0.01 ":zirconium.libera.chat 372 tester :- Please visit us in #libera for 
questions and support.")
+ (0.01 ":zirconium.libera.chat 372 tester :-  ")
+ (0.01 ":zirconium.libera.chat 372 tester :- Website and documentation:  
https://libera.chat";)
+ (0.01 ":zirconium.libera.chat 372 tester :- Webchat:                    
https://web.libera.chat";)
+ (0.01 ":zirconium.libera.chat 372 tester :- Network policies:           
https://libera.chat/policies";)
+ (0.01 ":zirconium.libera.chat 372 tester :- Email:                      
support@libera.chat")
+ (0.00 ":zirconium.libera.chat 376 tester :End of /MOTD command."))
+
+((mode-user 1.2 "MODE tester +i")
+ (0.02 ":tester MODE tester :+Zi")
+ (0.02 ":NickServ!NickServ@services.libera.chat NOTICE tester :This nickname 
is registered. Please choose a different nickname, or identify via \2/msg 
NickServ IDENTIFY tester <password>\2"))
+
+((privmsg 2 "PRIVMSG NickServ :IDENTIFY changeme")
+ (0.96 ":NickServ!NickServ@services.libera.chat NOTICE tester :You are now 
identified for \2tester\2.")
+ (0.25 ":NickServ!NickServ@services.libera.chat NOTICE tester :Last login 
from: \2~tester@school.edu/tester\2 on Jun 18 01:15:56 2021 +0000."))
+
+((quit 5 "QUIT :\2ERC\2")
+ (0.19 ":tester!~user@static-198-54-131-100.cust.tzulo.com QUIT :Client Quit"))
+
+((linger 1 LINGER))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]