mirror of
https://github.com/progval/irctest.git
synced 2025-04-06 07:19:54 +00:00
Compare commits
16 Commits
ban-privms
...
elist-2par
Author | SHA1 | Date | |
---|---|---|---|
6559bb34c0 | |||
67f08fb211 | |||
199d15b434 | |||
b2e8f5d1e1 | |||
136a7923c0 | |||
5364f963ae | |||
1ea3e1c15c | |||
8530c85adc | |||
6815dd238b | |||
00562ff82d | |||
b7e8a7a5f5 | |||
6181dd07ad | |||
5fe4d4cfd8 | |||
544ca4b7ed | |||
35d342a478 | |||
29e4c2bbdb |
62
.github/workflows/test-devel.yml
vendored
62
.github/workflows/test-devel.yml
vendored
@ -3,7 +3,7 @@
|
||||
|
||||
jobs:
|
||||
build-anope:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -43,7 +43,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-bahamut:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -92,7 +92,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-hybrid:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -131,7 +131,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-inspircd:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -162,7 +162,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-ngircd:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -203,7 +203,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-plexus4:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -245,7 +245,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-solanum:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -285,7 +285,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-unrealircd:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -331,7 +331,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-unrealircd-5:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -401,7 +401,7 @@ jobs:
|
||||
- test-unrealircd-anope
|
||||
- test-unrealircd-atheme
|
||||
- test-unrealircd-dlk
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Download Artifacts
|
||||
@ -428,7 +428,7 @@ jobs:
|
||||
test-bahamut:
|
||||
needs:
|
||||
- build-bahamut
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -462,7 +462,7 @@ jobs:
|
||||
needs:
|
||||
- build-bahamut
|
||||
- build-anope
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -500,7 +500,7 @@ jobs:
|
||||
test-bahamut-atheme:
|
||||
needs:
|
||||
- build-bahamut
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -532,7 +532,7 @@ jobs:
|
||||
path: pytest.xml
|
||||
test-ergo:
|
||||
needs: []
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -574,7 +574,7 @@ jobs:
|
||||
needs:
|
||||
- build-hybrid
|
||||
- build-anope
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -612,7 +612,7 @@ jobs:
|
||||
test-inspircd:
|
||||
needs:
|
||||
- build-inspircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -646,7 +646,7 @@ jobs:
|
||||
needs:
|
||||
- build-inspircd
|
||||
- build-anope
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -683,7 +683,7 @@ jobs:
|
||||
path: pytest.xml
|
||||
test-ircu2:
|
||||
needs: []
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -722,7 +722,7 @@ jobs:
|
||||
path: pytest.xml
|
||||
test-limnoria:
|
||||
needs: []
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -750,7 +750,7 @@ jobs:
|
||||
path: pytest.xml
|
||||
test-nefarious:
|
||||
needs: []
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -789,7 +789,7 @@ jobs:
|
||||
test-ngircd:
|
||||
needs:
|
||||
- build-ngircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -823,7 +823,7 @@ jobs:
|
||||
needs:
|
||||
- build-ngircd
|
||||
- build-anope
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -861,7 +861,7 @@ jobs:
|
||||
test-ngircd-atheme:
|
||||
needs:
|
||||
- build-ngircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -895,7 +895,7 @@ jobs:
|
||||
needs:
|
||||
- build-plexus4
|
||||
- build-anope
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -933,7 +933,7 @@ jobs:
|
||||
test-solanum:
|
||||
needs:
|
||||
- build-solanum
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -965,7 +965,7 @@ jobs:
|
||||
path: pytest.xml
|
||||
test-sopel:
|
||||
needs: []
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -993,7 +993,7 @@ jobs:
|
||||
test-unrealircd:
|
||||
needs:
|
||||
- build-unrealircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -1026,7 +1026,7 @@ jobs:
|
||||
test-unrealircd-5:
|
||||
needs:
|
||||
- build-unrealircd-5
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -1060,7 +1060,7 @@ jobs:
|
||||
needs:
|
||||
- build-unrealircd
|
||||
- build-anope
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -1098,7 +1098,7 @@ jobs:
|
||||
test-unrealircd-atheme:
|
||||
needs:
|
||||
- build-unrealircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -1131,7 +1131,7 @@ jobs:
|
||||
test-unrealircd-dlk:
|
||||
needs:
|
||||
- build-unrealircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
|
12
.github/workflows/test-devel_release.yml
vendored
12
.github/workflows/test-devel_release.yml
vendored
@ -3,7 +3,7 @@
|
||||
|
||||
jobs:
|
||||
build-anope:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -43,7 +43,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-inspircd:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -80,7 +80,7 @@ jobs:
|
||||
- test-inspircd
|
||||
- test-inspircd-anope
|
||||
- test-inspircd-atheme
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Download Artifacts
|
||||
@ -107,7 +107,7 @@ jobs:
|
||||
test-inspircd:
|
||||
needs:
|
||||
- build-inspircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -141,7 +141,7 @@ jobs:
|
||||
needs:
|
||||
- build-inspircd
|
||||
- build-anope
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -179,7 +179,7 @@ jobs:
|
||||
test-inspircd-atheme:
|
||||
needs:
|
||||
- build-inspircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
|
70
.github/workflows/test-stable.yml
vendored
70
.github/workflows/test-stable.yml
vendored
@ -3,7 +3,7 @@
|
||||
|
||||
jobs:
|
||||
build-anope:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -43,7 +43,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-bahamut:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -92,7 +92,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-charybdis:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -132,7 +132,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-hybrid:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -171,7 +171,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-inspircd:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -202,7 +202,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-ngircd:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -243,7 +243,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-plexus4:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -285,7 +285,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-solanum:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -325,7 +325,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-unrealircd:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -371,7 +371,7 @@ jobs:
|
||||
path: ~/artefacts-*.tar.gz
|
||||
retention-days: 1
|
||||
build-unrealircd-5:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create directories
|
||||
run: cd ~/; mkdir -p .local/ go/
|
||||
@ -444,7 +444,7 @@ jobs:
|
||||
- test-unrealircd-anope
|
||||
- test-unrealircd-atheme
|
||||
- test-unrealircd-dlk
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Download Artifacts
|
||||
@ -471,7 +471,7 @@ jobs:
|
||||
test-bahamut:
|
||||
needs:
|
||||
- build-bahamut
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -505,7 +505,7 @@ jobs:
|
||||
needs:
|
||||
- build-bahamut
|
||||
- build-anope
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -543,7 +543,7 @@ jobs:
|
||||
test-bahamut-atheme:
|
||||
needs:
|
||||
- build-bahamut
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -576,7 +576,7 @@ jobs:
|
||||
test-charybdis:
|
||||
needs:
|
||||
- build-charybdis
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -608,7 +608,7 @@ jobs:
|
||||
path: pytest.xml
|
||||
test-ergo:
|
||||
needs: []
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -650,7 +650,7 @@ jobs:
|
||||
needs:
|
||||
- build-hybrid
|
||||
- build-anope
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -688,7 +688,7 @@ jobs:
|
||||
test-inspircd:
|
||||
needs:
|
||||
- build-inspircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -722,7 +722,7 @@ jobs:
|
||||
needs:
|
||||
- build-inspircd
|
||||
- build-anope
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -760,7 +760,7 @@ jobs:
|
||||
test-inspircd-atheme:
|
||||
needs:
|
||||
- build-inspircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -792,7 +792,7 @@ jobs:
|
||||
path: pytest.xml
|
||||
test-irc2:
|
||||
needs: []
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -842,7 +842,7 @@ jobs:
|
||||
path: pytest.xml
|
||||
test-ircu2:
|
||||
needs: []
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -881,7 +881,7 @@ jobs:
|
||||
path: pytest.xml
|
||||
test-limnoria:
|
||||
needs: []
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -908,7 +908,7 @@ jobs:
|
||||
path: pytest.xml
|
||||
test-nefarious:
|
||||
needs: []
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -947,7 +947,7 @@ jobs:
|
||||
test-ngircd:
|
||||
needs:
|
||||
- build-ngircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -981,7 +981,7 @@ jobs:
|
||||
needs:
|
||||
- build-ngircd
|
||||
- build-anope
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -1019,7 +1019,7 @@ jobs:
|
||||
test-ngircd-atheme:
|
||||
needs:
|
||||
- build-ngircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -1053,7 +1053,7 @@ jobs:
|
||||
needs:
|
||||
- build-plexus4
|
||||
- build-anope
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -1091,7 +1091,7 @@ jobs:
|
||||
test-solanum:
|
||||
needs:
|
||||
- build-solanum
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -1123,7 +1123,7 @@ jobs:
|
||||
path: pytest.xml
|
||||
test-sopel:
|
||||
needs: []
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -1151,7 +1151,7 @@ jobs:
|
||||
test-unrealircd:
|
||||
needs:
|
||||
- build-unrealircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -1184,7 +1184,7 @@ jobs:
|
||||
test-unrealircd-5:
|
||||
needs:
|
||||
- build-unrealircd-5
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -1218,7 +1218,7 @@ jobs:
|
||||
needs:
|
||||
- build-unrealircd
|
||||
- build-anope
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -1256,7 +1256,7 @@ jobs:
|
||||
test-unrealircd-atheme:
|
||||
needs:
|
||||
- build-unrealircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
@ -1289,7 +1289,7 @@ jobs:
|
||||
test-unrealircd-dlk:
|
||||
needs:
|
||||
- build-unrealircd
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
|
@ -2,22 +2,23 @@ exclude: ^irctest/scram
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.3.0
|
||||
rev: 23.1.0
|
||||
hooks:
|
||||
- id: black
|
||||
language_version: python3
|
||||
|
||||
- repo: https://github.com/PyCQA/isort
|
||||
rev: 5.5.2
|
||||
rev: 5.11.5
|
||||
hooks:
|
||||
- id: isort
|
||||
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 5.0.4
|
||||
hooks:
|
||||
- id: flake8
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v0.812
|
||||
rev: v1.0.1
|
||||
hooks:
|
||||
- id: mypy
|
||||
additional_dependencies: [types-PyYAML, types-docutils]
|
||||
|
@ -7,6 +7,7 @@ import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
import tempfile
|
||||
import textwrap
|
||||
import time
|
||||
from typing import IO, Any, Callable, Dict, List, Optional, Set, Tuple, Type
|
||||
|
||||
@ -156,10 +157,18 @@ class DirectoryBasedController(_BaseController):
|
||||
],
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
subprocess.check_output(
|
||||
[self.openssl_bin, "dhparam", "-out", self.dh_path, "128"],
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
with self.dh_path.open("w") as fd:
|
||||
fd.write(
|
||||
textwrap.dedent(
|
||||
"""
|
||||
-----BEGIN DH PARAMETERS-----
|
||||
MIGHAoGBAJICSyQAiLj1fw8b5xELcnpqBQ+wvOyKgim4IetWOgZnRQFkTgOeoRZD
|
||||
HksACRFJL/EqHxDKcy/2Ghwr2axhNxSJ+UOBmraP3WfodV/fCDPnZ+XnI9fjHsIr
|
||||
rjisPMqomjXeiTB1UeAHvLUmCK4yx6lpAJsCYwJjsqkycUfHiy1bAgEC
|
||||
-----END DH PARAMETERS-----
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class BaseClientController(_BaseController):
|
||||
|
@ -173,7 +173,7 @@ class _IrcTestCase(Generic[TController]):
|
||||
) -> Optional[str]:
|
||||
"""Returns an error message if the message doesn't match the given arguments,
|
||||
or None if it matches."""
|
||||
for (key, value) in kwargs.items():
|
||||
for key, value in kwargs.items():
|
||||
if getattr(msg, key) != value:
|
||||
fail_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
|
||||
user: Optional[List[str]] = None
|
||||
server: socket.socket
|
||||
protocol_version = Optional[str]
|
||||
acked_capabilities = Optional[Set[str]]
|
||||
protocol_version: Optional[str]
|
||||
acked_capabilities: Optional[Set[str]]
|
||||
|
||||
__new__ = object.__new__ # pytest won't collect Generic[] subclasses otherwise
|
||||
|
||||
@ -448,7 +448,9 @@ class BaseClientTestCase(_IrcTestCase[basecontrollers.BaseClientController]):
|
||||
print("{:.3f} S: {}".format(time.time(), line.strip()))
|
||||
|
||||
def readCapLs(
|
||||
self, auth: Optional[Authentication] = None, tls_config: tls.TlsConfig = None
|
||||
self,
|
||||
auth: Optional[Authentication] = None,
|
||||
tls_config: Optional[tls.TlsConfig] = None,
|
||||
) -> None:
|
||||
(hostname, port) = self.server.getsockname()
|
||||
self.controller.run(
|
||||
@ -458,9 +460,9 @@ class BaseClientTestCase(_IrcTestCase[basecontrollers.BaseClientController]):
|
||||
m = self.getMessage()
|
||||
self.assertEqual(m.command, "CAP", "First message is not CAP LS.")
|
||||
if m.params == ["LS"]:
|
||||
self.protocol_version = 301
|
||||
self.protocol_version = "301"
|
||||
elif m.params == ["LS", "302"]:
|
||||
self.protocol_version = 302
|
||||
self.protocol_version = "302"
|
||||
elif m.params == ["END"]:
|
||||
self.protocol_version = None
|
||||
else:
|
||||
@ -689,7 +691,7 @@ class BaseServerTestCase(
|
||||
def connectClient(
|
||||
self,
|
||||
nick: str,
|
||||
name: TClientName = None,
|
||||
name: Optional[TClientName] = None,
|
||||
capabilities: Optional[List[str]] = None,
|
||||
skip_if_cap_nak: bool = False,
|
||||
show_io: Optional[bool] = None,
|
||||
@ -734,8 +736,8 @@ class BaseServerTestCase(
|
||||
self.server_support[param] = None
|
||||
welcome.append(m)
|
||||
|
||||
self.targmax: Dict[str, Optional[str]] = dict(
|
||||
item.split(":", 1) # type: ignore
|
||||
self.targmax: Dict[str, Optional[str]] = dict( # type: ignore[assignment]
|
||||
item.split(":", 1)
|
||||
for item in (self.server_support.get("TARGMAX") or "").split(",")
|
||||
if item
|
||||
)
|
||||
|
@ -1,3 +1,4 @@
|
||||
import functools
|
||||
import shutil
|
||||
import subprocess
|
||||
from typing import Optional, Set, Type
|
||||
@ -80,8 +81,8 @@ TEMPLATE_CONFIG = """
|
||||
|
||||
# HELP/HELPOP
|
||||
<module name="alias"> # for the HELP alias
|
||||
<module name="helpop">
|
||||
<include file="examples/helpop.conf.example">
|
||||
<module name="{help_module_name}">
|
||||
<include file="examples/{help_module_name}.conf.example">
|
||||
|
||||
# Misc:
|
||||
<log method="file" type="*" level="debug" target="/tmp/ircd-{port}.log">
|
||||
@ -94,6 +95,17 @@ 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):
|
||||
software_name = "InspIRCd"
|
||||
supported_sasl_mechanisms = {"PLAIN"}
|
||||
@ -138,6 +150,13 @@ class InspircdController(BaseServerController, DirectoryBasedController):
|
||||
else:
|
||||
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:
|
||||
fd.write(
|
||||
TEMPLATE_CONFIG.format(
|
||||
@ -147,6 +166,7 @@ class InspircdController(BaseServerController, DirectoryBasedController):
|
||||
services_port=services_port,
|
||||
password_field=password_field,
|
||||
ssl_config=ssl_config,
|
||||
help_module_name=help_module_name,
|
||||
)
|
||||
)
|
||||
assert self.directory
|
||||
|
@ -73,7 +73,7 @@ class SopelController(BaseClientController):
|
||||
auth_method="auth_method = sasl" if auth else "",
|
||||
)
|
||||
)
|
||||
self.proc = subprocess.Popen(["sopel", "--quiet", "-c", self.filename])
|
||||
self.proc = subprocess.Popen(["sopel", "-c", self.filename])
|
||||
|
||||
|
||||
def get_irctest_controller_class() -> Type[SopelController]:
|
||||
|
@ -39,7 +39,7 @@ class CaseResult:
|
||||
type: Optional[str] = None
|
||||
message: Optional[str] = None
|
||||
|
||||
def output_filename(self):
|
||||
def output_filename(self) -> str:
|
||||
test_name = self.test_name
|
||||
if len(test_name) > 50 or set(test_name) & NETLIFY_CHAR_BLACKLIST:
|
||||
# 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
|
||||
details = None
|
||||
system_out = None
|
||||
extra = {}
|
||||
extra: Dict[str, str] = {}
|
||||
for child in case:
|
||||
if child.tag == "skipped":
|
||||
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
|
||||
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()
|
||||
):
|
||||
if multiple_modules:
|
||||
@ -220,7 +220,7 @@ def build_test_table(jobs: List[str], results: List[CaseResult]) -> ET.Element:
|
||||
|
||||
# One row for each test:
|
||||
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}"
|
||||
if len(row_anchor) >= 50:
|
||||
# Too long; give up on generating readable URL
|
||||
@ -314,7 +314,7 @@ def write_html_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
|
||||
module_categories = {
|
||||
job_categories[result.job]
|
||||
@ -366,7 +366,7 @@ def write_html_index(output_dir: Path, pages: List[Tuple[str, str, str]]) -> Non
|
||||
|
||||
module_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":
|
||||
module_pages.append((title, file_name))
|
||||
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.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)
|
||||
|
||||
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.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.text = job
|
||||
|
||||
|
@ -18,7 +18,7 @@ class Artifact:
|
||||
download_url: str
|
||||
|
||||
@property
|
||||
def public_download_url(self):
|
||||
def public_download_url(self) -> str:
|
||||
# GitHub API is not available publicly for artifacts, we need to use
|
||||
# a third-party proxy to access it...
|
||||
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
|
||||
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):
|
||||
remaining_keys_wildcard = (expected_key.key, expected_value)
|
||||
else:
|
||||
@ -168,7 +168,7 @@ def match_dict(
|
||||
|
||||
if 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):
|
||||
return False
|
||||
if not match_string(value, expected_value):
|
||||
|
@ -9,6 +9,7 @@ from irctest.patma import ANYSTR
|
||||
REGISTER_CAP_NAME = "draft/account-registration"
|
||||
|
||||
|
||||
@cases.mark_services
|
||||
@cases.mark_specifications("IRCv3")
|
||||
class RegisterBeforeConnectTestCase(cases.BaseServerTestCase):
|
||||
@staticmethod
|
||||
@ -33,6 +34,7 @@ class RegisterBeforeConnectTestCase(cases.BaseServerTestCase):
|
||||
self.assertMessageMatch(register_response, params=["SUCCESS", ANYSTR, ANYSTR])
|
||||
|
||||
|
||||
@cases.mark_services
|
||||
@cases.mark_specifications("IRCv3")
|
||||
class RegisterBeforeConnectDisallowedTestCase(cases.BaseServerTestCase):
|
||||
@staticmethod
|
||||
@ -60,6 +62,7 @@ class RegisterBeforeConnectDisallowedTestCase(cases.BaseServerTestCase):
|
||||
)
|
||||
|
||||
|
||||
@cases.mark_services
|
||||
@cases.mark_specifications("IRCv3")
|
||||
class RegisterEmailVerifiedTestCase(cases.BaseServerTestCase):
|
||||
@staticmethod
|
||||
@ -110,6 +113,7 @@ class RegisterEmailVerifiedTestCase(cases.BaseServerTestCase):
|
||||
)
|
||||
|
||||
|
||||
@cases.mark_services
|
||||
@cases.mark_specifications("IRCv3", "Ergo")
|
||||
class RegisterNoLandGrabsTestCase(cases.BaseServerTestCase):
|
||||
@staticmethod
|
||||
|
@ -238,6 +238,135 @@ class ListTestCase(_BasedListTestCase):
|
||||
self.sendLine(3, "LIST <100")
|
||||
self.assertEqual(self._parseChanList(3), {"#chan1", "#chan2"})
|
||||
|
||||
@cases.mark_specifications("Modern")
|
||||
def testListTwoChannels(self):
|
||||
"""
|
||||
"Parameters: [<channel>{,<channel>}] [<elistcond>{,<elistcond>}]"
|
||||
-- https://modern.ircdocs.horse/#list-message
|
||||
"""
|
||||
self.connectClient("foo")
|
||||
|
||||
if "TARGMAX" in self.server_support:
|
||||
for item in (self.server_support["TARGMAX"]).split(","):
|
||||
(command, max_) = item.split(":", 1)
|
||||
if command == "LIST" and int(max_ or "1000") < 2:
|
||||
raise runner.OptionalExtensionNotSupported("TARGMAX=LIST >= 2")
|
||||
|
||||
self.sendLine(1, "JOIN #chan1")
|
||||
self.getMessages(1)
|
||||
self.sendLine(1, "JOIN #chan2")
|
||||
self.getMessages(1)
|
||||
self.sendLine(1, "JOIN #chan3")
|
||||
self.getMessages(1)
|
||||
|
||||
self.connectClient("bar")
|
||||
self.sendLine(2, "JOIN #chan2")
|
||||
self.getMessages(2)
|
||||
|
||||
self.connectClient("baz")
|
||||
|
||||
self.sendLine(3, "LIST")
|
||||
self.assertEqual(self._parseChanList(3), {"#chan1", "#chan2", "#chan3"})
|
||||
|
||||
self.sendLine(3, "LIST #chan1,#chan2")
|
||||
self.assertEqual(self._parseChanList(3), {"#chan1", "#chan2"})
|
||||
|
||||
@cases.mark_isupport("ELIST")
|
||||
def testListTwoMasks(self):
|
||||
self.connectClient("foo")
|
||||
|
||||
if "M" not in self.server_support.get("ELIST", ""):
|
||||
raise runner.OptionalExtensionNotSupported("ELIST=M")
|
||||
|
||||
if "TARGMAX" in self.server_support:
|
||||
for item in (self.server_support["TARGMAX"]).split(","):
|
||||
(command, max_) = item.split(":", 1)
|
||||
if command == "LIST" and int(max_ or "1000") < 2:
|
||||
raise runner.OptionalExtensionNotSupported("TARGMAX=LIST >= 2")
|
||||
|
||||
self.sendLine(1, "JOIN #chan1")
|
||||
self.getMessages(1)
|
||||
self.sendLine(1, "JOIN #chan2")
|
||||
self.getMessages(1)
|
||||
self.sendLine(1, "JOIN #chan3")
|
||||
self.getMessages(1)
|
||||
|
||||
self.connectClient("bar")
|
||||
self.sendLine(2, "JOIN #chan2")
|
||||
self.getMessages(2)
|
||||
|
||||
self.connectClient("baz")
|
||||
|
||||
self.sendLine(3, "LIST")
|
||||
self.assertEqual(self._parseChanList(3), {"#chan1", "#chan2", "#chan3"})
|
||||
|
||||
self.sendLine(3, "LIST *an1,*an2")
|
||||
self.assertEqual(self._parseChanList(3), {"#chan1", "#chan2"})
|
||||
|
||||
@cases.mark_isupport("ELIST")
|
||||
@cases.mark_specifications("Modern")
|
||||
def testListTwoParams(self):
|
||||
"""
|
||||
"Parameters: [<channel>{,<channel>}] [<elistcond>{,<elistcond>}]"
|
||||
-- https://modern.ircdocs.horse/#list-message
|
||||
"""
|
||||
self.connectClient("foo")
|
||||
|
||||
if "U" not in self.server_support.get("ELIST", ""):
|
||||
raise runner.OptionalExtensionNotSupported("ELIST=U")
|
||||
|
||||
self.sendLine(1, "JOIN #chan1")
|
||||
self.getMessages(1)
|
||||
self.sendLine(1, "JOIN #chan2")
|
||||
self.getMessages(1)
|
||||
|
||||
self.connectClient("bar")
|
||||
self.sendLine(2, "JOIN #chan2")
|
||||
self.getMessages(2)
|
||||
|
||||
self.connectClient("baz")
|
||||
|
||||
self.sendLine(3, "LIST #chan1 >0")
|
||||
self.assertEqual(self._parseChanList(3), {"#chan1"})
|
||||
|
||||
self.sendLine(3, "LIST #chan1 <1")
|
||||
self.assertEqual(self._parseChanList(3), set())
|
||||
|
||||
@cases.mark_isupport("ELIST")
|
||||
@cases.mark_specifications("Modern")
|
||||
def testListTwoParamsTwoChannels(self):
|
||||
"""
|
||||
"Parameters: [<channel>{,<channel>}] [<elistcond>{,<elistcond>}]"
|
||||
-- https://modern.ircdocs.horse/#list-message
|
||||
"""
|
||||
self.connectClient("foo")
|
||||
|
||||
if "U" not in self.server_support.get("ELIST", ""):
|
||||
raise runner.OptionalExtensionNotSupported("ELIST=U")
|
||||
|
||||
if "TARGMAX" in self.server_support:
|
||||
for item in (self.server_support["TARGMAX"]).split(","):
|
||||
(command, max_) = item.split(":", 1)
|
||||
if command == "LIST" and int(max_ or "1000") < 2:
|
||||
raise runner.OptionalExtensionNotSupported("TARGMAX=LIST >= 2")
|
||||
|
||||
self.sendLine(1, "JOIN #chan1")
|
||||
self.getMessages(1)
|
||||
self.sendLine(1, "JOIN #chan2")
|
||||
self.getMessages(1)
|
||||
|
||||
self.connectClient("bar")
|
||||
self.sendLine(2, "JOIN #chan2")
|
||||
self.getMessages(2)
|
||||
|
||||
self.connectClient("baz")
|
||||
|
||||
self.sendLine(3, "LIST #chan1,#chan2 >0")
|
||||
self.assertEqual(self._parseChanList(3), {"#chan1", "#chan2"})
|
||||
|
||||
self.sendLine(3, "LIST #chan1,#chan2 <1")
|
||||
self.assertEqual(self._parseChanList(3), set())
|
||||
|
||||
|
||||
class FaketimeListTestCase(_BasedListTestCase):
|
||||
faketime = "+1y x30" # for every wall clock second, 1 minute passed for the server
|
||||
|
@ -32,6 +32,26 @@ class PrivmsgTestCase(cases.BaseServerTestCase):
|
||||
# ERR_NOSUCHNICK, ERR_NOSUCHCHANNEL, or ERR_CANNOTSENDTOCHAN
|
||||
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):
|
||||
@cases.mark_specifications("RFC1459", "RFC2812")
|
||||
|
@ -1,7 +1,10 @@
|
||||
"""
|
||||
`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.client_mock import NoMessageException
|
||||
from irctest.numerics import (
|
||||
@ -13,7 +16,7 @@ from irctest.numerics import (
|
||||
from irctest.patma import ANYSTR, StrRe
|
||||
|
||||
|
||||
class MonitorTestCase(cases.BaseServerTestCase):
|
||||
class _BaseMonitorTestCase(cases.BaseServerTestCase):
|
||||
def check_server_support(self):
|
||||
if "MONITOR" not in self.server_support:
|
||||
raise runner.IsupportTokenNotSupported("MONITOR")
|
||||
@ -42,6 +45,8 @@ class MonitorTestCase(cases.BaseServerTestCase):
|
||||
extra_format=(nick,),
|
||||
)
|
||||
|
||||
|
||||
class MonitorTestCase(_BaseMonitorTestCase):
|
||||
@cases.mark_specifications("IRCv3")
|
||||
@cases.mark_isupport("MONITOR")
|
||||
def testMonitorOneDisconnected(self):
|
||||
@ -295,10 +300,11 @@ class MonitorTestCase(cases.BaseServerTestCase):
|
||||
self.sendLine(2, "NICK qux")
|
||||
self.getMessages(2)
|
||||
mononline = self.getMessages(1)[0]
|
||||
self.assertEqual(mononline.command, RPL_MONONLINE)
|
||||
self.assertEqual(len(mononline.params), 2, mononline.params)
|
||||
self.assertIn(mononline.params[0], ("bar", "*"))
|
||||
self.assertEqual(mononline.params[1].split("!")[0], "qux")
|
||||
self.assertMessageMatch(
|
||||
mononline,
|
||||
command=RPL_MONONLINE,
|
||||
params=[StrRe(r"(bar|\*)"), StrRe("qux(!.*)?")],
|
||||
)
|
||||
|
||||
# no numerics for a case change
|
||||
self.sendLine(2, "NICK QUX")
|
||||
@ -309,7 +315,246 @@ class MonitorTestCase(cases.BaseServerTestCase):
|
||||
self.getMessages(2)
|
||||
monoffline = self.getMessages(1)[0]
|
||||
# should get RPL_MONOFFLINE with the current unfolded nick
|
||||
self.assertEqual(monoffline.command, RPL_MONOFFLINE)
|
||||
self.assertEqual(len(monoffline.params), 2, monoffline.params)
|
||||
self.assertIn(monoffline.params[0], ("bar", "*"))
|
||||
self.assertEqual(monoffline.params[1].split("!")[0], "QUX")
|
||||
self.assertMessageMatch(
|
||||
monoffline,
|
||||
command=RPL_MONOFFLINE,
|
||||
params=[StrRe(r"(bar|\*)"), "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,36 +1,21 @@
|
||||
"""
|
||||
`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>`_
|
||||
"""
|
||||
|
||||
from irctest import cases
|
||||
from irctest import cases, runner
|
||||
from irctest.patma import ANYSTR
|
||||
|
||||
|
||||
class Utf8TestCase(cases.BaseServerTestCase):
|
||||
@cases.mark_specifications("Ergo")
|
||||
def testUtf8Validation(self):
|
||||
def testNonUtf8Filtering(self):
|
||||
self.connectClient(
|
||||
"bar",
|
||||
capabilities=["batch", "echo-message", "labeled-response"],
|
||||
)
|
||||
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.assertMessageMatch(
|
||||
self.getMessage(1),
|
||||
@ -38,3 +23,26 @@ class Utf8TestCase(cases.BaseServerTestCase):
|
||||
params=["PRIVMSG", "INVALID_UTF8", ANYSTR],
|
||||
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,6 +99,12 @@ class _WhoisTestMixin(cases.BaseServerTestCase):
|
||||
],
|
||||
)
|
||||
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
|
||||
# explicit configuration by the operators.
|
||||
assert False, "RPL_WHOISSPECIAL in use with default configuration"
|
||||
|
@ -27,16 +27,19 @@ class Specifications(enum.Enum):
|
||||
|
||||
@enum.unique
|
||||
class Capabilities(enum.Enum):
|
||||
ACCOUNT_NOTIFY = "account-notify"
|
||||
ACCOUNT_TAG = "account-tag"
|
||||
AWAY_NOTIFY = "away-notify"
|
||||
BATCH = "batch"
|
||||
ECHO_MESSAGE = "echo-message"
|
||||
EXTENDED_JOIN = "extended-join"
|
||||
EXTENDED_MONITOR = "extended-monitor"
|
||||
LABELED_RESPONSE = "labeled-response"
|
||||
MESSAGE_TAGS = "message-tags"
|
||||
MULTILINE = "draft/multiline"
|
||||
MULTI_PREFIX = "multi-prefix"
|
||||
SERVER_TIME = "server-time"
|
||||
SETNAME = "setname"
|
||||
STS = "sts"
|
||||
|
||||
@classmethod
|
||||
@ -49,6 +52,7 @@ class Capabilities(enum.Enum):
|
||||
|
||||
@enum.unique
|
||||
class IsupportTokens(enum.Enum):
|
||||
ACCOUNTEXTBAN = "ACCOUNTEXTBAN"
|
||||
BOT = "BOT"
|
||||
ELIST = "ELIST"
|
||||
INVEX = "INVEX"
|
||||
@ -56,6 +60,7 @@ class IsupportTokens(enum.Enum):
|
||||
MONITOR = "MONITOR"
|
||||
STATUSMSG = "STATUSMSG"
|
||||
TARGMAX = "TARGMAX"
|
||||
UTF8ONLY = "UTF8ONLY"
|
||||
WHOX = "WHOX"
|
||||
|
||||
@classmethod
|
||||
|
@ -116,7 +116,7 @@ def get_build_job(*, software_config, software_id, version_flavor):
|
||||
return None
|
||||
|
||||
return {
|
||||
"runs-on": "ubuntu-latest",
|
||||
"runs-on": "ubuntu-20.04",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Create directories",
|
||||
@ -191,7 +191,7 @@ def get_test_job(*, config, test_config, test_id, version_flavor, jobs):
|
||||
unpack = []
|
||||
|
||||
return {
|
||||
"runs-on": "ubuntu-latest",
|
||||
"runs-on": "ubuntu-20.04",
|
||||
"needs": needs,
|
||||
"steps": [
|
||||
{"uses": "actions/checkout@v2"},
|
||||
@ -263,7 +263,6 @@ def upload_steps(software_id):
|
||||
|
||||
|
||||
def generate_workflow(config: dict, version_flavor: VersionFlavor):
|
||||
|
||||
on: dict
|
||||
if version_flavor == VersionFlavor.STABLE:
|
||||
on = {"push": None, "pull_request": None}
|
||||
@ -307,7 +306,7 @@ def generate_workflow(config: dict, version_flavor: VersionFlavor):
|
||||
jobs["publish-test-results"] = {
|
||||
"name": "Publish Dashboard",
|
||||
"needs": sorted({f"test-{test_id}" for test_id in config["tests"]} & set(jobs)),
|
||||
"runs-on": "ubuntu-latest",
|
||||
"runs-on": "ubuntu-20.04",
|
||||
# the build-and-test job might be skipped, we don't need to run
|
||||
# this job then
|
||||
"if": "success() || failure()",
|
||||
|
3
mypy.ini
3
mypy.ini
@ -12,6 +12,9 @@ disallow_untyped_defs = False
|
||||
[mypy-irctest.client_tests.*]
|
||||
disallow_untyped_defs = False
|
||||
|
||||
[mypy-irctest.self_tests.*]
|
||||
disallow_untyped_defs = False
|
||||
|
||||
[mypy-defusedxml.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
|
@ -18,19 +18,23 @@ markers =
|
||||
private_chathistory
|
||||
|
||||
# capabilities
|
||||
account-notify
|
||||
account-tag
|
||||
away-notify
|
||||
batch
|
||||
echo-message
|
||||
extended-join
|
||||
extended-monitor
|
||||
labeled-response
|
||||
message-tags
|
||||
draft/multiline
|
||||
multi-prefix
|
||||
server-time
|
||||
setname
|
||||
sts
|
||||
|
||||
# isupport tokens
|
||||
ACCOUNTEXTBAN
|
||||
BOT
|
||||
ELIST
|
||||
INVEX
|
||||
@ -38,6 +42,7 @@ markers =
|
||||
PREFIX
|
||||
STATUSMSG
|
||||
TARGMAX
|
||||
UTF8ONLY
|
||||
WHOX
|
||||
|
||||
python_classes = *TestCase Test*
|
||||
|
Reference in New Issue
Block a user