mirror of
https://github.com/progval/irctest.git
synced 2025-04-07 15:59:49 +00:00
Compare commits
2 Commits
redaction
...
ban-privms
Author | SHA1 | Date | |
---|---|---|---|
0816232c1c | |||
3319920250 |
340
.github/workflows/test-devel.yml
vendored
340
.github/workflows/test-devel.yml
vendored
@ -3,12 +3,12 @@
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-anope:
|
build-anope:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Create directories
|
- name: Create directories
|
||||||
run: cd ~/; mkdir -p .local/ go/
|
run: cd ~/; mkdir -p .local/ go/
|
||||||
- name: Cache dependencies
|
- name: Cache dependencies
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
key: 3-${{ runner.os }}-anope-devel
|
key: 3-${{ runner.os }}-anope-devel
|
||||||
path: '~/.cache
|
path: '~/.cache
|
||||||
@ -16,13 +16,13 @@ jobs:
|
|||||||
${ github.workspace }/anope
|
${ github.workspace }/anope
|
||||||
|
|
||||||
'
|
'
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Checkout Anope
|
- name: Checkout Anope
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
path: anope
|
path: anope
|
||||||
ref: 2.0.9
|
ref: 2.0.9
|
||||||
@ -37,18 +37,18 @@ jobs:
|
|||||||
- name: Make artefact tarball
|
- name: Make artefact tarball
|
||||||
run: cd ~; tar -czf artefacts-anope.tar.gz .local/ go/
|
run: cd ~; tar -czf artefacts-anope.tar.gz .local/ go/
|
||||||
- name: Upload build artefacts
|
- name: Upload build artefacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-anope
|
name: installed-anope
|
||||||
path: ~/artefacts-*.tar.gz
|
path: ~/artefacts-*.tar.gz
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
build-bahamut:
|
build-bahamut:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Create directories
|
- name: Create directories
|
||||||
run: cd ~/; mkdir -p .local/ go/
|
run: cd ~/; mkdir -p .local/ go/
|
||||||
- name: Cache dependencies
|
- name: Cache dependencies
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
key: 3-${{ runner.os }}-bahamut-devel
|
key: 3-${{ runner.os }}-bahamut-devel
|
||||||
path: '~/.cache
|
path: '~/.cache
|
||||||
@ -56,13 +56,13 @@ jobs:
|
|||||||
${ github.workspace }/Bahamut
|
${ github.workspace }/Bahamut
|
||||||
|
|
||||||
'
|
'
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Checkout Bahamut
|
- name: Checkout Bahamut
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
path: Bahamut
|
path: Bahamut
|
||||||
ref: master
|
ref: master
|
||||||
@ -86,18 +86,18 @@ jobs:
|
|||||||
- name: Make artefact tarball
|
- name: Make artefact tarball
|
||||||
run: cd ~; tar -czf artefacts-bahamut.tar.gz .local/ go/
|
run: cd ~; tar -czf artefacts-bahamut.tar.gz .local/ go/
|
||||||
- name: Upload build artefacts
|
- name: Upload build artefacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-bahamut
|
name: installed-bahamut
|
||||||
path: ~/artefacts-*.tar.gz
|
path: ~/artefacts-*.tar.gz
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
build-hybrid:
|
build-hybrid:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Create directories
|
- name: Create directories
|
||||||
run: cd ~/; mkdir -p .local/ go/
|
run: cd ~/; mkdir -p .local/ go/
|
||||||
- name: Cache dependencies
|
- name: Cache dependencies
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
key: 3-${{ runner.os }}-hybrid-devel
|
key: 3-${{ runner.os }}-hybrid-devel
|
||||||
path: '~/.cache
|
path: '~/.cache
|
||||||
@ -105,13 +105,13 @@ jobs:
|
|||||||
${ github.workspace }/ircd-hybrid
|
${ github.workspace }/ircd-hybrid
|
||||||
|
|
||||||
'
|
'
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Checkout Hybrid
|
- name: Checkout Hybrid
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
path: ircd-hybrid
|
path: ircd-hybrid
|
||||||
ref: 8.2.x
|
ref: 8.2.x
|
||||||
@ -125,23 +125,23 @@ jobs:
|
|||||||
- name: Make artefact tarball
|
- name: Make artefact tarball
|
||||||
run: cd ~; tar -czf artefacts-hybrid.tar.gz .local/ go/
|
run: cd ~; tar -czf artefacts-hybrid.tar.gz .local/ go/
|
||||||
- name: Upload build artefacts
|
- name: Upload build artefacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-hybrid
|
name: installed-hybrid
|
||||||
path: ~/artefacts-*.tar.gz
|
path: ~/artefacts-*.tar.gz
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
build-inspircd:
|
build-inspircd:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Create directories
|
- name: Create directories
|
||||||
run: cd ~/; mkdir -p .local/ go/
|
run: cd ~/; mkdir -p .local/ go/
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Checkout InspIRCd
|
- name: Checkout InspIRCd
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
path: inspircd
|
path: inspircd
|
||||||
ref: master
|
ref: master
|
||||||
@ -149,29 +149,25 @@ jobs:
|
|||||||
- name: Build InspIRCd
|
- name: Build InspIRCd
|
||||||
run: |
|
run: |
|
||||||
cd $GITHUB_WORKSPACE/inspircd/
|
cd $GITHUB_WORKSPACE/inspircd/
|
||||||
|
patch src/inspircd.cpp < $GITHUB_WORKSPACE/patches/inspircd_mainloop.patch
|
||||||
# Insp3 <= 3.16.0 and Insp4 <= 4.0.0a21 don't support -DINSPIRCD_UNLIMITED_MAINLOOP
|
|
||||||
patch src/inspircd.cpp < $GITHUB_WORKSPACE/patches/inspircd_mainloop.patch || true
|
|
||||||
|
|
||||||
./configure --prefix=$HOME/.local/inspircd --development
|
./configure --prefix=$HOME/.local/inspircd --development
|
||||||
|
make -j 4
|
||||||
CXXFLAGS=-DINSPIRCD_UNLIMITED_MAINLOOP make -j 4
|
|
||||||
make install
|
make install
|
||||||
- name: Make artefact tarball
|
- name: Make artefact tarball
|
||||||
run: cd ~; tar -czf artefacts-inspircd.tar.gz .local/ go/
|
run: cd ~; tar -czf artefacts-inspircd.tar.gz .local/ go/
|
||||||
- name: Upload build artefacts
|
- name: Upload build artefacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-inspircd
|
name: installed-inspircd
|
||||||
path: ~/artefacts-*.tar.gz
|
path: ~/artefacts-*.tar.gz
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
build-ngircd:
|
build-ngircd:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Create directories
|
- name: Create directories
|
||||||
run: cd ~/; mkdir -p .local/ go/
|
run: cd ~/; mkdir -p .local/ go/
|
||||||
- name: Cache dependencies
|
- name: Cache dependencies
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
key: 3-${{ runner.os }}-ngircd-devel
|
key: 3-${{ runner.os }}-ngircd-devel
|
||||||
path: '~/.cache
|
path: '~/.cache
|
||||||
@ -179,13 +175,13 @@ jobs:
|
|||||||
${ github.workspace }/ngircd
|
${ github.workspace }/ngircd
|
||||||
|
|
||||||
'
|
'
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Checkout ngircd
|
- name: Checkout ngircd
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
path: ngircd
|
path: ngircd
|
||||||
ref: master
|
ref: master
|
||||||
@ -201,18 +197,18 @@ jobs:
|
|||||||
- name: Make artefact tarball
|
- name: Make artefact tarball
|
||||||
run: cd ~; tar -czf artefacts-ngircd.tar.gz .local/ go/
|
run: cd ~; tar -czf artefacts-ngircd.tar.gz .local/ go/
|
||||||
- name: Upload build artefacts
|
- name: Upload build artefacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-ngircd
|
name: installed-ngircd
|
||||||
path: ~/artefacts-*.tar.gz
|
path: ~/artefacts-*.tar.gz
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
build-plexus4:
|
build-plexus4:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Create directories
|
- name: Create directories
|
||||||
run: cd ~/; mkdir -p .local/ go/
|
run: cd ~/; mkdir -p .local/ go/
|
||||||
- name: Cache dependencies
|
- name: Cache dependencies
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
key: 3-${{ runner.os }}-plexus4-devel
|
key: 3-${{ runner.os }}-plexus4-devel
|
||||||
path: '~/.cache
|
path: '~/.cache
|
||||||
@ -220,9 +216,9 @@ jobs:
|
|||||||
${ github.workspace }/placeholder
|
${ github.workspace }/placeholder
|
||||||
|
|
||||||
'
|
'
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: clone
|
- name: clone
|
||||||
@ -243,18 +239,18 @@ jobs:
|
|||||||
- name: Make artefact tarball
|
- name: Make artefact tarball
|
||||||
run: cd ~; tar -czf artefacts-plexus4.tar.gz .local/ go/
|
run: cd ~; tar -czf artefacts-plexus4.tar.gz .local/ go/
|
||||||
- name: Upload build artefacts
|
- name: Upload build artefacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-plexus4
|
name: installed-plexus4
|
||||||
path: ~/artefacts-*.tar.gz
|
path: ~/artefacts-*.tar.gz
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
build-solanum:
|
build-solanum:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Create directories
|
- name: Create directories
|
||||||
run: cd ~/; mkdir -p .local/ go/
|
run: cd ~/; mkdir -p .local/ go/
|
||||||
- name: Cache dependencies
|
- name: Cache dependencies
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
key: 3-${{ runner.os }}-solanum-devel
|
key: 3-${{ runner.os }}-solanum-devel
|
||||||
path: '~/.cache
|
path: '~/.cache
|
||||||
@ -262,13 +258,13 @@ jobs:
|
|||||||
${ github.workspace }/solanum
|
${ github.workspace }/solanum
|
||||||
|
|
||||||
'
|
'
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Checkout Solanum
|
- name: Checkout Solanum
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
path: solanum
|
path: solanum
|
||||||
ref: main
|
ref: main
|
||||||
@ -283,18 +279,18 @@ jobs:
|
|||||||
- name: Make artefact tarball
|
- name: Make artefact tarball
|
||||||
run: cd ~; tar -czf artefacts-solanum.tar.gz .local/ go/
|
run: cd ~; tar -czf artefacts-solanum.tar.gz .local/ go/
|
||||||
- name: Upload build artefacts
|
- name: Upload build artefacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-solanum
|
name: installed-solanum
|
||||||
path: ~/artefacts-*.tar.gz
|
path: ~/artefacts-*.tar.gz
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
build-unrealircd:
|
build-unrealircd:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Create directories
|
- name: Create directories
|
||||||
run: cd ~/; mkdir -p .local/ go/
|
run: cd ~/; mkdir -p .local/ go/
|
||||||
- name: Cache dependencies
|
- name: Cache dependencies
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
key: 3-${{ runner.os }}-unrealircd-devel
|
key: 3-${{ runner.os }}-unrealircd-devel
|
||||||
path: '~/.cache
|
path: '~/.cache
|
||||||
@ -302,13 +298,13 @@ jobs:
|
|||||||
${ github.workspace }/unrealircd
|
${ github.workspace }/unrealircd
|
||||||
|
|
||||||
'
|
'
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Checkout UnrealIRCd 6
|
- name: Checkout UnrealIRCd 6
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
path: unrealircd
|
path: unrealircd
|
||||||
ref: unreal60_dev
|
ref: unreal60_dev
|
||||||
@ -324,24 +320,23 @@ jobs:
|
|||||||
CFLAGS="-O0 -march=x86-64" CXXFLAGS="$CFLAGS" ./Config -quick
|
CFLAGS="-O0 -march=x86-64" CXXFLAGS="$CFLAGS" ./Config -quick
|
||||||
make -j 4
|
make -j 4
|
||||||
make install
|
make install
|
||||||
~/.local/unrealircd/unrealircd module install third/react
|
|
||||||
# Prevent download of geoIP database on first startup
|
# Prevent download of geoIP database on first startup
|
||||||
sed -i 's/loadmodule "geoip_classic";//' ~/.local/unrealircd/conf/modules.default.conf
|
sed -i 's/loadmodule "geoip_classic";//' ~/.local/unrealircd/conf/modules.default.conf
|
||||||
- name: Make artefact tarball
|
- name: Make artefact tarball
|
||||||
run: cd ~; tar -czf artefacts-unrealircd.tar.gz .local/ go/
|
run: cd ~; tar -czf artefacts-unrealircd.tar.gz .local/ go/
|
||||||
- name: Upload build artefacts
|
- name: Upload build artefacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-unrealircd
|
name: installed-unrealircd
|
||||||
path: ~/artefacts-*.tar.gz
|
path: ~/artefacts-*.tar.gz
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
build-unrealircd-5:
|
build-unrealircd-5:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Create directories
|
- name: Create directories
|
||||||
run: cd ~/; mkdir -p .local/ go/
|
run: cd ~/; mkdir -p .local/ go/
|
||||||
- name: Cache dependencies
|
- name: Cache dependencies
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
key: 3-${{ runner.os }}-unrealircd-5-devel
|
key: 3-${{ runner.os }}-unrealircd-5-devel
|
||||||
path: '~/.cache
|
path: '~/.cache
|
||||||
@ -349,13 +344,13 @@ jobs:
|
|||||||
${ github.workspace }/unrealircd
|
${ github.workspace }/unrealircd
|
||||||
|
|
||||||
'
|
'
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Checkout UnrealIRCd 5
|
- name: Checkout UnrealIRCd 5
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
path: unrealircd
|
path: unrealircd
|
||||||
ref: unreal52
|
ref: unreal52
|
||||||
@ -371,13 +366,12 @@ jobs:
|
|||||||
CFLAGS="-O0 -march=x86-64" CXXFLAGS="$CFLAGS" ./Config -quick
|
CFLAGS="-O0 -march=x86-64" CXXFLAGS="$CFLAGS" ./Config -quick
|
||||||
make -j 4
|
make -j 4
|
||||||
make install
|
make install
|
||||||
~/.local/unrealircd/unrealircd module install third/react
|
|
||||||
# Prevent download of geoIP database on first startup
|
# Prevent download of geoIP database on first startup
|
||||||
sed -i 's/loadmodule "geoip_classic";//' ~/.local/unrealircd/conf/modules.default.conf
|
sed -i 's/loadmodule "geoip_classic";//' ~/.local/unrealircd/conf/modules.default.conf
|
||||||
- name: Make artefact tarball
|
- name: Make artefact tarball
|
||||||
run: cd ~; tar -czf artefacts-unrealircd-5.tar.gz .local/ go/
|
run: cd ~; tar -czf artefacts-unrealircd-5.tar.gz .local/ go/
|
||||||
- name: Upload build artefacts
|
- name: Upload build artefacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-unrealircd-5
|
name: installed-unrealircd-5
|
||||||
path: ~/artefacts-*.tar.gz
|
path: ~/artefacts-*.tar.gz
|
||||||
@ -407,11 +401,11 @@ jobs:
|
|||||||
- test-unrealircd-anope
|
- test-unrealircd-anope
|
||||||
- test-unrealircd-atheme
|
- test-unrealircd-atheme
|
||||||
- test-unrealircd-dlk
|
- test-unrealircd-dlk
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Download Artifacts
|
- name: Download Artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
path: artifacts
|
path: artifacts
|
||||||
- name: Install dashboard dependencies
|
- name: Install dashboard dependencies
|
||||||
@ -434,15 +428,15 @@ jobs:
|
|||||||
test-bahamut:
|
test-bahamut:
|
||||||
needs:
|
needs:
|
||||||
- build-bahamut
|
- build-bahamut
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-bahamut
|
name: installed-bahamut
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -460,7 +454,7 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_bahamut_devel
|
name: pytest-results_bahamut_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
@ -468,20 +462,20 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- build-bahamut
|
- build-bahamut
|
||||||
- build-anope
|
- build-anope
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-bahamut
|
name: installed-bahamut
|
||||||
path: '~'
|
path: '~'
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-anope
|
name: installed-anope
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -499,22 +493,22 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_bahamut-anope_devel
|
name: pytest-results_bahamut-anope_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-bahamut-atheme:
|
test-bahamut-atheme:
|
||||||
needs:
|
needs:
|
||||||
- build-bahamut
|
- build-bahamut
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-bahamut
|
name: installed-bahamut
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -532,21 +526,21 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_bahamut-atheme_devel
|
name: pytest-results_bahamut-atheme_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-ergo:
|
test-ergo:
|
||||||
needs: []
|
needs: []
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Checkout Ergo
|
- name: Checkout Ergo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
path: ergo
|
path: ergo
|
||||||
ref: master
|
ref: master
|
||||||
@ -572,7 +566,7 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_ergo_devel
|
name: pytest-results_ergo_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
@ -580,20 +574,20 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- build-hybrid
|
- build-hybrid
|
||||||
- build-anope
|
- build-anope
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-hybrid
|
name: installed-hybrid
|
||||||
path: '~'
|
path: '~'
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-anope
|
name: installed-anope
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -611,22 +605,22 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_hybrid_devel
|
name: pytest-results_hybrid_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-inspircd:
|
test-inspircd:
|
||||||
needs:
|
needs:
|
||||||
- build-inspircd
|
- build-inspircd
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-inspircd
|
name: installed-inspircd
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -644,7 +638,7 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_inspircd_devel
|
name: pytest-results_inspircd_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
@ -652,20 +646,20 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- build-inspircd
|
- build-inspircd
|
||||||
- build-anope
|
- build-anope
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-inspircd
|
name: installed-inspircd
|
||||||
path: '~'
|
path: '~'
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-anope
|
name: installed-anope
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -683,21 +677,21 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_inspircd-anope_devel
|
name: pytest-results_inspircd-anope_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-ircu2:
|
test-ircu2:
|
||||||
needs: []
|
needs: []
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Checkout ircu2
|
- name: Checkout ircu2
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
path: ircu2
|
path: ircu2
|
||||||
ref: u2_10_12_branch
|
ref: u2_10_12_branch
|
||||||
@ -722,17 +716,17 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_ircu2_devel
|
name: pytest-results_ircu2_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-limnoria:
|
test-limnoria:
|
||||||
needs: []
|
needs: []
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@ -750,21 +744,21 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_limnoria_devel
|
name: pytest-results_limnoria_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-nefarious:
|
test-nefarious:
|
||||||
needs: []
|
needs: []
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Checkout nefarious
|
- name: Checkout nefarious
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
path: nefarious
|
path: nefarious
|
||||||
ref: master
|
ref: master
|
||||||
@ -788,22 +782,22 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_nefarious_devel
|
name: pytest-results_nefarious_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-ngircd:
|
test-ngircd:
|
||||||
needs:
|
needs:
|
||||||
- build-ngircd
|
- build-ngircd
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-ngircd
|
name: installed-ngircd
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -821,7 +815,7 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_ngircd_devel
|
name: pytest-results_ngircd_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
@ -829,20 +823,20 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- build-ngircd
|
- build-ngircd
|
||||||
- build-anope
|
- build-anope
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-ngircd
|
name: installed-ngircd
|
||||||
path: '~'
|
path: '~'
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-anope
|
name: installed-anope
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -860,22 +854,22 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_ngircd-anope_devel
|
name: pytest-results_ngircd-anope_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-ngircd-atheme:
|
test-ngircd-atheme:
|
||||||
needs:
|
needs:
|
||||||
- build-ngircd
|
- build-ngircd
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-ngircd
|
name: installed-ngircd
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -893,7 +887,7 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_ngircd-atheme_devel
|
name: pytest-results_ngircd-atheme_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
@ -901,20 +895,20 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- build-plexus4
|
- build-plexus4
|
||||||
- build-anope
|
- build-anope
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-plexus4
|
name: installed-plexus4
|
||||||
path: '~'
|
path: '~'
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-anope
|
name: installed-anope
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -932,22 +926,22 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_plexus4_devel
|
name: pytest-results_plexus4_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-solanum:
|
test-solanum:
|
||||||
needs:
|
needs:
|
||||||
- build-solanum
|
- build-solanum
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-solanum
|
name: installed-solanum
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -965,17 +959,17 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_solanum_devel
|
name: pytest-results_solanum_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-sopel:
|
test-sopel:
|
||||||
needs: []
|
needs: []
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@ -992,22 +986,22 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_sopel_devel
|
name: pytest-results_sopel_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-unrealircd:
|
test-unrealircd:
|
||||||
needs:
|
needs:
|
||||||
- build-unrealircd
|
- build-unrealircd
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-unrealircd
|
name: installed-unrealircd
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -1025,22 +1019,22 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_unrealircd_devel
|
name: pytest-results_unrealircd_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-unrealircd-5:
|
test-unrealircd-5:
|
||||||
needs:
|
needs:
|
||||||
- build-unrealircd-5
|
- build-unrealircd-5
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-unrealircd-5
|
name: installed-unrealircd-5
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -1058,7 +1052,7 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_unrealircd-5_devel
|
name: pytest-results_unrealircd-5_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
@ -1066,20 +1060,20 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- build-unrealircd
|
- build-unrealircd
|
||||||
- build-anope
|
- build-anope
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-unrealircd
|
name: installed-unrealircd
|
||||||
path: '~'
|
path: '~'
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-anope
|
name: installed-anope
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -1097,22 +1091,22 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_unrealircd-anope_devel
|
name: pytest-results_unrealircd-anope_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-unrealircd-atheme:
|
test-unrealircd-atheme:
|
||||||
needs:
|
needs:
|
||||||
- build-unrealircd
|
- build-unrealircd
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-unrealircd
|
name: installed-unrealircd
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -1130,29 +1124,29 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_unrealircd-atheme_devel
|
name: pytest-results_unrealircd-atheme_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-unrealircd-dlk:
|
test-unrealircd-dlk:
|
||||||
needs:
|
needs:
|
||||||
- build-unrealircd
|
- build-unrealircd
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-unrealircd
|
name: installed-unrealircd
|
||||||
path: '~'
|
path: '~'
|
||||||
- name: Unpack artefacts
|
- name: Unpack artefacts
|
||||||
run: cd ~; find -name 'artefacts-*.tar.gz' -exec tar -xzf '{}' \;
|
run: cd ~; find -name 'artefacts-*.tar.gz' -exec tar -xzf '{}' \;
|
||||||
- name: Checkout Dlk
|
- name: Checkout Dlk
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
path: Dlk-Services
|
path: Dlk-Services
|
||||||
ref: main
|
ref: main
|
||||||
@ -1176,7 +1170,7 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_unrealircd-dlk_devel
|
name: pytest-results_unrealircd-dlk_devel
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
|
68
.github/workflows/test-devel_release.yml
vendored
68
.github/workflows/test-devel_release.yml
vendored
@ -3,12 +3,12 @@
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-anope:
|
build-anope:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Create directories
|
- name: Create directories
|
||||||
run: cd ~/; mkdir -p .local/ go/
|
run: cd ~/; mkdir -p .local/ go/
|
||||||
- name: Cache dependencies
|
- name: Cache dependencies
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
key: 3-${{ runner.os }}-anope-devel_release
|
key: 3-${{ runner.os }}-anope-devel_release
|
||||||
path: '~/.cache
|
path: '~/.cache
|
||||||
@ -16,13 +16,13 @@ jobs:
|
|||||||
${ github.workspace }/anope
|
${ github.workspace }/anope
|
||||||
|
|
||||||
'
|
'
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Checkout Anope
|
- name: Checkout Anope
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
path: anope
|
path: anope
|
||||||
ref: 2.0.9
|
ref: 2.0.9
|
||||||
@ -37,23 +37,23 @@ jobs:
|
|||||||
- name: Make artefact tarball
|
- name: Make artefact tarball
|
||||||
run: cd ~; tar -czf artefacts-anope.tar.gz .local/ go/
|
run: cd ~; tar -czf artefacts-anope.tar.gz .local/ go/
|
||||||
- name: Upload build artefacts
|
- name: Upload build artefacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-anope
|
name: installed-anope
|
||||||
path: ~/artefacts-*.tar.gz
|
path: ~/artefacts-*.tar.gz
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
build-inspircd:
|
build-inspircd:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Create directories
|
- name: Create directories
|
||||||
run: cd ~/; mkdir -p .local/ go/
|
run: cd ~/; mkdir -p .local/ go/
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Checkout InspIRCd
|
- name: Checkout InspIRCd
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
path: inspircd
|
path: inspircd
|
||||||
ref: insp3
|
ref: insp3
|
||||||
@ -61,18 +61,14 @@ jobs:
|
|||||||
- name: Build InspIRCd
|
- name: Build InspIRCd
|
||||||
run: |
|
run: |
|
||||||
cd $GITHUB_WORKSPACE/inspircd/
|
cd $GITHUB_WORKSPACE/inspircd/
|
||||||
|
patch src/inspircd.cpp < $GITHUB_WORKSPACE/patches/inspircd_mainloop.patch
|
||||||
# Insp3 <= 3.16.0 and Insp4 <= 4.0.0a21 don't support -DINSPIRCD_UNLIMITED_MAINLOOP
|
|
||||||
patch src/inspircd.cpp < $GITHUB_WORKSPACE/patches/inspircd_mainloop.patch || true
|
|
||||||
|
|
||||||
./configure --prefix=$HOME/.local/inspircd --development
|
./configure --prefix=$HOME/.local/inspircd --development
|
||||||
|
make -j 4
|
||||||
CXXFLAGS=-DINSPIRCD_UNLIMITED_MAINLOOP make -j 4
|
|
||||||
make install
|
make install
|
||||||
- name: Make artefact tarball
|
- name: Make artefact tarball
|
||||||
run: cd ~; tar -czf artefacts-inspircd.tar.gz .local/ go/
|
run: cd ~; tar -czf artefacts-inspircd.tar.gz .local/ go/
|
||||||
- name: Upload build artefacts
|
- name: Upload build artefacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-inspircd
|
name: installed-inspircd
|
||||||
path: ~/artefacts-*.tar.gz
|
path: ~/artefacts-*.tar.gz
|
||||||
@ -84,11 +80,11 @@ jobs:
|
|||||||
- test-inspircd
|
- test-inspircd
|
||||||
- test-inspircd-anope
|
- test-inspircd-anope
|
||||||
- test-inspircd-atheme
|
- test-inspircd-atheme
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Download Artifacts
|
- name: Download Artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
path: artifacts
|
path: artifacts
|
||||||
- name: Install dashboard dependencies
|
- name: Install dashboard dependencies
|
||||||
@ -111,15 +107,15 @@ jobs:
|
|||||||
test-inspircd:
|
test-inspircd:
|
||||||
needs:
|
needs:
|
||||||
- build-inspircd
|
- build-inspircd
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-inspircd
|
name: installed-inspircd
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -137,7 +133,7 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_inspircd_devel_release
|
name: pytest-results_inspircd_devel_release
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
@ -145,20 +141,20 @@ jobs:
|
|||||||
needs:
|
needs:
|
||||||
- build-inspircd
|
- build-inspircd
|
||||||
- build-anope
|
- build-anope
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-inspircd
|
name: installed-inspircd
|
||||||
path: '~'
|
path: '~'
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-anope
|
name: installed-anope
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -176,22 +172,22 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_inspircd-anope_devel_release
|
name: pytest-results_inspircd-anope_devel_release
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
test-inspircd-atheme:
|
test-inspircd-atheme:
|
||||||
needs:
|
needs:
|
||||||
- build-inspircd
|
- build-inspircd
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Download build artefacts
|
- name: Download build artefacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: installed-inspircd
|
name: installed-inspircd
|
||||||
path: '~'
|
path: '~'
|
||||||
@ -209,7 +205,7 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
- if: always()
|
- if: always()
|
||||||
name: Publish results
|
name: Publish results
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: pytest-results_inspircd-atheme_devel_release
|
name: pytest-results_inspircd-atheme_devel_release
|
||||||
path: pytest.xml
|
path: pytest.xml
|
||||||
|
386
.github/workflows/test-stable.yml
vendored
386
.github/workflows/test-stable.yml
vendored
File diff suppressed because it is too large
Load Diff
@ -2,23 +2,22 @@ exclude: ^irctest/scram
|
|||||||
|
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 23.1.0
|
rev: 22.3.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
language_version: python3
|
language_version: python3
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/isort
|
- repo: https://github.com/PyCQA/isort
|
||||||
rev: 5.11.5
|
rev: 5.5.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: isort
|
- id: isort
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/flake8
|
- repo: https://gitlab.com/pycqa/flake8
|
||||||
rev: 5.0.4
|
rev: 5.0.4
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: v1.0.1
|
rev: v0.812
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
additional_dependencies: [types-PyYAML, types-docutils]
|
|
||||||
|
@ -110,11 +110,8 @@ cd /tmp/
|
|||||||
git clone https://github.com/inspircd/inspircd.git
|
git clone https://github.com/inspircd/inspircd.git
|
||||||
cd inspircd
|
cd inspircd
|
||||||
|
|
||||||
# Optional, makes tests run considerably faster. Pick one depending on the InspIRCd version:
|
# optional, makes tests run considerably faster
|
||||||
# on Insp3 <= 3.16.0 and Insp4 <= 4.0.0a21:
|
|
||||||
patch src/inspircd.cpp < ~/irctest/patches/inspircd_mainloop.patch
|
patch src/inspircd.cpp < ~/irctest/patches/inspircd_mainloop.patch
|
||||||
# on Insp3 >= 3.17.0 and Insp4 >= 4.0.0a22:
|
|
||||||
export CXXFLAGS=-DINSPIRCD_UNLIMITED_MAINLOOP
|
|
||||||
|
|
||||||
./configure --prefix=$HOME/.local/ --development
|
./configure --prefix=$HOME/.local/ --development
|
||||||
make -j 4
|
make -j 4
|
||||||
|
@ -1,27 +1,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import multiprocessing
|
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import shutil
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
import textwrap
|
|
||||||
import time
|
import time
|
||||||
from typing import (
|
from typing import IO, Any, Callable, Dict, List, Optional, Set, Tuple, Type
|
||||||
IO,
|
|
||||||
Any,
|
|
||||||
Callable,
|
|
||||||
Dict,
|
|
||||||
List,
|
|
||||||
MutableMapping,
|
|
||||||
Optional,
|
|
||||||
Set,
|
|
||||||
Tuple,
|
|
||||||
Type,
|
|
||||||
)
|
|
||||||
|
|
||||||
import irctest
|
import irctest
|
||||||
|
|
||||||
@ -70,43 +57,9 @@ class _BaseController:
|
|||||||
supported_sasl_mechanisms: Set[str]
|
supported_sasl_mechanisms: Set[str]
|
||||||
proc: Optional[subprocess.Popen]
|
proc: Optional[subprocess.Popen]
|
||||||
|
|
||||||
_used_ports: Set[Tuple[str, int]]
|
|
||||||
"""``(hostname, port))`` used by this controller."""
|
|
||||||
# the following need to be shared between processes in case we are running in
|
|
||||||
# parallel (with pytest-xdist)
|
|
||||||
# The dicts are used as a set of (hostname, port), because _manager.set() doesn't
|
|
||||||
# exist.
|
|
||||||
_manager = multiprocessing.Manager()
|
|
||||||
_port_lock = _manager.Lock()
|
|
||||||
"""Lock for access to ``_all_used_ports`` and ``_available_ports``."""
|
|
||||||
_all_used_ports: MutableMapping[Tuple[str, int], None] = _manager.dict()
|
|
||||||
"""``(hostname, port)`` used by all controllers."""
|
|
||||||
_available_ports: MutableMapping[Tuple[str, int], None] = _manager.dict()
|
|
||||||
"""``(hostname, port)`` available to any controller."""
|
|
||||||
|
|
||||||
def __init__(self, test_config: TestCaseControllerConfig):
|
def __init__(self, test_config: TestCaseControllerConfig):
|
||||||
self.test_config = test_config
|
self.test_config = test_config
|
||||||
self.proc = None
|
self.proc = None
|
||||||
self._used_ports = set()
|
|
||||||
|
|
||||||
def get_hostname_and_port(self) -> Tuple[str, int]:
|
|
||||||
with self._port_lock:
|
|
||||||
try:
|
|
||||||
# try to get a known available port
|
|
||||||
((hostname, port), _) = self._available_ports.popitem()
|
|
||||||
except KeyError:
|
|
||||||
# if there aren't any, iterate while we get a fresh one.
|
|
||||||
while True:
|
|
||||||
(hostname, port) = find_hostname_and_port()
|
|
||||||
if (hostname, port) not in self._all_used_ports:
|
|
||||||
# double-checking in self._used_ports to prevent collisions
|
|
||||||
# between controllers starting at the same time.
|
|
||||||
break
|
|
||||||
|
|
||||||
# Make this port unavailable to other processes
|
|
||||||
self._all_used_ports[(hostname, port)] = None
|
|
||||||
|
|
||||||
return (hostname, port)
|
|
||||||
|
|
||||||
def check_is_alive(self) -> None:
|
def check_is_alive(self) -> None:
|
||||||
assert self.proc
|
assert self.proc
|
||||||
@ -130,11 +83,6 @@ class _BaseController:
|
|||||||
if self.proc:
|
if self.proc:
|
||||||
self.kill_proc()
|
self.kill_proc()
|
||||||
|
|
||||||
# move this controller's ports from _all_used_ports to _available_ports
|
|
||||||
for hostname, port in self._used_ports:
|
|
||||||
del self._all_used_ports[(hostname, port)]
|
|
||||||
self._available_ports[(hostname, port)] = None
|
|
||||||
|
|
||||||
|
|
||||||
class DirectoryBasedController(_BaseController):
|
class DirectoryBasedController(_BaseController):
|
||||||
"""Helper for controllers whose software configuration is based on an
|
"""Helper for controllers whose software configuration is based on an
|
||||||
@ -208,18 +156,10 @@ class DirectoryBasedController(_BaseController):
|
|||||||
],
|
],
|
||||||
stderr=subprocess.DEVNULL,
|
stderr=subprocess.DEVNULL,
|
||||||
)
|
)
|
||||||
with self.dh_path.open("w") as fd:
|
subprocess.check_output(
|
||||||
fd.write(
|
[self.openssl_bin, "dhparam", "-out", self.dh_path, "128"],
|
||||||
textwrap.dedent(
|
stderr=subprocess.DEVNULL,
|
||||||
"""
|
)
|
||||||
-----BEGIN DH PARAMETERS-----
|
|
||||||
MIGHAoGBAJICSyQAiLj1fw8b5xELcnpqBQ+wvOyKgim4IetWOgZnRQFkTgOeoRZD
|
|
||||||
HksACRFJL/EqHxDKcy/2Ghwr2axhNxSJ+UOBmraP3WfodV/fCDPnZ+XnI9fjHsIr
|
|
||||||
rjisPMqomjXeiTB1UeAHvLUmCK4yx6lpAJsCYwJjsqkycUfHiy1bAgEC
|
|
||||||
-----END DH PARAMETERS-----
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class BaseClientController(_BaseController):
|
class BaseClientController(_BaseController):
|
||||||
@ -253,6 +193,9 @@ class BaseServerController(_BaseController):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.faketime_enabled = False
|
self.faketime_enabled = False
|
||||||
|
|
||||||
|
def get_hostname_and_port(self) -> Tuple[str, int]:
|
||||||
|
return find_hostname_and_port()
|
||||||
|
|
||||||
def run(
|
def run(
|
||||||
self,
|
self,
|
||||||
hostname: str,
|
hostname: str,
|
||||||
@ -261,6 +204,8 @@ class BaseServerController(_BaseController):
|
|||||||
password: Optional[str],
|
password: Optional[str],
|
||||||
ssl: bool,
|
ssl: bool,
|
||||||
run_services: bool,
|
run_services: bool,
|
||||||
|
valid_metadata_keys: Optional[Set[str]],
|
||||||
|
invalid_metadata_keys: Optional[Set[str]],
|
||||||
faketime: Optional[str],
|
faketime: Optional[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -173,7 +173,7 @@ class _IrcTestCase(Generic[TController]):
|
|||||||
) -> Optional[str]:
|
) -> Optional[str]:
|
||||||
"""Returns an error message if the message doesn't match the given arguments,
|
"""Returns an error message if the message doesn't match the given arguments,
|
||||||
or None if it matches."""
|
or None if it matches."""
|
||||||
for key, value in kwargs.items():
|
for (key, value) in kwargs.items():
|
||||||
if getattr(msg, key) != value:
|
if getattr(msg, key) != value:
|
||||||
fail_msg = (
|
fail_msg = (
|
||||||
fail_msg or "expected {param} to be {expects}, got {got}: {msg}"
|
fail_msg or "expected {param} to be {expects}, got {got}: {msg}"
|
||||||
@ -351,8 +351,8 @@ class BaseClientTestCase(_IrcTestCase[basecontrollers.BaseClientController]):
|
|||||||
nick: Optional[str] = None
|
nick: Optional[str] = None
|
||||||
user: Optional[List[str]] = None
|
user: Optional[List[str]] = None
|
||||||
server: socket.socket
|
server: socket.socket
|
||||||
protocol_version: Optional[str]
|
protocol_version = Optional[str]
|
||||||
acked_capabilities: Optional[Set[str]]
|
acked_capabilities = Optional[Set[str]]
|
||||||
|
|
||||||
__new__ = object.__new__ # pytest won't collect Generic[] subclasses otherwise
|
__new__ = object.__new__ # pytest won't collect Generic[] subclasses otherwise
|
||||||
|
|
||||||
@ -448,9 +448,7 @@ class BaseClientTestCase(_IrcTestCase[basecontrollers.BaseClientController]):
|
|||||||
print("{:.3f} S: {}".format(time.time(), line.strip()))
|
print("{:.3f} S: {}".format(time.time(), line.strip()))
|
||||||
|
|
||||||
def readCapLs(
|
def readCapLs(
|
||||||
self,
|
self, auth: Optional[Authentication] = None, tls_config: tls.TlsConfig = None
|
||||||
auth: Optional[Authentication] = None,
|
|
||||||
tls_config: Optional[tls.TlsConfig] = None,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
(hostname, port) = self.server.getsockname()
|
(hostname, port) = self.server.getsockname()
|
||||||
self.controller.run(
|
self.controller.run(
|
||||||
@ -460,9 +458,9 @@ class BaseClientTestCase(_IrcTestCase[basecontrollers.BaseClientController]):
|
|||||||
m = self.getMessage()
|
m = self.getMessage()
|
||||||
self.assertEqual(m.command, "CAP", "First message is not CAP LS.")
|
self.assertEqual(m.command, "CAP", "First message is not CAP LS.")
|
||||||
if m.params == ["LS"]:
|
if m.params == ["LS"]:
|
||||||
self.protocol_version = "301"
|
self.protocol_version = 301
|
||||||
elif m.params == ["LS", "302"]:
|
elif m.params == ["LS", "302"]:
|
||||||
self.protocol_version = "302"
|
self.protocol_version = 302
|
||||||
elif m.params == ["END"]:
|
elif m.params == ["END"]:
|
||||||
self.protocol_version = None
|
self.protocol_version = None
|
||||||
else:
|
else:
|
||||||
@ -529,6 +527,8 @@ class BaseServerTestCase(
|
|||||||
|
|
||||||
password: Optional[str] = None
|
password: Optional[str] = None
|
||||||
ssl = False
|
ssl = False
|
||||||
|
valid_metadata_keys: Set[str] = set()
|
||||||
|
invalid_metadata_keys: Set[str] = set()
|
||||||
server_support: Optional[Dict[str, Optional[str]]]
|
server_support: Optional[Dict[str, Optional[str]]]
|
||||||
run_services = False
|
run_services = False
|
||||||
|
|
||||||
@ -548,6 +548,8 @@ class BaseServerTestCase(
|
|||||||
self.hostname,
|
self.hostname,
|
||||||
self.port,
|
self.port,
|
||||||
password=self.password,
|
password=self.password,
|
||||||
|
valid_metadata_keys=self.valid_metadata_keys,
|
||||||
|
invalid_metadata_keys=self.invalid_metadata_keys,
|
||||||
ssl=self.ssl,
|
ssl=self.ssl,
|
||||||
run_services=self.run_services,
|
run_services=self.run_services,
|
||||||
faketime=self.faketime,
|
faketime=self.faketime,
|
||||||
@ -687,7 +689,7 @@ class BaseServerTestCase(
|
|||||||
def connectClient(
|
def connectClient(
|
||||||
self,
|
self,
|
||||||
nick: str,
|
nick: str,
|
||||||
name: Optional[TClientName] = None,
|
name: TClientName = None,
|
||||||
capabilities: Optional[List[str]] = None,
|
capabilities: Optional[List[str]] = None,
|
||||||
skip_if_cap_nak: bool = False,
|
skip_if_cap_nak: bool = False,
|
||||||
show_io: Optional[bool] = None,
|
show_io: Optional[bool] = None,
|
||||||
@ -706,7 +708,7 @@ class BaseServerTestCase(
|
|||||||
self.requestCapabilities(client, capabilities, skip_if_cap_nak)
|
self.requestCapabilities(client, capabilities, skip_if_cap_nak)
|
||||||
if password is not None:
|
if password is not None:
|
||||||
if "sasl" not in (capabilities or ()):
|
if "sasl" not in (capabilities or ()):
|
||||||
raise ValueError("Used 'password' option without sasl capbility")
|
raise ValueError("Used 'password' option without sasl capbilitiy")
|
||||||
self.authenticateClient(client, account or nick, password)
|
self.authenticateClient(client, account or nick, password)
|
||||||
|
|
||||||
self.sendLine(client, "NICK {}".format(nick))
|
self.sendLine(client, "NICK {}".format(nick))
|
||||||
@ -732,8 +734,8 @@ class BaseServerTestCase(
|
|||||||
self.server_support[param] = None
|
self.server_support[param] = None
|
||||||
welcome.append(m)
|
welcome.append(m)
|
||||||
|
|
||||||
self.targmax: Dict[str, Optional[str]] = dict( # type: ignore[assignment]
|
self.targmax: Dict[str, Optional[str]] = dict(
|
||||||
item.split(":", 1)
|
item.split(":", 1) # type: ignore
|
||||||
for item in (self.server_support.get("TARGMAX") or "").split(",")
|
for item in (self.server_support.get("TARGMAX") or "").split(",")
|
||||||
if item
|
if item
|
||||||
)
|
)
|
||||||
|
@ -3,7 +3,12 @@ import shutil
|
|||||||
import subprocess
|
import subprocess
|
||||||
from typing import Optional, Set, Type
|
from typing import Optional, Set, Type
|
||||||
|
|
||||||
from irctest.basecontrollers import BaseServerController, DirectoryBasedController
|
from irctest.basecontrollers import (
|
||||||
|
BaseServerController,
|
||||||
|
DirectoryBasedController,
|
||||||
|
NotImplementedByController,
|
||||||
|
)
|
||||||
|
from irctest.irc_utils.junkdrawer import find_hostname_and_port
|
||||||
|
|
||||||
TEMPLATE_CONFIG = """
|
TEMPLATE_CONFIG = """
|
||||||
global {{
|
global {{
|
||||||
@ -107,14 +112,21 @@ class BahamutController(BaseServerController, DirectoryBasedController):
|
|||||||
password: Optional[str],
|
password: Optional[str],
|
||||||
ssl: bool,
|
ssl: bool,
|
||||||
run_services: bool,
|
run_services: bool,
|
||||||
|
valid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
invalid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
restricted_metadata_keys: Optional[Set[str]] = None,
|
||||||
faketime: Optional[str],
|
faketime: Optional[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
|
if valid_metadata_keys or invalid_metadata_keys:
|
||||||
|
raise NotImplementedByController(
|
||||||
|
"Defining valid and invalid METADATA keys."
|
||||||
|
)
|
||||||
assert self.proc is None
|
assert self.proc is None
|
||||||
self.port = port
|
self.port = port
|
||||||
self.hostname = hostname
|
self.hostname = hostname
|
||||||
self.create_config()
|
self.create_config()
|
||||||
(unused_hostname, unused_port) = self.get_hostname_and_port()
|
(unused_hostname, unused_port) = find_hostname_and_port()
|
||||||
(services_hostname, services_port) = self.get_hostname_and_port()
|
(services_hostname, services_port) = find_hostname_and_port()
|
||||||
|
|
||||||
password_field = "passwd {};".format(password) if password else ""
|
password_field = "passwd {};".format(password) if password else ""
|
||||||
|
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import Optional
|
from typing import Optional, Set
|
||||||
|
|
||||||
from irctest.basecontrollers import BaseServerController, DirectoryBasedController
|
from irctest.basecontrollers import (
|
||||||
|
BaseServerController,
|
||||||
|
DirectoryBasedController,
|
||||||
|
NotImplementedByController,
|
||||||
|
)
|
||||||
|
from irctest.irc_utils.junkdrawer import find_hostname_and_port
|
||||||
|
|
||||||
TEMPLATE_SSL_CONFIG = """
|
TEMPLATE_SSL_CONFIG = """
|
||||||
ssl_private_key = "{key_path}";
|
ssl_private_key = "{key_path}";
|
||||||
@ -36,13 +41,19 @@ class BaseHybridController(BaseServerController, DirectoryBasedController):
|
|||||||
password: Optional[str],
|
password: Optional[str],
|
||||||
ssl: bool,
|
ssl: bool,
|
||||||
run_services: bool,
|
run_services: bool,
|
||||||
|
valid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
invalid_metadata_keys: Optional[Set[str]] = None,
|
||||||
faketime: Optional[str],
|
faketime: Optional[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
|
if valid_metadata_keys or invalid_metadata_keys:
|
||||||
|
raise NotImplementedByController(
|
||||||
|
"Defining valid and invalid METADATA keys."
|
||||||
|
)
|
||||||
assert self.proc is None
|
assert self.proc is None
|
||||||
self.port = port
|
self.port = port
|
||||||
self.hostname = hostname
|
self.hostname = hostname
|
||||||
self.create_config()
|
self.create_config()
|
||||||
(services_hostname, services_port) = self.get_hostname_and_port()
|
(services_hostname, services_port) = find_hostname_and_port()
|
||||||
password_field = 'password = "{}";'.format(password) if password else ""
|
password_field = 'password = "{}";'.format(password) if password else ""
|
||||||
if ssl:
|
if ssl:
|
||||||
self.gen_ssl()
|
self.gen_ssl()
|
||||||
|
@ -3,9 +3,13 @@ import json
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import Any, Dict, Optional, Type, Union
|
from typing import Any, Dict, Optional, Set, Type, Union
|
||||||
|
|
||||||
from irctest.basecontrollers import BaseServerController, DirectoryBasedController
|
from irctest.basecontrollers import (
|
||||||
|
BaseServerController,
|
||||||
|
DirectoryBasedController,
|
||||||
|
NotImplementedByController,
|
||||||
|
)
|
||||||
from irctest.cases import BaseServerTestCase
|
from irctest.cases import BaseServerTestCase
|
||||||
|
|
||||||
BASE_CONFIG = {
|
BASE_CONFIG = {
|
||||||
@ -77,9 +81,6 @@ BASE_CONFIG = {
|
|||||||
"channel-length": 128,
|
"channel-length": 128,
|
||||||
"client-length": 128,
|
"client-length": 128,
|
||||||
"chathistory-maxmessages": 100,
|
"chathistory-maxmessages": 100,
|
||||||
"retention": {
|
|
||||||
"allow-individual-delete": True,
|
|
||||||
},
|
|
||||||
"tagmsg-storage": {
|
"tagmsg-storage": {
|
||||||
"default": False,
|
"default": False,
|
||||||
"whitelist": ["+draft/persist", "+persist"],
|
"whitelist": ["+draft/persist", "+persist"],
|
||||||
@ -129,7 +130,7 @@ def hash_password(password: Union[str, bytes]) -> str:
|
|||||||
["ergo", "genpasswd"], stdin=subprocess.PIPE, stdout=subprocess.PIPE
|
["ergo", "genpasswd"], stdin=subprocess.PIPE, stdout=subprocess.PIPE
|
||||||
)
|
)
|
||||||
out, _ = p.communicate(input_)
|
out, _ = p.communicate(input_)
|
||||||
return out.decode("utf-8").strip()
|
return out.decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
class ErgoController(BaseServerController, DirectoryBasedController):
|
class ErgoController(BaseServerController, DirectoryBasedController):
|
||||||
@ -152,9 +153,17 @@ class ErgoController(BaseServerController, DirectoryBasedController):
|
|||||||
password: Optional[str],
|
password: Optional[str],
|
||||||
ssl: bool,
|
ssl: bool,
|
||||||
run_services: bool,
|
run_services: bool,
|
||||||
|
valid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
invalid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
restricted_metadata_keys: Optional[Set[str]] = None,
|
||||||
faketime: Optional[str],
|
faketime: Optional[str],
|
||||||
config: Optional[Any] = None,
|
config: Optional[Any] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
if valid_metadata_keys or invalid_metadata_keys:
|
||||||
|
raise NotImplementedByController(
|
||||||
|
"Defining valid and invalid METADATA keys."
|
||||||
|
)
|
||||||
|
|
||||||
self.create_config()
|
self.create_config()
|
||||||
if config is None:
|
if config is None:
|
||||||
config = copy.deepcopy(BASE_CONFIG)
|
config = copy.deepcopy(BASE_CONFIG)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
from typing import Optional, Tuple, Type
|
from typing import Optional, Set, Tuple, Type
|
||||||
|
|
||||||
from irctest.basecontrollers import BaseServerController
|
from irctest.basecontrollers import BaseServerController
|
||||||
|
|
||||||
@ -39,6 +39,9 @@ class ExternalServerController(BaseServerController):
|
|||||||
password: Optional[str],
|
password: Optional[str],
|
||||||
ssl: bool,
|
ssl: bool,
|
||||||
run_services: bool,
|
run_services: bool,
|
||||||
|
valid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
invalid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
restricted_metadata_keys: Optional[Set[str]] = None,
|
||||||
faketime: Optional[str],
|
faketime: Optional[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
pass
|
pass
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
import functools
|
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import Optional, Type
|
from typing import Optional, Set, Type
|
||||||
|
|
||||||
from irctest.basecontrollers import BaseServerController, DirectoryBasedController
|
from irctest.basecontrollers import (
|
||||||
|
BaseServerController,
|
||||||
|
DirectoryBasedController,
|
||||||
|
NotImplementedByController,
|
||||||
|
)
|
||||||
|
from irctest.irc_utils.junkdrawer import find_hostname_and_port
|
||||||
|
|
||||||
TEMPLATE_CONFIG = """
|
TEMPLATE_CONFIG = """
|
||||||
# Clients:
|
# Clients:
|
||||||
@ -76,8 +80,8 @@ TEMPLATE_CONFIG = """
|
|||||||
|
|
||||||
# HELP/HELPOP
|
# HELP/HELPOP
|
||||||
<module name="alias"> # for the HELP alias
|
<module name="alias"> # for the HELP alias
|
||||||
<module name="{help_module_name}">
|
<module name="helpop">
|
||||||
<include file="examples/{help_module_name}.conf.example">
|
<include file="examples/helpop.conf.example">
|
||||||
|
|
||||||
# Misc:
|
# Misc:
|
||||||
<log method="file" type="*" level="debug" target="/tmp/ircd-{port}.log">
|
<log method="file" type="*" level="debug" target="/tmp/ircd-{port}.log">
|
||||||
@ -90,17 +94,6 @@ TEMPLATE_SSL_CONFIG = """
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@functools.lru_cache()
|
|
||||||
def installed_version() -> int:
|
|
||||||
output = subprocess.check_output(["inspircd", "--version"], universal_newlines=True)
|
|
||||||
if output.startswith("InspIRCd-3"):
|
|
||||||
return 3
|
|
||||||
if output.startswith("InspIRCd-4"):
|
|
||||||
return 4
|
|
||||||
else:
|
|
||||||
assert False, f"unexpected version: {output}"
|
|
||||||
|
|
||||||
|
|
||||||
class InspircdController(BaseServerController, DirectoryBasedController):
|
class InspircdController(BaseServerController, DirectoryBasedController):
|
||||||
software_name = "InspIRCd"
|
software_name = "InspIRCd"
|
||||||
supported_sasl_mechanisms = {"PLAIN"}
|
supported_sasl_mechanisms = {"PLAIN"}
|
||||||
@ -120,13 +113,20 @@ class InspircdController(BaseServerController, DirectoryBasedController):
|
|||||||
password: Optional[str],
|
password: Optional[str],
|
||||||
ssl: bool,
|
ssl: bool,
|
||||||
run_services: bool,
|
run_services: bool,
|
||||||
|
valid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
invalid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
restricted_metadata_keys: Optional[Set[str]] = None,
|
||||||
faketime: Optional[str] = None,
|
faketime: Optional[str] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
if valid_metadata_keys or invalid_metadata_keys:
|
||||||
|
raise NotImplementedByController(
|
||||||
|
"Defining valid and invalid METADATA keys."
|
||||||
|
)
|
||||||
assert self.proc is None
|
assert self.proc is None
|
||||||
self.port = port
|
self.port = port
|
||||||
self.hostname = hostname
|
self.hostname = hostname
|
||||||
self.create_config()
|
self.create_config()
|
||||||
(services_hostname, services_port) = self.get_hostname_and_port()
|
(services_hostname, services_port) = find_hostname_and_port()
|
||||||
|
|
||||||
password_field = 'password="{}"'.format(password) if password else ""
|
password_field = 'password="{}"'.format(password) if password else ""
|
||||||
|
|
||||||
@ -138,13 +138,6 @@ class InspircdController(BaseServerController, DirectoryBasedController):
|
|||||||
else:
|
else:
|
||||||
ssl_config = ""
|
ssl_config = ""
|
||||||
|
|
||||||
if installed_version() == 3:
|
|
||||||
help_module_name = "helpop"
|
|
||||||
elif installed_version() == 4:
|
|
||||||
help_module_name = "help"
|
|
||||||
else:
|
|
||||||
assert False, f"unexpected version: {installed_version()}"
|
|
||||||
|
|
||||||
with self.open_file("server.conf") as fd:
|
with self.open_file("server.conf") as fd:
|
||||||
fd.write(
|
fd.write(
|
||||||
TEMPLATE_CONFIG.format(
|
TEMPLATE_CONFIG.format(
|
||||||
@ -154,7 +147,6 @@ class InspircdController(BaseServerController, DirectoryBasedController):
|
|||||||
services_port=services_port,
|
services_port=services_port,
|
||||||
password_field=password_field,
|
password_field=password_field,
|
||||||
ssl_config=ssl_config,
|
ssl_config=ssl_config,
|
||||||
help_module_name=help_module_name,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
assert self.directory
|
assert self.directory
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import Optional, Type
|
from typing import Optional, Set, Type
|
||||||
|
|
||||||
from irctest.basecontrollers import (
|
from irctest.basecontrollers import (
|
||||||
BaseServerController,
|
BaseServerController,
|
||||||
@ -49,8 +49,14 @@ class Irc2Controller(BaseServerController, DirectoryBasedController):
|
|||||||
password: Optional[str],
|
password: Optional[str],
|
||||||
ssl: bool,
|
ssl: bool,
|
||||||
run_services: bool,
|
run_services: bool,
|
||||||
|
valid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
invalid_metadata_keys: Optional[Set[str]] = None,
|
||||||
faketime: Optional[str],
|
faketime: Optional[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
|
if valid_metadata_keys or invalid_metadata_keys:
|
||||||
|
raise NotImplementedByController(
|
||||||
|
"Defining valid and invalid METADATA keys."
|
||||||
|
)
|
||||||
if ssl:
|
if ssl:
|
||||||
raise NotImplementedByController("TLS")
|
raise NotImplementedByController("TLS")
|
||||||
if run_services:
|
if run_services:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import Optional, Type
|
from typing import Optional, Set, Type
|
||||||
|
|
||||||
from irctest.basecontrollers import (
|
from irctest.basecontrollers import (
|
||||||
BaseServerController,
|
BaseServerController,
|
||||||
@ -68,8 +68,14 @@ class Ircu2Controller(BaseServerController, DirectoryBasedController):
|
|||||||
password: Optional[str],
|
password: Optional[str],
|
||||||
ssl: bool,
|
ssl: bool,
|
||||||
run_services: bool,
|
run_services: bool,
|
||||||
|
valid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
invalid_metadata_keys: Optional[Set[str]] = None,
|
||||||
faketime: Optional[str],
|
faketime: Optional[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
|
if valid_metadata_keys or invalid_metadata_keys:
|
||||||
|
raise NotImplementedByController(
|
||||||
|
"Defining valid and invalid METADATA keys."
|
||||||
|
)
|
||||||
if ssl:
|
if ssl:
|
||||||
raise NotImplementedByController("TLS")
|
raise NotImplementedByController("TLS")
|
||||||
if run_services:
|
if run_services:
|
||||||
|
@ -33,10 +33,10 @@ extensions:
|
|||||||
- mammon.ext.ircv3.sasl
|
- mammon.ext.ircv3.sasl
|
||||||
- mammon.ext.misc.nopost
|
- mammon.ext.misc.nopost
|
||||||
metadata:
|
metadata:
|
||||||
restricted_keys: []
|
restricted_keys:
|
||||||
|
{restricted_keys}
|
||||||
whitelist:
|
whitelist:
|
||||||
- display-name
|
{authorized_keys}
|
||||||
- avatar
|
|
||||||
monitor:
|
monitor:
|
||||||
limit: 20
|
limit: 20
|
||||||
motd:
|
motd:
|
||||||
@ -89,6 +89,9 @@ class MammonController(BaseServerController, DirectoryBasedController):
|
|||||||
password: Optional[str],
|
password: Optional[str],
|
||||||
ssl: bool,
|
ssl: bool,
|
||||||
run_services: bool,
|
run_services: bool,
|
||||||
|
valid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
invalid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
restricted_metadata_keys: Optional[Set[str]] = None,
|
||||||
faketime: Optional[str],
|
faketime: Optional[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
if password is not None:
|
if password is not None:
|
||||||
@ -104,6 +107,8 @@ class MammonController(BaseServerController, DirectoryBasedController):
|
|||||||
directory=self.directory,
|
directory=self.directory,
|
||||||
hostname=hostname,
|
hostname=hostname,
|
||||||
port=port,
|
port=port,
|
||||||
|
authorized_keys=make_list(valid_metadata_keys or set()),
|
||||||
|
restricted_keys=make_list(restricted_metadata_keys or set()),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# with self.open_file('server.yml', 'r') as fd:
|
# with self.open_file('server.yml', 'r') as fd:
|
||||||
|
@ -2,7 +2,12 @@ import shutil
|
|||||||
import subprocess
|
import subprocess
|
||||||
from typing import Optional, Set, Type
|
from typing import Optional, Set, Type
|
||||||
|
|
||||||
from irctest.basecontrollers import BaseServerController, DirectoryBasedController
|
from irctest.basecontrollers import (
|
||||||
|
BaseServerController,
|
||||||
|
DirectoryBasedController,
|
||||||
|
NotImplementedByController,
|
||||||
|
)
|
||||||
|
from irctest.irc_utils.junkdrawer import find_hostname_and_port
|
||||||
|
|
||||||
TEMPLATE_CONFIG = """
|
TEMPLATE_CONFIG = """
|
||||||
[Global]
|
[Global]
|
||||||
@ -48,13 +53,20 @@ class NgircdController(BaseServerController, DirectoryBasedController):
|
|||||||
password: Optional[str],
|
password: Optional[str],
|
||||||
ssl: bool,
|
ssl: bool,
|
||||||
run_services: bool,
|
run_services: bool,
|
||||||
|
valid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
invalid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
restricted_metadata_keys: Optional[Set[str]] = None,
|
||||||
faketime: Optional[str],
|
faketime: Optional[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
|
if valid_metadata_keys or invalid_metadata_keys:
|
||||||
|
raise NotImplementedByController(
|
||||||
|
"Defining valid and invalid METADATA keys."
|
||||||
|
)
|
||||||
assert self.proc is None
|
assert self.proc is None
|
||||||
self.port = port
|
self.port = port
|
||||||
self.hostname = hostname
|
self.hostname = hostname
|
||||||
self.create_config()
|
self.create_config()
|
||||||
(unused_hostname, unused_port) = self.get_hostname_and_port()
|
(unused_hostname, unused_port) = find_hostname_and_port()
|
||||||
|
|
||||||
password_field = "Password = {}".format(password) if password else ""
|
password_field = "Password = {}".format(password) if password else ""
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import Optional, Type
|
from typing import Optional, Set, Type
|
||||||
|
|
||||||
from irctest.basecontrollers import (
|
from irctest.basecontrollers import (
|
||||||
BaseServerController,
|
BaseServerController,
|
||||||
@ -67,8 +67,14 @@ class SnircdController(BaseServerController, DirectoryBasedController):
|
|||||||
password: Optional[str],
|
password: Optional[str],
|
||||||
ssl: bool,
|
ssl: bool,
|
||||||
run_services: bool,
|
run_services: bool,
|
||||||
|
valid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
invalid_metadata_keys: Optional[Set[str]] = None,
|
||||||
faketime: Optional[str],
|
faketime: Optional[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
|
if valid_metadata_keys or invalid_metadata_keys:
|
||||||
|
raise NotImplementedByController(
|
||||||
|
"Defining valid and invalid METADATA keys."
|
||||||
|
)
|
||||||
if ssl:
|
if ssl:
|
||||||
raise NotImplementedByController("TLS")
|
raise NotImplementedByController("TLS")
|
||||||
if run_services:
|
if run_services:
|
||||||
|
@ -73,7 +73,7 @@ class SopelController(BaseClientController):
|
|||||||
auth_method="auth_method = sasl" if auth else "",
|
auth_method="auth_method = sasl" if auth else "",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.proc = subprocess.Popen(["sopel", "-c", self.filename])
|
self.proc = subprocess.Popen(["sopel", "--quiet", "-c", self.filename])
|
||||||
|
|
||||||
|
|
||||||
def get_irctest_controller_class() -> Type[SopelController]:
|
def get_irctest_controller_class() -> Type[SopelController]:
|
||||||
|
@ -5,15 +5,19 @@ from pathlib import Path
|
|||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import textwrap
|
import textwrap
|
||||||
from typing import Callable, ContextManager, Iterator, Optional, Type
|
from typing import Callable, ContextManager, Iterator, Optional, Set, Type
|
||||||
|
|
||||||
from irctest.basecontrollers import BaseServerController, DirectoryBasedController
|
from irctest.basecontrollers import (
|
||||||
|
BaseServerController,
|
||||||
|
DirectoryBasedController,
|
||||||
|
NotImplementedByController,
|
||||||
|
)
|
||||||
|
from irctest.irc_utils.junkdrawer import find_hostname_and_port
|
||||||
|
|
||||||
TEMPLATE_CONFIG = """
|
TEMPLATE_CONFIG = """
|
||||||
include "modules.default.conf";
|
include "modules.default.conf";
|
||||||
include "operclass.default.conf";
|
include "operclass.default.conf";
|
||||||
{extras}
|
{extras}
|
||||||
loadmodule "third/redact";
|
|
||||||
include "help/help.conf";
|
include "help/help.conf";
|
||||||
|
|
||||||
me {{
|
me {{
|
||||||
@ -97,12 +101,7 @@ set {{
|
|||||||
}}
|
}}
|
||||||
modes-on-join "+H 100:1d"; // Enables CHATHISTORY
|
modes-on-join "+H 100:1d"; // Enables CHATHISTORY
|
||||||
|
|
||||||
redacters {{
|
{set_extras}
|
||||||
op;
|
|
||||||
sender;
|
|
||||||
}}
|
|
||||||
|
|
||||||
{set_v6only}
|
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -125,24 +124,6 @@ oper "operuser" {{
|
|||||||
}}
|
}}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SET_V6ONLY = """
|
|
||||||
// Remove RPL_WHOISSPECIAL used to advertise security groups
|
|
||||||
whois-details {
|
|
||||||
security-groups { everyone none; self none; oper none; }
|
|
||||||
}
|
|
||||||
|
|
||||||
plaintext-policy {
|
|
||||||
server warn; // https://www.unrealircd.org/docs/FAQ#server-requires-tls
|
|
||||||
oper warn; // https://www.unrealircd.org/docs/FAQ#oper-requires-tls
|
|
||||||
}
|
|
||||||
|
|
||||||
anti-flood {
|
|
||||||
everyone {
|
|
||||||
connect-flood 255:10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def _filelock(path: Path) -> Callable[[], ContextManager]:
|
def _filelock(path: Path) -> Callable[[], ContextManager]:
|
||||||
"""Alternative to :cls:`multiprocessing.Lock` that works with pytest-xdist"""
|
"""Alternative to :cls:`multiprocessing.Lock` that works with pytest-xdist"""
|
||||||
@ -205,8 +186,15 @@ class UnrealircdController(BaseServerController, DirectoryBasedController):
|
|||||||
password: Optional[str],
|
password: Optional[str],
|
||||||
ssl: bool,
|
ssl: bool,
|
||||||
run_services: bool,
|
run_services: bool,
|
||||||
|
valid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
invalid_metadata_keys: Optional[Set[str]] = None,
|
||||||
|
restricted_metadata_keys: Optional[Set[str]] = None,
|
||||||
faketime: Optional[str],
|
faketime: Optional[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
|
if valid_metadata_keys or invalid_metadata_keys:
|
||||||
|
raise NotImplementedByController(
|
||||||
|
"Defining valid and invalid METADATA keys."
|
||||||
|
)
|
||||||
assert self.proc is None
|
assert self.proc is None
|
||||||
self.port = port
|
self.port = port
|
||||||
self.hostname = hostname
|
self.hostname = hostname
|
||||||
@ -219,54 +207,64 @@ class UnrealircdController(BaseServerController, DirectoryBasedController):
|
|||||||
loadmodule "cloak_md5";
|
loadmodule "cloak_md5";
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
set_v6only = SET_V6ONLY
|
set_extras = textwrap.indent(
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
|
// Remove RPL_WHOISSPECIAL used to advertise security groups
|
||||||
|
whois-details {
|
||||||
|
security-groups { everyone none; self none; oper none; }
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
" ",
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
extras = ""
|
extras = ""
|
||||||
set_v6only = ""
|
set_extras = ""
|
||||||
|
|
||||||
with self.open_file("empty.txt") as fd:
|
with self.open_file("empty.txt") as fd:
|
||||||
fd.write("\n")
|
fd.write("\n")
|
||||||
|
|
||||||
password_field = 'password "{}";'.format(password) if password else ""
|
password_field = 'password "{}";'.format(password) if password else ""
|
||||||
|
|
||||||
(services_hostname, services_port) = self.get_hostname_and_port()
|
|
||||||
(unused_hostname, unused_port) = self.get_hostname_and_port()
|
|
||||||
|
|
||||||
self.gen_ssl()
|
|
||||||
if ssl:
|
|
||||||
(tls_hostname, tls_port) = (hostname, port)
|
|
||||||
(hostname, port) = (unused_hostname, unused_port)
|
|
||||||
else:
|
|
||||||
# Unreal refuses to start without TLS enabled
|
|
||||||
(tls_hostname, tls_port) = (unused_hostname, unused_port)
|
|
||||||
|
|
||||||
assert self.directory
|
|
||||||
|
|
||||||
with self.open_file("unrealircd.conf") as fd:
|
|
||||||
fd.write(
|
|
||||||
TEMPLATE_CONFIG.format(
|
|
||||||
hostname=hostname,
|
|
||||||
port=port,
|
|
||||||
services_hostname=services_hostname,
|
|
||||||
services_port=services_port,
|
|
||||||
tls_hostname=tls_hostname,
|
|
||||||
tls_port=tls_port,
|
|
||||||
password_field=password_field,
|
|
||||||
key_path=self.key_path,
|
|
||||||
pem_path=self.pem_path,
|
|
||||||
empty_file=self.directory / "empty.txt",
|
|
||||||
set_v6only=set_v6only,
|
|
||||||
extras=extras,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if faketime and shutil.which("faketime"):
|
|
||||||
faketime_cmd = ["faketime", "-f", faketime]
|
|
||||||
self.faketime_enabled = True
|
|
||||||
else:
|
|
||||||
faketime_cmd = []
|
|
||||||
|
|
||||||
with _STARTSTOP_LOCK():
|
with _STARTSTOP_LOCK():
|
||||||
|
(services_hostname, services_port) = find_hostname_and_port()
|
||||||
|
(unused_hostname, unused_port) = find_hostname_and_port()
|
||||||
|
|
||||||
|
self.gen_ssl()
|
||||||
|
if ssl:
|
||||||
|
(tls_hostname, tls_port) = (hostname, port)
|
||||||
|
(hostname, port) = (unused_hostname, unused_port)
|
||||||
|
else:
|
||||||
|
# Unreal refuses to start without TLS enabled
|
||||||
|
(tls_hostname, tls_port) = (unused_hostname, unused_port)
|
||||||
|
|
||||||
|
assert self.directory
|
||||||
|
|
||||||
|
with self.open_file("unrealircd.conf") as fd:
|
||||||
|
fd.write(
|
||||||
|
TEMPLATE_CONFIG.format(
|
||||||
|
hostname=hostname,
|
||||||
|
port=port,
|
||||||
|
services_hostname=services_hostname,
|
||||||
|
services_port=services_port,
|
||||||
|
tls_hostname=tls_hostname,
|
||||||
|
tls_port=tls_port,
|
||||||
|
password_field=password_field,
|
||||||
|
key_path=self.key_path,
|
||||||
|
pem_path=self.pem_path,
|
||||||
|
empty_file=self.directory / "empty.txt",
|
||||||
|
extras=extras,
|
||||||
|
set_extras=set_extras,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if faketime and shutil.which("faketime"):
|
||||||
|
faketime_cmd = ["faketime", "-f", faketime]
|
||||||
|
self.faketime_enabled = True
|
||||||
|
else:
|
||||||
|
faketime_cmd = []
|
||||||
|
|
||||||
self.proc = subprocess.Popen(
|
self.proc = subprocess.Popen(
|
||||||
[
|
[
|
||||||
*faketime_cmd,
|
*faketime_cmd,
|
||||||
|
@ -39,7 +39,7 @@ class CaseResult:
|
|||||||
type: Optional[str] = None
|
type: Optional[str] = None
|
||||||
message: Optional[str] = None
|
message: Optional[str] = None
|
||||||
|
|
||||||
def output_filename(self) -> str:
|
def output_filename(self):
|
||||||
test_name = self.test_name
|
test_name = self.test_name
|
||||||
if len(test_name) > 50 or set(test_name) & NETLIFY_CHAR_BLACKLIST:
|
if len(test_name) > 50 or set(test_name) & NETLIFY_CHAR_BLACKLIST:
|
||||||
# File name too long or otherwise invalid. This should be good enough:
|
# File name too long or otherwise invalid. This should be good enough:
|
||||||
@ -75,7 +75,7 @@ def iter_job_results(job_file_name: Path, job: ET.ElementTree) -> Iterator[CaseR
|
|||||||
skipped = False
|
skipped = False
|
||||||
details = None
|
details = None
|
||||||
system_out = None
|
system_out = None
|
||||||
extra: Dict[str, str] = {}
|
extra = {}
|
||||||
for child in case:
|
for child in case:
|
||||||
if child.tag == "skipped":
|
if child.tag == "skipped":
|
||||||
success = True
|
success = True
|
||||||
@ -187,7 +187,7 @@ def build_test_table(jobs: List[str], results: List[CaseResult]) -> ET.Element:
|
|||||||
ET.SubElement(ET.SubElement(cell, "div"), "span").text = job
|
ET.SubElement(ET.SubElement(cell, "div"), "span").text = job
|
||||||
cell.set("class", "job-name")
|
cell.set("class", "job-name")
|
||||||
|
|
||||||
for (module_name, class_name), class_results in sorted(
|
for ((module_name, class_name), class_results) in sorted(
|
||||||
results_by_module_and_class.items()
|
results_by_module_and_class.items()
|
||||||
):
|
):
|
||||||
if multiple_modules:
|
if multiple_modules:
|
||||||
@ -220,7 +220,7 @@ def build_test_table(jobs: List[str], results: List[CaseResult]) -> ET.Element:
|
|||||||
|
|
||||||
# One row for each test:
|
# One row for each test:
|
||||||
results_by_test = group_by(class_results, key=lambda r: r.test_name)
|
results_by_test = group_by(class_results, key=lambda r: r.test_name)
|
||||||
for test_name, test_results in sorted(results_by_test.items()):
|
for (test_name, test_results) in sorted(results_by_test.items()):
|
||||||
row_anchor = f"{qualified_class_name}.{test_name}"
|
row_anchor = f"{qualified_class_name}.{test_name}"
|
||||||
if len(row_anchor) >= 50:
|
if len(row_anchor) >= 50:
|
||||||
# Too long; give up on generating readable URL
|
# Too long; give up on generating readable URL
|
||||||
@ -314,7 +314,7 @@ def write_html_pages(
|
|||||||
|
|
||||||
pages = []
|
pages = []
|
||||||
|
|
||||||
for module_name, module_results in sorted(results_by_module.items()):
|
for (module_name, module_results) in sorted(results_by_module.items()):
|
||||||
# Filter out client jobs if this is a server test module, and vice versa
|
# Filter out client jobs if this is a server test module, and vice versa
|
||||||
module_categories = {
|
module_categories = {
|
||||||
job_categories[result.job]
|
job_categories[result.job]
|
||||||
@ -366,7 +366,7 @@ def write_html_index(output_dir: Path, pages: List[Tuple[str, str, str]]) -> Non
|
|||||||
|
|
||||||
module_pages = []
|
module_pages = []
|
||||||
job_pages = []
|
job_pages = []
|
||||||
for page_type, title, file_name in sorted(pages):
|
for (page_type, title, file_name) in sorted(pages):
|
||||||
if page_type == "module":
|
if page_type == "module":
|
||||||
module_pages.append((title, file_name))
|
module_pages.append((title, file_name))
|
||||||
elif page_type == "job":
|
elif page_type == "job":
|
||||||
@ -379,7 +379,7 @@ def write_html_index(output_dir: Path, pages: List[Tuple[str, str, str]]) -> Non
|
|||||||
dl = ET.SubElement(body, "dl")
|
dl = ET.SubElement(body, "dl")
|
||||||
dl.set("class", "module-index")
|
dl.set("class", "module-index")
|
||||||
|
|
||||||
for module_name, file_name in sorted(module_pages):
|
for (module_name, file_name) in sorted(module_pages):
|
||||||
module = importlib.import_module(module_name)
|
module = importlib.import_module(module_name)
|
||||||
|
|
||||||
link = ET.SubElement(ET.SubElement(dl, "dt"), "a", href=f"./{file_name}")
|
link = ET.SubElement(ET.SubElement(dl, "dt"), "a", href=f"./{file_name}")
|
||||||
@ -391,7 +391,7 @@ def write_html_index(output_dir: Path, pages: List[Tuple[str, str, str]]) -> Non
|
|||||||
ul = ET.SubElement(body, "ul")
|
ul = ET.SubElement(body, "ul")
|
||||||
ul.set("class", "job-index")
|
ul.set("class", "job-index")
|
||||||
|
|
||||||
for job, file_name in sorted(job_pages):
|
for (job, file_name) in sorted(job_pages):
|
||||||
link = ET.SubElement(ET.SubElement(ul, "li"), "a", href=f"./{file_name}")
|
link = ET.SubElement(ET.SubElement(ul, "li"), "a", href=f"./{file_name}")
|
||||||
link.text = job
|
link.text = job
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ class Artifact:
|
|||||||
download_url: str
|
download_url: str
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def public_download_url(self) -> str:
|
def public_download_url(self):
|
||||||
# GitHub API is not available publicly for artifacts, we need to use
|
# GitHub API is not available publicly for artifacts, we need to use
|
||||||
# a third-party proxy to access it...
|
# a third-party proxy to access it...
|
||||||
name = urllib.parse.quote(self.name)
|
name = urllib.parse.quote(self.name)
|
||||||
|
@ -152,7 +152,7 @@ def match_dict(
|
|||||||
# Set to not-None if we find a Keys() operator in the dict keys
|
# Set to not-None if we find a Keys() operator in the dict keys
|
||||||
remaining_keys_wildcard = None
|
remaining_keys_wildcard = None
|
||||||
|
|
||||||
for expected_key, expected_value in expected.items():
|
for (expected_key, expected_value) in expected.items():
|
||||||
if isinstance(expected_key, RemainingKeys):
|
if isinstance(expected_key, RemainingKeys):
|
||||||
remaining_keys_wildcard = (expected_key.key, expected_value)
|
remaining_keys_wildcard = (expected_key.key, expected_value)
|
||||||
else:
|
else:
|
||||||
@ -168,7 +168,7 @@ def match_dict(
|
|||||||
|
|
||||||
if remaining_keys_wildcard:
|
if remaining_keys_wildcard:
|
||||||
(expected_key, expected_value) = remaining_keys_wildcard
|
(expected_key, expected_value) = remaining_keys_wildcard
|
||||||
for key, value in got.items():
|
for (key, value) in got.items():
|
||||||
if not match_string(key, expected_key):
|
if not match_string(key, expected_key):
|
||||||
return False
|
return False
|
||||||
if not match_string(value, expected_value):
|
if not match_string(value, expected_value):
|
||||||
|
@ -9,7 +9,6 @@ from irctest.patma import ANYSTR
|
|||||||
REGISTER_CAP_NAME = "draft/account-registration"
|
REGISTER_CAP_NAME = "draft/account-registration"
|
||||||
|
|
||||||
|
|
||||||
@cases.mark_services
|
|
||||||
@cases.mark_specifications("IRCv3")
|
@cases.mark_specifications("IRCv3")
|
||||||
class RegisterBeforeConnectTestCase(cases.BaseServerTestCase):
|
class RegisterBeforeConnectTestCase(cases.BaseServerTestCase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -34,7 +33,6 @@ class RegisterBeforeConnectTestCase(cases.BaseServerTestCase):
|
|||||||
self.assertMessageMatch(register_response, params=["SUCCESS", ANYSTR, ANYSTR])
|
self.assertMessageMatch(register_response, params=["SUCCESS", ANYSTR, ANYSTR])
|
||||||
|
|
||||||
|
|
||||||
@cases.mark_services
|
|
||||||
@cases.mark_specifications("IRCv3")
|
@cases.mark_specifications("IRCv3")
|
||||||
class RegisterBeforeConnectDisallowedTestCase(cases.BaseServerTestCase):
|
class RegisterBeforeConnectDisallowedTestCase(cases.BaseServerTestCase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -62,7 +60,6 @@ class RegisterBeforeConnectDisallowedTestCase(cases.BaseServerTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@cases.mark_services
|
|
||||||
@cases.mark_specifications("IRCv3")
|
@cases.mark_specifications("IRCv3")
|
||||||
class RegisterEmailVerifiedTestCase(cases.BaseServerTestCase):
|
class RegisterEmailVerifiedTestCase(cases.BaseServerTestCase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -113,7 +110,6 @@ class RegisterEmailVerifiedTestCase(cases.BaseServerTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@cases.mark_services
|
|
||||||
@cases.mark_specifications("IRCv3", "Ergo")
|
@cases.mark_specifications("IRCv3", "Ergo")
|
||||||
class RegisterNoLandGrabsTestCase(cases.BaseServerTestCase):
|
class RegisterNoLandGrabsTestCase(cases.BaseServerTestCase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -7,14 +7,18 @@ and ban exception (`Modern <https://modern.ircdocs.horse/#exception-channel-mode
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from irctest import cases, runner
|
from irctest import cases, runner
|
||||||
from irctest.numerics import ERR_BANNEDFROMCHAN, RPL_BANLIST, RPL_ENDOFBANLIST
|
from irctest.numerics import (
|
||||||
|
ERR_BANNEDFROMCHAN,
|
||||||
|
ERR_CANNOTSENDTOCHAN,
|
||||||
|
RPL_BANLIST,
|
||||||
|
RPL_ENDOFBANLIST,
|
||||||
|
)
|
||||||
from irctest.patma import ANYSTR, StrRe
|
from irctest.patma import ANYSTR, StrRe
|
||||||
|
|
||||||
|
|
||||||
class BanModeTestCase(cases.BaseServerTestCase):
|
class BanModeTestCase(cases.BaseServerTestCase):
|
||||||
@cases.mark_specifications("RFC1459", "RFC2812", "Modern")
|
@cases.mark_specifications("RFC1459", "RFC2812", "Modern")
|
||||||
def testBan(self):
|
def testBanJoin(self):
|
||||||
"""Basic ban operation"""
|
|
||||||
self.connectClient("chanop", name="chanop")
|
self.connectClient("chanop", name="chanop")
|
||||||
self.joinChannel("chanop", "#chan")
|
self.joinChannel("chanop", "#chan")
|
||||||
self.getMessages("chanop")
|
self.getMessages("chanop")
|
||||||
@ -32,6 +36,55 @@ class BanModeTestCase(cases.BaseServerTestCase):
|
|||||||
self.sendLine("bar", "JOIN #chan")
|
self.sendLine("bar", "JOIN #chan")
|
||||||
self.assertMessageMatch(self.getMessage("bar"), command="JOIN")
|
self.assertMessageMatch(self.getMessage("bar"), command="JOIN")
|
||||||
|
|
||||||
|
@cases.mark_specifications("Modern")
|
||||||
|
def testBanPrivmsg(self):
|
||||||
|
"""
|
||||||
|
TODO: this checks the following quote is false:
|
||||||
|
|
||||||
|
"If `<target>` is a channel name and the client is [banned](#ban-channel-mode)
|
||||||
|
and not covered by a [ban exception](#ban-exception-channel-mode), the
|
||||||
|
message will not be delivered and the command will silently fail."
|
||||||
|
-- https://modern.ircdocs.horse/#privmsg-message
|
||||||
|
|
||||||
|
to check https://github.com/ircdocs/modern-irc/pull/201
|
||||||
|
"""
|
||||||
|
self.connectClient("chanop", name="chanop")
|
||||||
|
self.joinChannel("chanop", "#chan")
|
||||||
|
self.getMessages("chanop")
|
||||||
|
|
||||||
|
self.connectClient("Bar", name="bar")
|
||||||
|
self.getMessages("bar")
|
||||||
|
self.sendLine("bar", "JOIN #chan")
|
||||||
|
self.getMessages("bar")
|
||||||
|
self.getMessages("chanop")
|
||||||
|
|
||||||
|
self.sendLine("chanop", "MODE #chan +b bar!*@*")
|
||||||
|
self.assertMessageMatch(self.getMessage("chanop"), command="MODE")
|
||||||
|
self.getMessages("chanop")
|
||||||
|
self.getMessages("bar")
|
||||||
|
|
||||||
|
self.sendLine("bar", "PRIVMSG #chan :hello world")
|
||||||
|
self.assertMessageMatch(
|
||||||
|
self.getMessage("bar"),
|
||||||
|
command=ERR_CANNOTSENDTOCHAN,
|
||||||
|
params=["Bar", "#chan", ANYSTR],
|
||||||
|
)
|
||||||
|
self.assertEqual(self.getMessages("bar"), [])
|
||||||
|
self.assertEqual(self.getMessages("chanop"), [])
|
||||||
|
|
||||||
|
self.sendLine("chanop", "MODE #chan -b bar!*@*")
|
||||||
|
self.assertMessageMatch(self.getMessage("chanop"), command="MODE")
|
||||||
|
self.getMessages("chanop")
|
||||||
|
self.getMessages("bar")
|
||||||
|
|
||||||
|
self.sendLine("bar", "PRIVMSG #chan :hello again")
|
||||||
|
self.assertEqual(self.getMessages("bar"), [])
|
||||||
|
self.assertMessageMatch(
|
||||||
|
self.getMessage("chanop"),
|
||||||
|
command="PRIVMSG",
|
||||||
|
params=["#chan", "hello again"],
|
||||||
|
)
|
||||||
|
|
||||||
@cases.mark_specifications("Modern")
|
@cases.mark_specifications("Modern")
|
||||||
def testBanList(self):
|
def testBanList(self):
|
||||||
"""`RPL_BANLIST <https://modern.ircdocs.horse/#rplbanlist-367>`_"""
|
"""`RPL_BANLIST <https://modern.ircdocs.horse/#rplbanlist-367>`_"""
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
"""
|
|
||||||
Channel "no external messages" mode (`RFC 1459
|
|
||||||
<https://datatracker.ietf.org/doc/html/rfc1459#section-4.2.3.1>`__,
|
|
||||||
`Modern <https://modern.ircdocs.horse/#no-external-messages-mode>`__)
|
|
||||||
"""
|
|
||||||
|
|
||||||
from irctest import cases
|
|
||||||
from irctest.numerics import ERR_CANNOTSENDTOCHAN
|
|
||||||
|
|
||||||
|
|
||||||
class NoExternalMessagesTestCase(cases.BaseServerTestCase):
|
|
||||||
@cases.mark_specifications("RFC1459", "Modern")
|
|
||||||
def testNoExternalMessagesMode(self):
|
|
||||||
# test the +n channel mode
|
|
||||||
self.connectClient("chanop", name="chanop")
|
|
||||||
self.joinChannel("chanop", "#chan")
|
|
||||||
self.sendLine("chanop", "MODE #chan +n")
|
|
||||||
self.getMessages("chanop")
|
|
||||||
|
|
||||||
self.connectClient("baz", name="baz")
|
|
||||||
# this message should be suppressed completely by +n
|
|
||||||
self.sendLine("baz", "PRIVMSG #chan :hi from baz")
|
|
||||||
replies = self.getMessages("baz")
|
|
||||||
reply_cmds = {reply.command for reply in replies}
|
|
||||||
self.assertIn(ERR_CANNOTSENDTOCHAN, reply_cmds)
|
|
||||||
self.assertEqual(self.getMessages("chanop"), [])
|
|
||||||
|
|
||||||
# set the channel to -n: baz should be able to send now
|
|
||||||
self.sendLine("chanop", "MODE #chan -n")
|
|
||||||
replies = self.getMessages("chanop")
|
|
||||||
modeLines = [line for line in replies if line.command == "MODE"]
|
|
||||||
self.assertMessageMatch(modeLines[0], command="MODE", params=["#chan", "-n"])
|
|
||||||
self.sendLine("baz", "PRIVMSG #chan :hi again from baz")
|
|
||||||
self.getMessages("baz")
|
|
||||||
relays = self.getMessages("chanop")
|
|
||||||
self.assertMessageMatch(
|
|
||||||
relays[0], command="PRIVMSG", params=["#chan", "hi again from baz"]
|
|
||||||
)
|
|
@ -32,26 +32,6 @@ class PrivmsgTestCase(cases.BaseServerTestCase):
|
|||||||
# ERR_NOSUCHNICK, ERR_NOSUCHCHANNEL, or ERR_CANNOTSENDTOCHAN
|
# ERR_NOSUCHNICK, ERR_NOSUCHCHANNEL, or ERR_CANNOTSENDTOCHAN
|
||||||
self.assertIn(msg.command, ("401", "403", "404"))
|
self.assertIn(msg.command, ("401", "403", "404"))
|
||||||
|
|
||||||
@cases.mark_specifications("RFC1459", "RFC2812")
|
|
||||||
def testPrivmsgToUser(self):
|
|
||||||
"""<https://tools.ietf.org/html/rfc2812#section-3.3.1>"""
|
|
||||||
self.connectClient("foo")
|
|
||||||
self.connectClient("bar")
|
|
||||||
self.sendLine(1, "PRIVMSG bar :hey there!")
|
|
||||||
self.getMessages(1)
|
|
||||||
pms = [msg for msg in self.getMessages(2) if msg.command == "PRIVMSG"]
|
|
||||||
self.assertEqual(len(pms), 1)
|
|
||||||
self.assertMessageMatch(pms[0], command="PRIVMSG", params=["bar", "hey there!"])
|
|
||||||
|
|
||||||
@cases.mark_specifications("RFC1459", "RFC2812")
|
|
||||||
def testPrivmsgNonexistentUser(self):
|
|
||||||
"""https://tools.ietf.org/html/rfc2812#section-3.3.1"""
|
|
||||||
self.connectClient("foo")
|
|
||||||
self.sendLine(1, "PRIVMSG bar :hey there!")
|
|
||||||
msg = self.getMessage(1)
|
|
||||||
# ERR_NOSUCHNICK
|
|
||||||
self.assertIn(msg.command, ("401"))
|
|
||||||
|
|
||||||
|
|
||||||
class NoticeTestCase(cases.BaseServerTestCase):
|
class NoticeTestCase(cases.BaseServerTestCase):
|
||||||
@cases.mark_specifications("RFC1459", "RFC2812")
|
@cases.mark_specifications("RFC1459", "RFC2812")
|
||||||
@ -100,13 +80,8 @@ class NoticeTestCase(cases.BaseServerTestCase):
|
|||||||
|
|
||||||
class TagsTestCase(cases.BaseServerTestCase):
|
class TagsTestCase(cases.BaseServerTestCase):
|
||||||
@cases.mark_capabilities("message-tags")
|
@cases.mark_capabilities("message-tags")
|
||||||
@cases.xfailIf(
|
@cases.xfailIfSoftware(
|
||||||
lambda self: bool(
|
["UnrealIRCd"], "https://bugs.unrealircd.org/view.php?id=5947"
|
||||||
self.controller.software_name == "UnrealIRCd"
|
|
||||||
and self.controller.software_version == 5
|
|
||||||
),
|
|
||||||
"UnrealIRCd <6.0.7 dropped messages with excessively large tags: "
|
|
||||||
"https://bugs.unrealircd.org/view.php?id=5947",
|
|
||||||
)
|
)
|
||||||
def testLineTooLong(self):
|
def testLineTooLong(self):
|
||||||
self.connectClient("bar", capabilities=["message-tags"], skip_if_cap_nak=True)
|
self.connectClient("bar", capabilities=["message-tags"], skip_if_cap_nak=True)
|
||||||
|
@ -6,8 +6,8 @@ from irctest import cases
|
|||||||
|
|
||||||
|
|
||||||
class MetadataTestCase(cases.BaseServerTestCase):
|
class MetadataTestCase(cases.BaseServerTestCase):
|
||||||
valid_metadata_keys = {"display-name", "avatar"}
|
valid_metadata_keys = {"valid_key1", "valid_key2"}
|
||||||
invalid_metadata_keys = {"indisplay-name", "inavatar"}
|
invalid_metadata_keys = {"invalid_key1", "invalid_key2"}
|
||||||
|
|
||||||
@cases.mark_specifications("IRCv3", deprecated=True)
|
@cases.mark_specifications("IRCv3", deprecated=True)
|
||||||
def testInIsupport(self):
|
def testInIsupport(self):
|
||||||
@ -36,7 +36,7 @@ class MetadataTestCase(cases.BaseServerTestCase):
|
|||||||
def testGetOneUnsetValid(self):
|
def testGetOneUnsetValid(self):
|
||||||
"""<http://ircv3.net/specs/core/metadata-3.2.html#metadata-get>"""
|
"""<http://ircv3.net/specs/core/metadata-3.2.html#metadata-get>"""
|
||||||
self.connectClient("foo")
|
self.connectClient("foo")
|
||||||
self.sendLine(1, "METADATA * GET display-name")
|
self.sendLine(1, "METADATA * GET valid_key1")
|
||||||
m = self.getMessage(1)
|
m = self.getMessage(1)
|
||||||
self.assertMessageMatch(
|
self.assertMessageMatch(
|
||||||
m,
|
m,
|
||||||
@ -52,7 +52,7 @@ class MetadataTestCase(cases.BaseServerTestCase):
|
|||||||
-- <http://ircv3.net/specs/core/metadata-3.2.html#metadata-get>
|
-- <http://ircv3.net/specs/core/metadata-3.2.html#metadata-get>
|
||||||
"""
|
"""
|
||||||
self.connectClient("foo")
|
self.connectClient("foo")
|
||||||
self.sendLine(1, "METADATA * GET display-name avatar")
|
self.sendLine(1, "METADATA * GET valid_key1 valid_key2")
|
||||||
m = self.getMessage(1)
|
m = self.getMessage(1)
|
||||||
self.assertMessageMatch(
|
self.assertMessageMatch(
|
||||||
m,
|
m,
|
||||||
@ -62,10 +62,10 @@ class MetadataTestCase(cases.BaseServerTestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
m.params[1],
|
m.params[1],
|
||||||
"display-name",
|
"valid_key1",
|
||||||
m,
|
m,
|
||||||
fail_msg="Response to “METADATA * GET display-name avatar” "
|
fail_msg="Response to “METADATA * GET valid_key1 valid_key2” "
|
||||||
"did not respond to display-name first: {msg}",
|
"did not respond to valid_key1 first: {msg}",
|
||||||
)
|
)
|
||||||
m = self.getMessage(1)
|
m = self.getMessage(1)
|
||||||
self.assertMessageMatch(
|
self.assertMessageMatch(
|
||||||
@ -76,10 +76,10 @@ class MetadataTestCase(cases.BaseServerTestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
m.params[1],
|
m.params[1],
|
||||||
"avatar",
|
"valid_key2",
|
||||||
m,
|
m,
|
||||||
fail_msg="Response to “METADATA * GET display-name avatar” "
|
fail_msg="Response to “METADATA * GET valid_key1 valid_key2” "
|
||||||
"did not respond to avatar as second response: {msg}",
|
"did not respond to valid_key2 as second response: {msg}",
|
||||||
)
|
)
|
||||||
|
|
||||||
@cases.mark_specifications("IRCv3", deprecated=True)
|
@cases.mark_specifications("IRCv3", deprecated=True)
|
||||||
@ -135,7 +135,7 @@ class MetadataTestCase(cases.BaseServerTestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
m.params[1],
|
m.params[1],
|
||||||
"display-name",
|
"valid_key1",
|
||||||
m,
|
m,
|
||||||
fail_msg="Second param of 761 after setting “{expects}” to "
|
fail_msg="Second param of 761 after setting “{expects}” to "
|
||||||
"“{}” is not “{expects}”: {msg}.",
|
"“{}” is not “{expects}”: {msg}.",
|
||||||
@ -190,7 +190,7 @@ class MetadataTestCase(cases.BaseServerTestCase):
|
|||||||
def testSetGetValid(self):
|
def testSetGetValid(self):
|
||||||
"""<http://ircv3.net/specs/core/metadata-3.2.html>"""
|
"""<http://ircv3.net/specs/core/metadata-3.2.html>"""
|
||||||
self.connectClient("foo")
|
self.connectClient("foo")
|
||||||
self.assertSetGetValue("*", "display-name", "myvalue")
|
self.assertSetGetValue("*", "valid_key1", "myvalue")
|
||||||
|
|
||||||
@cases.mark_specifications("IRCv3", deprecated=True)
|
@cases.mark_specifications("IRCv3", deprecated=True)
|
||||||
def testSetGetZeroCharInValue(self):
|
def testSetGetZeroCharInValue(self):
|
||||||
@ -198,7 +198,7 @@ class MetadataTestCase(cases.BaseServerTestCase):
|
|||||||
-- <http://ircv3.net/specs/core/metadata-3.2.html#metadata-restrictions>
|
-- <http://ircv3.net/specs/core/metadata-3.2.html#metadata-restrictions>
|
||||||
"""
|
"""
|
||||||
self.connectClient("foo")
|
self.connectClient("foo")
|
||||||
self.assertSetGetValue("*", "display-name", "zero->\0<-zero", "zero->\\0<-zero")
|
self.assertSetGetValue("*", "valid_key1", "zero->\0<-zero", "zero->\\0<-zero")
|
||||||
|
|
||||||
@cases.mark_specifications("IRCv3", deprecated=True)
|
@cases.mark_specifications("IRCv3", deprecated=True)
|
||||||
def testSetGetHeartInValue(self):
|
def testSetGetHeartInValue(self):
|
||||||
@ -209,7 +209,7 @@ class MetadataTestCase(cases.BaseServerTestCase):
|
|||||||
self.connectClient("foo")
|
self.connectClient("foo")
|
||||||
self.assertSetGetValue(
|
self.assertSetGetValue(
|
||||||
"*",
|
"*",
|
||||||
"display-name",
|
"valid_key1",
|
||||||
"->{}<-".format(heart),
|
"->{}<-".format(heart),
|
||||||
"zero->{}<-zero".format(heart.encode()),
|
"zero->{}<-zero".format(heart.encode()),
|
||||||
)
|
)
|
||||||
@ -223,7 +223,7 @@ class MetadataTestCase(cases.BaseServerTestCase):
|
|||||||
# Sending directly because it is not valid UTF-8 so Python would
|
# Sending directly because it is not valid UTF-8 so Python would
|
||||||
# not like it
|
# not like it
|
||||||
self.clients[1].conn.sendall(
|
self.clients[1].conn.sendall(
|
||||||
b"METADATA * SET display-name " b":invalid UTF-8 ->\xc3<-\r\n"
|
b"METADATA * SET valid_key1 " b":invalid UTF-8 ->\xc3<-\r\n"
|
||||||
)
|
)
|
||||||
commands = {m.command for m in self.getMessages(1)}
|
commands = {m.command for m in self.getMessages(1)}
|
||||||
self.assertNotIn(
|
self.assertNotIn(
|
||||||
@ -233,7 +233,7 @@ class MetadataTestCase(cases.BaseServerTestCase):
|
|||||||
"UTF-8 was answered with 761 (RPL_KEYVALUE)",
|
"UTF-8 was answered with 761 (RPL_KEYVALUE)",
|
||||||
)
|
)
|
||||||
self.clients[1].conn.sendall(
|
self.clients[1].conn.sendall(
|
||||||
b"METADATA * SET display-name " b":invalid UTF-8: \xc3\r\n"
|
b"METADATA * SET valid_key1 " b":invalid UTF-8: \xc3\r\n"
|
||||||
)
|
)
|
||||||
commands = {m.command for m in self.getMessages(1)}
|
commands = {m.command for m in self.getMessages(1)}
|
||||||
self.assertNotIn(
|
self.assertNotIn(
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
`IRCv3 MONITOR <https://ircv3.net/specs/extensions/monitor>`_
|
`IRCv3 MONITOR <https://ircv3.net/specs/extensions/monitor>`_
|
||||||
and `IRCv3 extended-monitor` <https://ircv3.net/specs/extensions/extended-monitor>`_
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from irctest import cases, runner
|
from irctest import cases, runner
|
||||||
from irctest.client_mock import NoMessageException
|
from irctest.client_mock import NoMessageException
|
||||||
from irctest.numerics import (
|
from irctest.numerics import (
|
||||||
@ -16,7 +13,7 @@ from irctest.numerics import (
|
|||||||
from irctest.patma import ANYSTR, StrRe
|
from irctest.patma import ANYSTR, StrRe
|
||||||
|
|
||||||
|
|
||||||
class _BaseMonitorTestCase(cases.BaseServerTestCase):
|
class MonitorTestCase(cases.BaseServerTestCase):
|
||||||
def check_server_support(self):
|
def check_server_support(self):
|
||||||
if "MONITOR" not in self.server_support:
|
if "MONITOR" not in self.server_support:
|
||||||
raise runner.IsupportTokenNotSupported("MONITOR")
|
raise runner.IsupportTokenNotSupported("MONITOR")
|
||||||
@ -45,8 +42,6 @@ class _BaseMonitorTestCase(cases.BaseServerTestCase):
|
|||||||
extra_format=(nick,),
|
extra_format=(nick,),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class MonitorTestCase(_BaseMonitorTestCase):
|
|
||||||
@cases.mark_specifications("IRCv3")
|
@cases.mark_specifications("IRCv3")
|
||||||
@cases.mark_isupport("MONITOR")
|
@cases.mark_isupport("MONITOR")
|
||||||
def testMonitorOneDisconnected(self):
|
def testMonitorOneDisconnected(self):
|
||||||
@ -300,11 +295,10 @@ class MonitorTestCase(_BaseMonitorTestCase):
|
|||||||
self.sendLine(2, "NICK qux")
|
self.sendLine(2, "NICK qux")
|
||||||
self.getMessages(2)
|
self.getMessages(2)
|
||||||
mononline = self.getMessages(1)[0]
|
mononline = self.getMessages(1)[0]
|
||||||
self.assertMessageMatch(
|
self.assertEqual(mononline.command, RPL_MONONLINE)
|
||||||
mononline,
|
self.assertEqual(len(mononline.params), 2, mononline.params)
|
||||||
command=RPL_MONONLINE,
|
self.assertIn(mononline.params[0], ("bar", "*"))
|
||||||
params=[StrRe(r"(bar|\*)"), StrRe("qux(!.*)?")],
|
self.assertEqual(mononline.params[1].split("!")[0], "qux")
|
||||||
)
|
|
||||||
|
|
||||||
# no numerics for a case change
|
# no numerics for a case change
|
||||||
self.sendLine(2, "NICK QUX")
|
self.sendLine(2, "NICK QUX")
|
||||||
@ -315,246 +309,7 @@ class MonitorTestCase(_BaseMonitorTestCase):
|
|||||||
self.getMessages(2)
|
self.getMessages(2)
|
||||||
monoffline = self.getMessages(1)[0]
|
monoffline = self.getMessages(1)[0]
|
||||||
# should get RPL_MONOFFLINE with the current unfolded nick
|
# should get RPL_MONOFFLINE with the current unfolded nick
|
||||||
self.assertMessageMatch(
|
self.assertEqual(monoffline.command, RPL_MONOFFLINE)
|
||||||
monoffline,
|
self.assertEqual(len(monoffline.params), 2, monoffline.params)
|
||||||
command=RPL_MONOFFLINE,
|
self.assertIn(monoffline.params[0], ("bar", "*"))
|
||||||
params=[StrRe(r"(bar|\*)"), "QUX"],
|
self.assertEqual(monoffline.params[1].split("!")[0], "QUX")
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class _BaseExtendedMonitorTestCase(_BaseMonitorTestCase):
|
|
||||||
def _setupExtendedMonitor(self, monitor_before_connect, watcher_caps, watched_caps):
|
|
||||||
"""Tests https://ircv3.net/specs/extensions/extended-monitor.html"""
|
|
||||||
self.connectClient(
|
|
||||||
"foo",
|
|
||||||
capabilities=["draft/extended-monitor", *watcher_caps],
|
|
||||||
skip_if_cap_nak=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
if monitor_before_connect:
|
|
||||||
self.sendLine(1, "MONITOR + bar")
|
|
||||||
self.getMessages(1)
|
|
||||||
self.connectClient("bar", capabilities=watched_caps, skip_if_cap_nak=True)
|
|
||||||
self.getMessages(2)
|
|
||||||
else:
|
|
||||||
self.connectClient("bar", capabilities=watched_caps, skip_if_cap_nak=True)
|
|
||||||
self.getMessages(2)
|
|
||||||
self.sendLine(1, "MONITOR + bar")
|
|
||||||
|
|
||||||
self.assertMononline(1, "bar")
|
|
||||||
self.assertEqual(self.getMessages(1), [])
|
|
||||||
|
|
||||||
|
|
||||||
class ExtendedMonitorTestCase(_BaseExtendedMonitorTestCase):
|
|
||||||
@cases.mark_specifications("IRCv3")
|
|
||||||
@cases.mark_capabilities("extended-monitor", "away-notify")
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"monitor_before_connect,cap",
|
|
||||||
[
|
|
||||||
pytest.param(
|
|
||||||
monitor_before_connect,
|
|
||||||
cap,
|
|
||||||
id=("monitor_before_connect" if monitor_before_connect else "")
|
|
||||||
+ "-"
|
|
||||||
+ ("with-cap" if cap else ""),
|
|
||||||
)
|
|
||||||
for monitor_before_connect in [True, False]
|
|
||||||
for cap in [True, False]
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def testExtendedMonitorAway(self, monitor_before_connect, cap):
|
|
||||||
"""Tests https://ircv3.net/specs/extensions/extended-monitor.html
|
|
||||||
with https://ircv3.net/specs/extensions/away-notify
|
|
||||||
"""
|
|
||||||
if cap:
|
|
||||||
self._setupExtendedMonitor(
|
|
||||||
monitor_before_connect, ["away-notify"], ["away-notify"]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self._setupExtendedMonitor(monitor_before_connect, ["away-notify"], [])
|
|
||||||
|
|
||||||
self.sendLine(2, "AWAY :afk")
|
|
||||||
self.getMessages(2)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(1), nick="bar", command="AWAY", params=["afk"]
|
|
||||||
)
|
|
||||||
self.assertEqual(self.getMessages(1), [], "watcher got unexpected messages")
|
|
||||||
|
|
||||||
self.sendLine(2, "AWAY")
|
|
||||||
self.getMessages(2)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(1), nick="bar", command="AWAY", params=[]
|
|
||||||
)
|
|
||||||
self.assertEqual(self.getMessages(1), [], "watcher got unexpected messages")
|
|
||||||
|
|
||||||
@cases.mark_specifications("IRCv3")
|
|
||||||
@cases.mark_capabilities("extended-monitor", "away-notify")
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"monitor_before_connect,cap",
|
|
||||||
[
|
|
||||||
pytest.param(
|
|
||||||
monitor_before_connect,
|
|
||||||
cap,
|
|
||||||
id=("monitor_before_connect" if monitor_before_connect else "")
|
|
||||||
+ "-"
|
|
||||||
+ ("with-cap" if cap else ""),
|
|
||||||
)
|
|
||||||
for monitor_before_connect in [True, False]
|
|
||||||
for cap in [True, False]
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def testExtendedMonitorAwayNoCap(self, monitor_before_connect, cap):
|
|
||||||
"""Tests https://ircv3.net/specs/extensions/extended-monitor.html
|
|
||||||
does nothing when ``away-notify`` is not enabled by the watcher
|
|
||||||
"""
|
|
||||||
if cap:
|
|
||||||
self._setupExtendedMonitor(monitor_before_connect, [], ["away-notify"])
|
|
||||||
else:
|
|
||||||
self._setupExtendedMonitor(monitor_before_connect, [], [])
|
|
||||||
|
|
||||||
self.sendLine(2, "AWAY :afk")
|
|
||||||
self.getMessages(2)
|
|
||||||
self.assertEqual(self.getMessages(1), [], "watcher got unexpected messages")
|
|
||||||
|
|
||||||
self.sendLine(2, "AWAY")
|
|
||||||
self.getMessages(2)
|
|
||||||
self.assertEqual(self.getMessages(1), [], "watcher got unexpected messages")
|
|
||||||
|
|
||||||
@cases.mark_specifications("IRCv3")
|
|
||||||
@cases.mark_capabilities("extended-monitor", "setname")
|
|
||||||
@pytest.mark.parametrize("monitor_before_connect", [True, False])
|
|
||||||
def testExtendedMonitorSetName(self, monitor_before_connect):
|
|
||||||
"""Tests https://ircv3.net/specs/extensions/extended-monitor.html
|
|
||||||
with https://ircv3.net/specs/extensions/setname
|
|
||||||
"""
|
|
||||||
self._setupExtendedMonitor(monitor_before_connect, ["setname"], ["setname"])
|
|
||||||
|
|
||||||
self.sendLine(2, "SETNAME :new name")
|
|
||||||
self.getMessages(2)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(1), nick="bar", command="SETNAME", params=["new name"]
|
|
||||||
)
|
|
||||||
self.assertEqual(self.getMessages(1), [], "watcher got unexpected messages")
|
|
||||||
|
|
||||||
@cases.mark_specifications("IRCv3")
|
|
||||||
@cases.mark_capabilities("extended-monitor", "setname")
|
|
||||||
@pytest.mark.parametrize("monitor_before_connect", [True, False])
|
|
||||||
def testExtendedMonitorSetNameNoCap(self, monitor_before_connect):
|
|
||||||
"""Tests https://ircv3.net/specs/extensions/extended-monitor.html
|
|
||||||
does nothing when ``setname`` is not enabled by the watcher
|
|
||||||
"""
|
|
||||||
self._setupExtendedMonitor(monitor_before_connect, [], ["setname"])
|
|
||||||
|
|
||||||
self.sendLine(2, "SETNAME :new name")
|
|
||||||
self.getMessages(2)
|
|
||||||
self.assertEqual(self.getMessages(1), [], "watcher got unexpected messages")
|
|
||||||
|
|
||||||
|
|
||||||
@cases.mark_services
|
|
||||||
class AuthenticatedExtendedMonitorTestCase(_BaseExtendedMonitorTestCase):
|
|
||||||
@cases.mark_specifications("IRCv3")
|
|
||||||
@cases.mark_capabilities("extended-monitor", "account-notify")
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"monitor_before_connect,cap",
|
|
||||||
[
|
|
||||||
pytest.param(
|
|
||||||
monitor_before_connect,
|
|
||||||
cap,
|
|
||||||
id=("monitor_before_connect" if monitor_before_connect else "")
|
|
||||||
+ "-"
|
|
||||||
+ ("with-cap" if cap else ""),
|
|
||||||
)
|
|
||||||
for monitor_before_connect in [True, False]
|
|
||||||
for cap in [True, False]
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def testExtendedMonitorAccountNotify(self, monitor_before_connect, cap):
|
|
||||||
"""Tests https://ircv3.net/specs/extensions/extended-monitor.html
|
|
||||||
does nothing when ``account-notify`` is not enabled by the watcher
|
|
||||||
"""
|
|
||||||
self.controller.registerUser(self, "jilles", "sesame")
|
|
||||||
|
|
||||||
if cap:
|
|
||||||
self._setupExtendedMonitor(
|
|
||||||
monitor_before_connect,
|
|
||||||
["account-notify"],
|
|
||||||
["account-notify", "sasl", "cap-notify"],
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self._setupExtendedMonitor(
|
|
||||||
monitor_before_connect, ["account-notify"], ["sasl", "cap-notify"]
|
|
||||||
)
|
|
||||||
|
|
||||||
self.sendLine(2, "AUTHENTICATE PLAIN")
|
|
||||||
m = self.getRegistrationMessage(2)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
m,
|
|
||||||
command="AUTHENTICATE",
|
|
||||||
params=["+"],
|
|
||||||
fail_msg="Sent “AUTHENTICATE PLAIN”, server should have "
|
|
||||||
"replied with “AUTHENTICATE +”, but instead sent: {msg}",
|
|
||||||
)
|
|
||||||
self.sendLine(2, "AUTHENTICATE amlsbGVzAGppbGxlcwBzZXNhbWU=")
|
|
||||||
m = self.getRegistrationMessage(2)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
m,
|
|
||||||
command="900",
|
|
||||||
fail_msg="Did not send 900 after correct SASL authentication.",
|
|
||||||
)
|
|
||||||
self.getMessages(2)
|
|
||||||
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(1), nick="bar", command="ACCOUNT", params=["jilles"]
|
|
||||||
)
|
|
||||||
self.assertEqual(self.getMessages(1), [], "watcher got unexpected messages")
|
|
||||||
|
|
||||||
@cases.mark_specifications("IRCv3")
|
|
||||||
@cases.mark_capabilities("extended-monitor", "account-notify")
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"monitor_before_connect,cap",
|
|
||||||
[
|
|
||||||
pytest.param(
|
|
||||||
monitor_before_connect,
|
|
||||||
cap,
|
|
||||||
id=("monitor_before_connect" if monitor_before_connect else "")
|
|
||||||
+ "-"
|
|
||||||
+ ("with-cap" if cap else ""),
|
|
||||||
)
|
|
||||||
for monitor_before_connect in [True, False]
|
|
||||||
for cap in [True, False]
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def testExtendedMonitorAccountNotifyNoCap(self, monitor_before_connect, cap):
|
|
||||||
"""Tests https://ircv3.net/specs/extensions/extended-monitor.html
|
|
||||||
does nothing when ``account-notify`` is not enabled by the watcher
|
|
||||||
"""
|
|
||||||
self.controller.registerUser(self, "jilles", "sesame")
|
|
||||||
|
|
||||||
if cap:
|
|
||||||
self._setupExtendedMonitor(
|
|
||||||
monitor_before_connect, [], ["account-notify", "sasl", "cap-notify"]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self._setupExtendedMonitor(
|
|
||||||
monitor_before_connect, [], ["sasl", "cap-notify"]
|
|
||||||
)
|
|
||||||
|
|
||||||
self.sendLine(2, "AUTHENTICATE PLAIN")
|
|
||||||
m = self.getRegistrationMessage(2)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
m,
|
|
||||||
command="AUTHENTICATE",
|
|
||||||
params=["+"],
|
|
||||||
fail_msg="Sent “AUTHENTICATE PLAIN”, server should have "
|
|
||||||
"replied with “AUTHENTICATE +”, but instead sent: {msg}",
|
|
||||||
)
|
|
||||||
self.sendLine(2, "AUTHENTICATE amlsbGVzAGppbGxlcwBzZXNhbWU=")
|
|
||||||
m = self.getRegistrationMessage(2)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
m,
|
|
||||||
command="900",
|
|
||||||
fail_msg="Did not send 900 after correct SASL authentication.",
|
|
||||||
)
|
|
||||||
self.getMessages(2)
|
|
||||||
|
|
||||||
self.assertEqual(self.getMessages(1), [], "watcher got unexpected messages")
|
|
||||||
|
@ -1,502 +0,0 @@
|
|||||||
"""
|
|
||||||
`IRCv3 draft message redaction <https://github.com/progval/ircv3-specifications/blob/redaction/extensions/message-redaction.md>`_
|
|
||||||
"""
|
|
||||||
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from irctest import cases
|
|
||||||
from irctest.patma import ANYDICT, ANYSTR, StrRe
|
|
||||||
|
|
||||||
CAPABILITIES = [
|
|
||||||
"message-tags",
|
|
||||||
"echo-message",
|
|
||||||
"batch",
|
|
||||||
"server-time",
|
|
||||||
"labeled-response",
|
|
||||||
"draft/message-redaction",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
@cases.mark_specifications("IRCv3")
|
|
||||||
@cases.mark_capabilities(*CAPABILITIES)
|
|
||||||
class ChannelRedactTestCase(cases.BaseServerTestCase):
|
|
||||||
def _setupRedactTest(self, redacteeId, redacteeNick, chathistory=False):
|
|
||||||
capabilities = list(CAPABILITIES)
|
|
||||||
if chathistory:
|
|
||||||
capabilities.extend(["batch", "draft/chathistory"])
|
|
||||||
self.connectClient("chanop", capabilities=capabilities, skip_if_cap_nak=True)
|
|
||||||
self.sendLine(1, "JOIN #chan")
|
|
||||||
self.connectClient("user", capabilities=capabilities, skip_if_cap_nak=True)
|
|
||||||
self.sendLine(2, "JOIN #chan")
|
|
||||||
self.getMessages(2) # synchronize
|
|
||||||
self.getMessages(1)
|
|
||||||
|
|
||||||
self.sendLine(redacteeId, "@label=1234 PRIVMSG #chan :hello there")
|
|
||||||
echo = self.getMessage(redacteeId)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
echo,
|
|
||||||
tags={"label": "1234", "msgid": StrRe("[^ ]+"), **ANYDICT},
|
|
||||||
prefix=StrRe(redacteeNick + "!.*"),
|
|
||||||
command="PRIVMSG",
|
|
||||||
params=["#chan", "hello there"],
|
|
||||||
)
|
|
||||||
msgid = echo.tags["msgid"]
|
|
||||||
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(3 - redacteeId),
|
|
||||||
tags={"msgid": msgid, **ANYDICT},
|
|
||||||
prefix=StrRe(redacteeNick + "!.*"),
|
|
||||||
command="PRIVMSG",
|
|
||||||
params=["#chan", "hello there"],
|
|
||||||
)
|
|
||||||
|
|
||||||
return msgid
|
|
||||||
|
|
||||||
def testRelayOpSelfRedact(self):
|
|
||||||
"""Channel op writes a message and redacts it themselves."""
|
|
||||||
msgid = self._setupRedactTest(redacteeId=1, redacteeNick="chanop")
|
|
||||||
|
|
||||||
self.sendLine(1, f"REDACT #chan {msgid} :oops")
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(1),
|
|
||||||
prefix=StrRe("chanop!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["#chan", msgid, "oops"],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(2),
|
|
||||||
prefix=StrRe("chanop!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["#chan", msgid, "oops"],
|
|
||||||
)
|
|
||||||
|
|
||||||
def testRelayOpRedact(self):
|
|
||||||
"""User writes a message and channel op redacts it."""
|
|
||||||
msgid = self._setupRedactTest(
|
|
||||||
redacteeId=2,
|
|
||||||
redacteeNick="user",
|
|
||||||
)
|
|
||||||
|
|
||||||
self.sendLine(1, f"REDACT #chan {msgid} :spam")
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(1),
|
|
||||||
prefix=StrRe("chanop!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["#chan", msgid, "spam"],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(2),
|
|
||||||
prefix=StrRe("chanop!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["#chan", msgid, "spam"],
|
|
||||||
)
|
|
||||||
|
|
||||||
def testRelayUserSelfRedact(self):
|
|
||||||
"""User writes a message and redacts it themselves.
|
|
||||||
|
|
||||||
Servers may either accept or reject this."""
|
|
||||||
msgid = self._setupRedactTest(redacteeId=2, redacteeNick="user")
|
|
||||||
|
|
||||||
self.sendLine(2, f"REDACT #chan {msgid} :oops")
|
|
||||||
|
|
||||||
msg = self.getMessage(2)
|
|
||||||
if msg.command == "REDACT":
|
|
||||||
self.assertMessageMatch(
|
|
||||||
msg,
|
|
||||||
prefix=StrRe("user!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["#chan", msgid, "oops"],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(1),
|
|
||||||
prefix=StrRe("user!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["#chan", msgid, "oops"],
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.assertMessageMatch(
|
|
||||||
msg,
|
|
||||||
command="FAIL",
|
|
||||||
params=["REDACT", "REDACT_FORBIDDEN", "#chan", msgid, ANYSTR],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(self.getMessages(1), [])
|
|
||||||
|
|
||||||
def testRejectRedactOtherUser(self):
|
|
||||||
"""Channel op writes a message and a user attempts to redact it."""
|
|
||||||
msgid = self._setupRedactTest(redacteeId=1, redacteeNick="chanop")
|
|
||||||
|
|
||||||
self.sendLine(2, f"REDACT #chan {msgid} :oops")
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(2),
|
|
||||||
command="FAIL",
|
|
||||||
params=["REDACT", "REDACT_FORBIDDEN", "#chan", msgid, ANYSTR],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(self.getMessages(1), [])
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"chathistory_requester",
|
|
||||||
[
|
|
||||||
pytest.param(1, id="chathistory-to-chanop"),
|
|
||||||
pytest.param(2, id="chathistory-to-user"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def testOpSelfRedactChathistory(self, chathistory_requester):
|
|
||||||
"""Channel op writes a message and redacts it themselves; both the op
|
|
||||||
and a regular user check the chathistory afterward.
|
|
||||||
|
|
||||||
https://github.com/progval/ircv3-specifications/blob/redaction/extensions/message-redaction.md#chat-history
|
|
||||||
"""
|
|
||||||
msgid = self._setupRedactTest(
|
|
||||||
redacteeId=1, redacteeNick="chanop", chathistory=True
|
|
||||||
)
|
|
||||||
|
|
||||||
self.sendLine(1, f"REDACT #chan {msgid} :oops")
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(1),
|
|
||||||
prefix=StrRe("chanop!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["#chan", msgid, "oops"],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.getMessages(1)
|
|
||||||
self.getMessages(2)
|
|
||||||
|
|
||||||
self.sendLine(chathistory_requester, "CHATHISTORY LATEST #chan * 10")
|
|
||||||
|
|
||||||
(start_msg, *msgs, end_msg) = self.getMessages(chathistory_requester)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
start_msg,
|
|
||||||
command="BATCH",
|
|
||||||
params=[StrRe(r"\+.+"), "chathistory", "#chan"],
|
|
||||||
)
|
|
||||||
batch_tag = start_msg.params[0][1:]
|
|
||||||
|
|
||||||
# remove Ergo's event-playback fallback
|
|
||||||
msgs = [msg for msg in msgs if not msg.prefix.startswith("HistServ!")]
|
|
||||||
|
|
||||||
self.assertMessageMatch(end_msg, command="BATCH", params=["-" + batch_tag])
|
|
||||||
|
|
||||||
if len(msgs) == 0:
|
|
||||||
pass # Server removed the message entirely
|
|
||||||
elif len(msgs) == 1:
|
|
||||||
# Server replaced with the REDACT
|
|
||||||
self.assertMessageMatch(
|
|
||||||
msgs[0],
|
|
||||||
prefix=StrRe("sender!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["#chan", msgid, "oops"],
|
|
||||||
)
|
|
||||||
elif len(msgs) == 2:
|
|
||||||
# Server appended the REDACT
|
|
||||||
self.assertMessageMatch(
|
|
||||||
msgs[0],
|
|
||||||
tags={"msgid": msgid, **ANYDICT},
|
|
||||||
command="PRIVMSG",
|
|
||||||
params=["#chan", msgid, "hello there"],
|
|
||||||
)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
msgs[1],
|
|
||||||
prefix=StrRe("sender!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["#chan", msgid, "oops"],
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.assertTrue(False, fail_msg=f"Unexpectedly many messages: {msgs}")
|
|
||||||
|
|
||||||
def testOpRedactNonExistant(self):
|
|
||||||
"""Channel op writes a message and redacts a random non-existant id."""
|
|
||||||
self._setupRedactTest(redacteeId=1, redacteeNick="chanop")
|
|
||||||
|
|
||||||
nonexistent_msgid = str(uuid.uuid4())
|
|
||||||
|
|
||||||
self.sendLine(1, f"REDACT #chan {nonexistent_msgid} :oops")
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(1),
|
|
||||||
command="FAIL",
|
|
||||||
params=["REDACT", "UNKNOWN_MSGID", "#chan", nonexistent_msgid, ANYSTR],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(self.getMessages(2), [])
|
|
||||||
|
|
||||||
def testOpRedactWrongChan(self):
|
|
||||||
"""Channel op writes a message and redacts it, but uses the wrong channel
|
|
||||||
as target."""
|
|
||||||
msgid = self._setupRedactTest(redacteeId=1, redacteeNick="chanop")
|
|
||||||
|
|
||||||
self.sendLine(1, "JOIN #otherChan")
|
|
||||||
self.getMessages(1)
|
|
||||||
|
|
||||||
self.sendLine(1, f"REDACT #otherChan {msgid} :oops")
|
|
||||||
|
|
||||||
msg = self.getMessage(1)
|
|
||||||
|
|
||||||
self.assertMessageMatch(
|
|
||||||
msg,
|
|
||||||
command="FAIL",
|
|
||||||
)
|
|
||||||
if msg.params[1] == "UNKNOWN_MSGID":
|
|
||||||
self.assertMessageMatch(
|
|
||||||
msg,
|
|
||||||
command="FAIL",
|
|
||||||
params=["REDACT", "UNKNOWN_MSGID", "#otherChan", msgid, ANYSTR],
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.assertMessageMatch(
|
|
||||||
msg,
|
|
||||||
command="FAIL",
|
|
||||||
params=["REDACT", "REDACT_FORBIDDEN", "#otherChan", ANYSTR],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(self.getMessages(2), [])
|
|
||||||
|
|
||||||
|
|
||||||
@cases.mark_specifications("IRCv3")
|
|
||||||
@cases.mark_capabilities(*CAPABILITIES)
|
|
||||||
@cases.mark_services
|
|
||||||
@pytest.mark.private_chathistory
|
|
||||||
class PmRedactTestCase(cases.BaseServerTestCase):
|
|
||||||
"""Tests REDACT command in private messages between authenticated accounts"""
|
|
||||||
|
|
||||||
def _setupRedactTest(self, chathistory=False):
|
|
||||||
capabilities = [*CAPABILITIES, "sasl"]
|
|
||||||
if chathistory:
|
|
||||||
capabilities.extend(["batch", "draft/chathistory"])
|
|
||||||
self.controller.registerUser(self, "sender", "senderpass")
|
|
||||||
self.controller.registerUser(self, "recipient", "recipientpass")
|
|
||||||
self.connectClient(
|
|
||||||
"sender",
|
|
||||||
password="senderpass",
|
|
||||||
capabilities=capabilities,
|
|
||||||
skip_if_cap_nak=True,
|
|
||||||
)
|
|
||||||
self.connectClient(
|
|
||||||
"recipient",
|
|
||||||
password="recipientpass",
|
|
||||||
capabilities=capabilities,
|
|
||||||
skip_if_cap_nak=True,
|
|
||||||
)
|
|
||||||
self.getMessages(2) # synchronize
|
|
||||||
self.getMessages(1)
|
|
||||||
|
|
||||||
self.sendLine(1, "@label=1234 PRIVMSG recipient :hello there")
|
|
||||||
echo = self.getMessage(1)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
echo,
|
|
||||||
tags={"label": "1234", "msgid": StrRe("[^ ]+"), **ANYDICT},
|
|
||||||
prefix=StrRe("sender!.*"),
|
|
||||||
command="PRIVMSG",
|
|
||||||
params=["recipient", "hello there"],
|
|
||||||
)
|
|
||||||
msgid = echo.tags["msgid"]
|
|
||||||
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(2),
|
|
||||||
tags={"msgid": msgid, **ANYDICT},
|
|
||||||
prefix=StrRe("sender!.*"),
|
|
||||||
command="PRIVMSG",
|
|
||||||
params=["recipient", "hello there"],
|
|
||||||
)
|
|
||||||
|
|
||||||
return msgid
|
|
||||||
|
|
||||||
def testRelaySenderRedact(self):
|
|
||||||
"""Someone writes a message in private and redacts it themselves."""
|
|
||||||
msgid = self._setupRedactTest()
|
|
||||||
|
|
||||||
self.sendLine(1, f"REDACT recipient {msgid} :oops")
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(1),
|
|
||||||
prefix=StrRe("sender!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["recipient", msgid, "oops"],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(2),
|
|
||||||
prefix=StrRe("sender!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["recipient", msgid, "oops"],
|
|
||||||
)
|
|
||||||
|
|
||||||
def testRelayRecipientRedact(self):
|
|
||||||
"""Someone writes a message in private and their recipient redacts it.
|
|
||||||
|
|
||||||
Servers may either accept or reject this."""
|
|
||||||
msgid = self._setupRedactTest()
|
|
||||||
|
|
||||||
self.sendLine(2, f"REDACT sender {msgid} :oops")
|
|
||||||
|
|
||||||
msg = self.getMessage(2)
|
|
||||||
if msg.command == "REDACT":
|
|
||||||
self.assertMessageMatch(
|
|
||||||
msg,
|
|
||||||
prefix=StrRe("recipient!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["sender", msgid, "oops"],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(1),
|
|
||||||
prefix=StrRe("user!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["sender", msgid, "oops"],
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.assertMessageMatch(
|
|
||||||
msg,
|
|
||||||
command="FAIL",
|
|
||||||
params=[
|
|
||||||
"REDACT",
|
|
||||||
StrRe("(REDACT_FORBIDDEN|UNKNOWN_MSGID)"),
|
|
||||||
"sender",
|
|
||||||
msgid,
|
|
||||||
ANYSTR,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(self.getMessages(1), [])
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("nick", ["sender", "recipient"])
|
|
||||||
def testRejectRedactOtherUser(self, nick):
|
|
||||||
"""Someone writes a message in private to someone else and an unrelated person
|
|
||||||
attempts to redact it."""
|
|
||||||
msgid = self._setupRedactTest()
|
|
||||||
|
|
||||||
self.controller.registerUser(self, "censor", "censorpass")
|
|
||||||
self.connectClient(
|
|
||||||
"censor",
|
|
||||||
password="censorpass",
|
|
||||||
capabilities=[*CAPABILITIES, "sasl"],
|
|
||||||
skip_if_cap_nak=True,
|
|
||||||
)
|
|
||||||
self.getMessages(3) # synchronize
|
|
||||||
|
|
||||||
self.sendLine(3, f"REDACT {nick} {msgid} :oops")
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(3),
|
|
||||||
command="FAIL",
|
|
||||||
params=[
|
|
||||||
"REDACT",
|
|
||||||
StrRe("(REDACT_FORBIDDEN|UNKNOWN_MSGID)"),
|
|
||||||
nick,
|
|
||||||
msgid,
|
|
||||||
ANYSTR,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(self.getMessages(1), [])
|
|
||||||
self.assertEqual(self.getMessages(2), [])
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"chathistory_requester",
|
|
||||||
[
|
|
||||||
pytest.param(1, id="chathistory-to-sender"),
|
|
||||||
pytest.param(2, id="chathistory-to-recipient"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
@pytest.mark.private_chathistory
|
|
||||||
def testSenderRedactChathistory(self, chathistory_requester):
|
|
||||||
"""Channel op writes a message and redacts it themselves; both the op
|
|
||||||
and a regular user check the chathistory afterward.
|
|
||||||
|
|
||||||
https://github.com/progval/ircv3-specifications/blob/redaction/extensions/message-redaction.md#chat-history
|
|
||||||
"""
|
|
||||||
msgid = self._setupRedactTest(chathistory=True)
|
|
||||||
|
|
||||||
self.sendLine(1, f"REDACT recipient {msgid} :oops")
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(1),
|
|
||||||
prefix=StrRe("sender!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["recipient", msgid, "oops"],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.getMessages(1)
|
|
||||||
self.getMessages(2)
|
|
||||||
|
|
||||||
if chathistory_requester == 1:
|
|
||||||
others_nick = "recipient"
|
|
||||||
else:
|
|
||||||
others_nick = "sender"
|
|
||||||
|
|
||||||
self.sendLine(chathistory_requester, f"CHATHISTORY LATEST {others_nick} * 10")
|
|
||||||
|
|
||||||
(start_msg, *msgs, end_msg) = self.getMessages(chathistory_requester)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
start_msg,
|
|
||||||
command="BATCH",
|
|
||||||
params=[StrRe(r"\+.+"), "chathistory", others_nick],
|
|
||||||
)
|
|
||||||
batch_tag = start_msg.params[0][1:]
|
|
||||||
|
|
||||||
# remove Ergo's event-playback fallback
|
|
||||||
msgs = [msg for msg in msgs if not msg.prefix.startswith("HistServ!")]
|
|
||||||
|
|
||||||
self.assertMessageMatch(end_msg, command="BATCH", params=["-" + batch_tag])
|
|
||||||
|
|
||||||
if len(msgs) == 0:
|
|
||||||
pass # Server removed the message entirely
|
|
||||||
elif len(msgs) == 1:
|
|
||||||
# Server replaced with the REDACT
|
|
||||||
self.assertMessageMatch(
|
|
||||||
msgs[0],
|
|
||||||
prefix=StrRe("sender!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["recipient", msgid, "oops"],
|
|
||||||
)
|
|
||||||
elif len(msgs) == 2:
|
|
||||||
# Server appended the REDACT
|
|
||||||
self.assertMessageMatch(
|
|
||||||
msgs[0],
|
|
||||||
tags={"msgid": msgid, **ANYDICT},
|
|
||||||
command="PRIVMSG",
|
|
||||||
params=["recipient", msgid, "hello there"],
|
|
||||||
)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
msgs[1],
|
|
||||||
prefix=StrRe("sender!.*"),
|
|
||||||
command="REDACT",
|
|
||||||
params=["recipient", msgid, "oops"],
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.assertTrue(False, fail_msg=f"Unexpectedly many messages: {msgs}")
|
|
||||||
|
|
||||||
def testRedactNonExistant(self):
|
|
||||||
"""Someone writes a message in private to someone else and redacts a random
|
|
||||||
non-existant id."""
|
|
||||||
self._setupRedactTest()
|
|
||||||
|
|
||||||
nonexistent_msgid = str(uuid.uuid4())
|
|
||||||
|
|
||||||
self.sendLine(1, f"REDACT recipient {nonexistent_msgid} :oops")
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(1),
|
|
||||||
command="FAIL",
|
|
||||||
params=["REDACT", "UNKNOWN_MSGID", "recipient", nonexistent_msgid, ANYSTR],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(self.getMessages(2), [])
|
|
||||||
|
|
||||||
def testOpRedactWrongChan(self):
|
|
||||||
"""Channel op writes a message and redacts it, but uses the wrong channel
|
|
||||||
as target."""
|
|
||||||
msgid = self._setupRedactTest()
|
|
||||||
|
|
||||||
self.sendLine(1, "JOIN #otherChan")
|
|
||||||
self.getMessages(1)
|
|
||||||
|
|
||||||
self.sendLine(1, f"REDACT #otherChan {msgid} :oops")
|
|
||||||
self.assertMessageMatch(
|
|
||||||
self.getMessage(1),
|
|
||||||
command="FAIL",
|
|
||||||
params=["REDACT", "UNKNOWN_MSGID", "#otherChan", msgid, ANYSTR],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(self.getMessages(2), [])
|
|
@ -1,21 +1,36 @@
|
|||||||
"""
|
"""
|
||||||
`Ergo <https://ergo.chat/>`_-specific tests of non-Unicode filtering
|
`Ergo <https://ergo.chat/>`_-specific tests of non-Unicode filtering
|
||||||
|
|
||||||
|
TODO: turn this into a test of `IRCv3 UTF8ONLY
|
||||||
<https://ircv3.net/specs/extensions/utf8-only>`_
|
<https://ircv3.net/specs/extensions/utf8-only>`_
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from irctest import cases, runner
|
from irctest import cases
|
||||||
from irctest.patma import ANYSTR
|
from irctest.patma import ANYSTR
|
||||||
|
|
||||||
|
|
||||||
class Utf8TestCase(cases.BaseServerTestCase):
|
class Utf8TestCase(cases.BaseServerTestCase):
|
||||||
@cases.mark_specifications("Ergo")
|
@cases.mark_specifications("Ergo")
|
||||||
def testNonUtf8Filtering(self):
|
def testUtf8Validation(self):
|
||||||
self.connectClient(
|
self.connectClient(
|
||||||
"bar",
|
"bar",
|
||||||
capabilities=["batch", "echo-message", "labeled-response"],
|
capabilities=["batch", "echo-message", "labeled-response"],
|
||||||
)
|
)
|
||||||
self.joinChannel(1, "#qux")
|
self.joinChannel(1, "#qux")
|
||||||
|
self.sendLine(1, "PRIVMSG #qux hi")
|
||||||
|
ms = self.getMessages(1)
|
||||||
|
self.assertMessageMatch(
|
||||||
|
[m for m in ms if m.command == "PRIVMSG"][0], params=["#qux", "hi"]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.sendLine(1, b"PRIVMSG #qux hi\xaa")
|
||||||
|
self.assertMessageMatch(
|
||||||
|
self.getMessage(1),
|
||||||
|
command="FAIL",
|
||||||
|
params=["PRIVMSG", "INVALID_UTF8", ANYSTR],
|
||||||
|
tags={},
|
||||||
|
)
|
||||||
|
|
||||||
self.sendLine(1, b"@label=xyz PRIVMSG #qux hi\xaa")
|
self.sendLine(1, b"@label=xyz PRIVMSG #qux hi\xaa")
|
||||||
self.assertMessageMatch(
|
self.assertMessageMatch(
|
||||||
self.getMessage(1),
|
self.getMessage(1),
|
||||||
@ -23,26 +38,3 @@ class Utf8TestCase(cases.BaseServerTestCase):
|
|||||||
params=["PRIVMSG", "INVALID_UTF8", ANYSTR],
|
params=["PRIVMSG", "INVALID_UTF8", ANYSTR],
|
||||||
tags={"label": "xyz"},
|
tags={"label": "xyz"},
|
||||||
)
|
)
|
||||||
|
|
||||||
@cases.mark_isupport("UTF8ONLY")
|
|
||||||
def testUtf8Validation(self):
|
|
||||||
self.connectClient("foo")
|
|
||||||
self.connectClient("bar")
|
|
||||||
|
|
||||||
if "UTF8ONLY" not in self.server_support:
|
|
||||||
raise runner.IsupportTokenNotSupported("UTF8ONLY")
|
|
||||||
|
|
||||||
self.sendLine(1, "PRIVMSG bar hi")
|
|
||||||
self.getMessages(1) # synchronize
|
|
||||||
ms = self.getMessages(2)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
[m for m in ms if m.command == "PRIVMSG"][0], params=["bar", "hi"]
|
|
||||||
)
|
|
||||||
|
|
||||||
self.sendLine(1, b"PRIVMSG bar hi\xaa")
|
|
||||||
|
|
||||||
m = self.getMessage(1)
|
|
||||||
assert m.command in ("FAIL", "WARN", "ERROR")
|
|
||||||
|
|
||||||
if m.command in ("FAIL", "WARN"):
|
|
||||||
self.assertMessageMatch(m, params=["PRIVMSG", "INVALID_UTF8", ANYSTR])
|
|
||||||
|
@ -99,12 +99,6 @@ class _WhoisTestMixin(cases.BaseServerTestCase):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
elif m.command == RPL_WHOISSPECIAL:
|
elif m.command == RPL_WHOISSPECIAL:
|
||||||
services_controller = self.controller.services_controller
|
|
||||||
if (
|
|
||||||
services_controller is not None
|
|
||||||
and services_controller.software_name == "Dlk-Services"
|
|
||||||
):
|
|
||||||
continue
|
|
||||||
# Technically allowed, but it's a bad style to use this without
|
# Technically allowed, but it's a bad style to use this without
|
||||||
# explicit configuration by the operators.
|
# explicit configuration by the operators.
|
||||||
assert False, "RPL_WHOISSPECIAL in use with default configuration"
|
assert False, "RPL_WHOISSPECIAL in use with default configuration"
|
||||||
|
@ -201,6 +201,10 @@ class WhowasTestCase(cases.BaseServerTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@cases.mark_specifications("RFC1459", "RFC2812", "Modern")
|
@cases.mark_specifications("RFC1459", "RFC2812", "Modern")
|
||||||
|
@cases.xfailIfSoftware(
|
||||||
|
["InspIRCd"],
|
||||||
|
"Feature not released yet: https://github.com/inspircd/inspircd/pull/1967",
|
||||||
|
)
|
||||||
def testWhowasMultiple(self):
|
def testWhowasMultiple(self):
|
||||||
"""
|
"""
|
||||||
"The history is searched backward, returning the most recent entry first."
|
"The history is searched backward, returning the most recent entry first."
|
||||||
@ -211,6 +215,10 @@ class WhowasTestCase(cases.BaseServerTestCase):
|
|||||||
self._testWhowasMultiple(second_result=True, whowas_command="WHOWAS nick2")
|
self._testWhowasMultiple(second_result=True, whowas_command="WHOWAS nick2")
|
||||||
|
|
||||||
@cases.mark_specifications("RFC1459", "RFC2812", "Modern")
|
@cases.mark_specifications("RFC1459", "RFC2812", "Modern")
|
||||||
|
@cases.xfailIfSoftware(
|
||||||
|
["InspIRCd"],
|
||||||
|
"Feature not released yet: https://github.com/inspircd/inspircd/pull/1968",
|
||||||
|
)
|
||||||
def testWhowasCount1(self):
|
def testWhowasCount1(self):
|
||||||
"""
|
"""
|
||||||
"If there are multiple entries, up to <count> replies will be returned"
|
"If there are multiple entries, up to <count> replies will be returned"
|
||||||
@ -221,6 +229,10 @@ class WhowasTestCase(cases.BaseServerTestCase):
|
|||||||
self._testWhowasMultiple(second_result=False, whowas_command="WHOWAS nick2 1")
|
self._testWhowasMultiple(second_result=False, whowas_command="WHOWAS nick2 1")
|
||||||
|
|
||||||
@cases.mark_specifications("RFC1459", "RFC2812", "Modern")
|
@cases.mark_specifications("RFC1459", "RFC2812", "Modern")
|
||||||
|
@cases.xfailIfSoftware(
|
||||||
|
["InspIRCd"],
|
||||||
|
"Feature not released yet: https://github.com/inspircd/inspircd/pull/1968",
|
||||||
|
)
|
||||||
def testWhowasCount2(self):
|
def testWhowasCount2(self):
|
||||||
"""
|
"""
|
||||||
"If there are multiple entries, up to <count> replies will be returned"
|
"If there are multiple entries, up to <count> replies will be returned"
|
||||||
@ -231,6 +243,10 @@ class WhowasTestCase(cases.BaseServerTestCase):
|
|||||||
self._testWhowasMultiple(second_result=True, whowas_command="WHOWAS nick2 2")
|
self._testWhowasMultiple(second_result=True, whowas_command="WHOWAS nick2 2")
|
||||||
|
|
||||||
@cases.mark_specifications("RFC1459", "RFC2812", "Modern")
|
@cases.mark_specifications("RFC1459", "RFC2812", "Modern")
|
||||||
|
@cases.xfailIfSoftware(
|
||||||
|
["InspIRCd"],
|
||||||
|
"Feature not released yet: https://github.com/inspircd/inspircd/pull/1968",
|
||||||
|
)
|
||||||
def testWhowasCountNegative(self):
|
def testWhowasCountNegative(self):
|
||||||
"""
|
"""
|
||||||
"If a non-positive number is passed as being <count>, then a full search
|
"If a non-positive number is passed as being <count>, then a full search
|
||||||
@ -248,6 +264,10 @@ class WhowasTestCase(cases.BaseServerTestCase):
|
|||||||
@cases.xfailIfSoftware(
|
@cases.xfailIfSoftware(
|
||||||
["ircu2"], "Fix not released yet: https://github.com/UndernetIRC/ircu2/pull/19"
|
["ircu2"], "Fix not released yet: https://github.com/UndernetIRC/ircu2/pull/19"
|
||||||
)
|
)
|
||||||
|
@cases.xfailIfSoftware(
|
||||||
|
["InspIRCd"],
|
||||||
|
"Feature not released yet: https://github.com/inspircd/inspircd/pull/1967",
|
||||||
|
)
|
||||||
def testWhowasCountZero(self):
|
def testWhowasCountZero(self):
|
||||||
"""
|
"""
|
||||||
"If a non-positive number is passed as being <count>, then a full search
|
"If a non-positive number is passed as being <count>, then a full search
|
||||||
|
@ -27,20 +27,16 @@ class Specifications(enum.Enum):
|
|||||||
|
|
||||||
@enum.unique
|
@enum.unique
|
||||||
class Capabilities(enum.Enum):
|
class Capabilities(enum.Enum):
|
||||||
ACCOUNT_NOTIFY = "account-notify"
|
|
||||||
ACCOUNT_TAG = "account-tag"
|
ACCOUNT_TAG = "account-tag"
|
||||||
AWAY_NOTIFY = "away-notify"
|
AWAY_NOTIFY = "away-notify"
|
||||||
BATCH = "batch"
|
BATCH = "batch"
|
||||||
ECHO_MESSAGE = "echo-message"
|
ECHO_MESSAGE = "echo-message"
|
||||||
EXTENDED_JOIN = "extended-join"
|
EXTENDED_JOIN = "extended-join"
|
||||||
EXTENDED_MONITOR = "extended-monitor"
|
|
||||||
LABELED_RESPONSE = "labeled-response"
|
LABELED_RESPONSE = "labeled-response"
|
||||||
MESSAGE_REDACTION = "draft/message-redaction"
|
|
||||||
MESSAGE_TAGS = "message-tags"
|
MESSAGE_TAGS = "message-tags"
|
||||||
MULTILINE = "draft/multiline"
|
MULTILINE = "draft/multiline"
|
||||||
MULTI_PREFIX = "multi-prefix"
|
MULTI_PREFIX = "multi-prefix"
|
||||||
SERVER_TIME = "server-time"
|
SERVER_TIME = "server-time"
|
||||||
SETNAME = "setname"
|
|
||||||
STS = "sts"
|
STS = "sts"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -60,7 +56,6 @@ class IsupportTokens(enum.Enum):
|
|||||||
MONITOR = "MONITOR"
|
MONITOR = "MONITOR"
|
||||||
STATUSMSG = "STATUSMSG"
|
STATUSMSG = "STATUSMSG"
|
||||||
TARGMAX = "TARGMAX"
|
TARGMAX = "TARGMAX"
|
||||||
UTF8ONLY = "UTF8ONLY"
|
|
||||||
WHOX = "WHOX"
|
WHOX = "WHOX"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -65,7 +65,7 @@ def get_install_steps(*, software_config, software_id, version_flavor):
|
|||||||
install_steps = [
|
install_steps = [
|
||||||
{
|
{
|
||||||
"name": f"Checkout {name}",
|
"name": f"Checkout {name}",
|
||||||
"uses": "actions/checkout@v3",
|
"uses": "actions/checkout@v2",
|
||||||
"with": {
|
"with": {
|
||||||
"repository": software_config["repository"],
|
"repository": software_config["repository"],
|
||||||
"ref": ref,
|
"ref": ref,
|
||||||
@ -94,7 +94,7 @@ def get_build_job(*, software_config, software_id, version_flavor):
|
|||||||
cache = [
|
cache = [
|
||||||
{
|
{
|
||||||
"name": "Cache dependencies",
|
"name": "Cache dependencies",
|
||||||
"uses": "actions/cache@v3",
|
"uses": "actions/cache@v2",
|
||||||
"with": {
|
"with": {
|
||||||
"path": f"~/.cache\n${{ github.workspace }}/{path}\n",
|
"path": f"~/.cache\n${{ github.workspace }}/{path}\n",
|
||||||
"key": "3-${{ runner.os }}-"
|
"key": "3-${{ runner.os }}-"
|
||||||
@ -116,17 +116,17 @@ def get_build_job(*, software_config, software_id, version_flavor):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"runs-on": "ubuntu-20.04",
|
"runs-on": "ubuntu-latest",
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"name": "Create directories",
|
"name": "Create directories",
|
||||||
"run": "cd ~/; mkdir -p .local/ go/",
|
"run": "cd ~/; mkdir -p .local/ go/",
|
||||||
},
|
},
|
||||||
*cache,
|
*cache,
|
||||||
{"uses": "actions/checkout@v3"},
|
{"uses": "actions/checkout@v2"},
|
||||||
{
|
{
|
||||||
"name": "Set up Python 3.7",
|
"name": "Set up Python 3.7",
|
||||||
"uses": "actions/setup-python@v4",
|
"uses": "actions/setup-python@v2",
|
||||||
"with": {"python-version": 3.7},
|
"with": {"python-version": 3.7},
|
||||||
},
|
},
|
||||||
*install_steps,
|
*install_steps,
|
||||||
@ -159,7 +159,7 @@ def get_test_job(*, config, test_config, test_id, version_flavor, jobs):
|
|||||||
downloads.append(
|
downloads.append(
|
||||||
{
|
{
|
||||||
"name": "Download build artefacts",
|
"name": "Download build artefacts",
|
||||||
"uses": "actions/download-artifact@v3",
|
"uses": "actions/download-artifact@v2",
|
||||||
"with": {"name": f"installed-{software_id}", "path": "~"},
|
"with": {"name": f"installed-{software_id}", "path": "~"},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -191,13 +191,13 @@ def get_test_job(*, config, test_config, test_id, version_flavor, jobs):
|
|||||||
unpack = []
|
unpack = []
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"runs-on": "ubuntu-20.04",
|
"runs-on": "ubuntu-latest",
|
||||||
"needs": needs,
|
"needs": needs,
|
||||||
"steps": [
|
"steps": [
|
||||||
{"uses": "actions/checkout@v3"},
|
{"uses": "actions/checkout@v2"},
|
||||||
{
|
{
|
||||||
"name": "Set up Python 3.7",
|
"name": "Set up Python 3.7",
|
||||||
"uses": "actions/setup-python@v4",
|
"uses": "actions/setup-python@v2",
|
||||||
"with": {"python-version": 3.7},
|
"with": {"python-version": 3.7},
|
||||||
},
|
},
|
||||||
*downloads,
|
*downloads,
|
||||||
@ -231,7 +231,7 @@ def get_test_job(*, config, test_config, test_id, version_flavor, jobs):
|
|||||||
{
|
{
|
||||||
"name": "Publish results",
|
"name": "Publish results",
|
||||||
"if": "always()",
|
"if": "always()",
|
||||||
"uses": "actions/upload-artifact@v3",
|
"uses": "actions/upload-artifact@v2",
|
||||||
"with": {
|
"with": {
|
||||||
"name": f"pytest-results_{test_id}_{version_flavor.value}",
|
"name": f"pytest-results_{test_id}_{version_flavor.value}",
|
||||||
"path": "pytest.xml",
|
"path": "pytest.xml",
|
||||||
@ -250,7 +250,7 @@ def upload_steps(software_id):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Upload build artefacts",
|
"name": "Upload build artefacts",
|
||||||
"uses": "actions/upload-artifact@v3",
|
"uses": "actions/upload-artifact@v2",
|
||||||
"with": {
|
"with": {
|
||||||
"name": f"installed-{software_id}",
|
"name": f"installed-{software_id}",
|
||||||
"path": "~/artefacts-*.tar.gz",
|
"path": "~/artefacts-*.tar.gz",
|
||||||
@ -263,6 +263,7 @@ def upload_steps(software_id):
|
|||||||
|
|
||||||
|
|
||||||
def generate_workflow(config: dict, version_flavor: VersionFlavor):
|
def generate_workflow(config: dict, version_flavor: VersionFlavor):
|
||||||
|
|
||||||
on: dict
|
on: dict
|
||||||
if version_flavor == VersionFlavor.STABLE:
|
if version_flavor == VersionFlavor.STABLE:
|
||||||
on = {"push": None, "pull_request": None}
|
on = {"push": None, "pull_request": None}
|
||||||
@ -306,15 +307,15 @@ def generate_workflow(config: dict, version_flavor: VersionFlavor):
|
|||||||
jobs["publish-test-results"] = {
|
jobs["publish-test-results"] = {
|
||||||
"name": "Publish Dashboard",
|
"name": "Publish Dashboard",
|
||||||
"needs": sorted({f"test-{test_id}" for test_id in config["tests"]} & set(jobs)),
|
"needs": sorted({f"test-{test_id}" for test_id in config["tests"]} & set(jobs)),
|
||||||
"runs-on": "ubuntu-20.04",
|
"runs-on": "ubuntu-latest",
|
||||||
# the build-and-test job might be skipped, we don't need to run
|
# the build-and-test job might be skipped, we don't need to run
|
||||||
# this job then
|
# this job then
|
||||||
"if": "success() || failure()",
|
"if": "success() || failure()",
|
||||||
"steps": [
|
"steps": [
|
||||||
{"uses": "actions/checkout@v3"},
|
{"uses": "actions/checkout@v2"},
|
||||||
{
|
{
|
||||||
"name": "Download Artifacts",
|
"name": "Download Artifacts",
|
||||||
"uses": "actions/download-artifact@v3",
|
"uses": "actions/download-artifact@v2",
|
||||||
"with": {"path": "artifacts"},
|
"with": {"path": "artifacts"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
3
mypy.ini
3
mypy.ini
@ -12,9 +12,6 @@ disallow_untyped_defs = False
|
|||||||
[mypy-irctest.client_tests.*]
|
[mypy-irctest.client_tests.*]
|
||||||
disallow_untyped_defs = False
|
disallow_untyped_defs = False
|
||||||
|
|
||||||
[mypy-irctest.self_tests.*]
|
|
||||||
disallow_untyped_defs = False
|
|
||||||
|
|
||||||
[mypy-defusedxml.*]
|
[mypy-defusedxml.*]
|
||||||
ignore_missing_imports = True
|
ignore_missing_imports = True
|
||||||
|
|
||||||
|
@ -18,20 +18,16 @@ markers =
|
|||||||
private_chathistory
|
private_chathistory
|
||||||
|
|
||||||
# capabilities
|
# capabilities
|
||||||
account-notify
|
|
||||||
account-tag
|
account-tag
|
||||||
away-notify
|
away-notify
|
||||||
batch
|
batch
|
||||||
echo-message
|
echo-message
|
||||||
extended-join
|
extended-join
|
||||||
extended-monitor
|
|
||||||
labeled-response
|
labeled-response
|
||||||
draft/message-redaction
|
|
||||||
message-tags
|
message-tags
|
||||||
draft/multiline
|
draft/multiline
|
||||||
multi-prefix
|
multi-prefix
|
||||||
server-time
|
server-time
|
||||||
setname
|
|
||||||
sts
|
sts
|
||||||
|
|
||||||
# isupport tokens
|
# isupport tokens
|
||||||
@ -42,7 +38,6 @@ markers =
|
|||||||
PREFIX
|
PREFIX
|
||||||
STATUSMSG
|
STATUSMSG
|
||||||
TARGMAX
|
TARGMAX
|
||||||
UTF8ONLY
|
|
||||||
WHOX
|
WHOX
|
||||||
|
|
||||||
python_classes = *TestCase Test*
|
python_classes = *TestCase Test*
|
||||||
|
@ -42,7 +42,7 @@ def partial_compaction(d):
|
|||||||
# tests separate
|
# tests separate
|
||||||
compacted_d = {}
|
compacted_d = {}
|
||||||
successes = []
|
successes = []
|
||||||
for k, v in d.items():
|
for (k, v) in d.items():
|
||||||
if isinstance(v, CompactedResult) and v.success and v.nb_skipped == 0:
|
if isinstance(v, CompactedResult) and v.success and v.nb_skipped == 0:
|
||||||
successes.append((k, v))
|
successes.append((k, v))
|
||||||
else:
|
else:
|
||||||
|
@ -143,7 +143,7 @@ software:
|
|||||||
name: InspIRCd
|
name: InspIRCd
|
||||||
repository: inspircd/inspircd
|
repository: inspircd/inspircd
|
||||||
refs: &inspircd_refs
|
refs: &inspircd_refs
|
||||||
stable: v3.15.0
|
stable: v3.12.0
|
||||||
release: null
|
release: null
|
||||||
devel: master
|
devel: master
|
||||||
devel_release: insp3
|
devel_release: insp3
|
||||||
@ -153,13 +153,9 @@ software:
|
|||||||
separate_build_job: true
|
separate_build_job: true
|
||||||
build_script: &inspircd_build_script |
|
build_script: &inspircd_build_script |
|
||||||
cd $GITHUB_WORKSPACE/inspircd/
|
cd $GITHUB_WORKSPACE/inspircd/
|
||||||
|
patch src/inspircd.cpp < $GITHUB_WORKSPACE/patches/inspircd_mainloop.patch
|
||||||
# Insp3 <= 3.16.0 and Insp4 <= 4.0.0a21 don't support -DINSPIRCD_UNLIMITED_MAINLOOP
|
|
||||||
patch src/inspircd.cpp < $GITHUB_WORKSPACE/patches/inspircd_mainloop.patch || true
|
|
||||||
|
|
||||||
./configure --prefix=$HOME/.local/inspircd --development
|
./configure --prefix=$HOME/.local/inspircd --development
|
||||||
|
make -j 4
|
||||||
CXXFLAGS=-DINSPIRCD_UNLIMITED_MAINLOOP make -j 4
|
|
||||||
make install
|
make install
|
||||||
irc2:
|
irc2:
|
||||||
name: irc2
|
name: irc2
|
||||||
@ -272,8 +268,8 @@ software:
|
|||||||
name: UnrealIRCd 6
|
name: UnrealIRCd 6
|
||||||
repository: unrealircd/unrealircd
|
repository: unrealircd/unrealircd
|
||||||
refs:
|
refs:
|
||||||
stable: da3c1c654481a33035b9c703957e1c25d0158259 # 6.0.7
|
stable: cedd23ae9cdd5985ce16e9869cbdb808479c3fc4 # 6.0.3
|
||||||
release: da3c1c654481a33035b9c703957e1c25d0158259 # 6.0.7
|
release: cedd23ae9cdd5985ce16e9869cbdb808479c3fc4 # 6.0.3
|
||||||
devel: unreal60_dev
|
devel: unreal60_dev
|
||||||
devel_release: null
|
devel_release: null
|
||||||
path: unrealircd
|
path: unrealircd
|
||||||
@ -289,7 +285,6 @@ software:
|
|||||||
CFLAGS="-O0 -march=x86-64" CXXFLAGS="$CFLAGS" ./Config -quick
|
CFLAGS="-O0 -march=x86-64" CXXFLAGS="$CFLAGS" ./Config -quick
|
||||||
make -j 4
|
make -j 4
|
||||||
make install
|
make install
|
||||||
~/.local/unrealircd/unrealircd module install third/react
|
|
||||||
# Prevent download of geoIP database on first startup
|
# Prevent download of geoIP database on first startup
|
||||||
sed -i 's/loadmodule "geoip_classic";//' ~/.local/unrealircd/conf/modules.default.conf
|
sed -i 's/loadmodule "geoip_classic";//' ~/.local/unrealircd/conf/modules.default.conf
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user