Create tests (#15)

Created a tests folder which contains pytest and bats tests.
Pytest is used to login and send messages to other accounts.
Bats is used to check the log for debug messages.

This fixes #13.
This commit is contained in:
Sara Aimée Smiseth 2020-10-30 17:47:05 +01:00 committed by GitHub
parent fc45a7bab1
commit b70fcbd98e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 353 additions and 1 deletions

26
.github/workflows/test.yml vendored Normal file
View file

@ -0,0 +1,26 @@
name: Test
on:
pull_request:
branches: dev
push:
branches: dev
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Checkout submodules
uses: textbook/git-checkout-submodule-action@master
- name: install python3-venv
run: sudo apt-get install python3-venv
- name: build test image
run: docker build . -t prosody
- name: run tests
run: cd ./tests/ && ./test.bash

3
.gitignore vendored
View file

@ -1 +1,4 @@
data/*
tests/certs/
tests/venv/
tests/__pycache__/

9
.gitmodules vendored Normal file
View file

@ -0,0 +1,9 @@
[submodule "tests/bats/bats-support"]
path = tests/bats/bats-support
url = https://github.com/bats-core/bats-support.git
[submodule "tests/bats/bats-core"]
path = tests/bats/bats-core
url = https://github.com/bats-core/bats-core.git
[submodule "tests/bats/bats-assert"]
path = tests/bats/bats-assert
url = https://github.com/bats-core/bats-assert.git

@ -0,0 +1 @@
Subproject commit 0a8dd57e2cc6d4cc064b1ed6b4e79b9f7fee096f

1
tests/bats/bats-core Submodule

@ -0,0 +1 @@
Subproject commit 8fb853a6cbc0169958707381985f3cd59789ccb1

@ -0,0 +1 @@
Subproject commit d140a65044b2d6810381935ae7f0c94c7023c8c3

24
tests/docker-compose.yml Normal file
View file

@ -0,0 +1,24 @@
version: '3.7'
services:
prosody:
image: prosody
restart: unless-stopped
ports:
- "5000:5000"
- "5222:5222"
- "5223:5223"
- "5269:5269"
- "5281:5281"
environment:
DOMAIN: localhost
E2E_POLICY_WHITELIST: "admin@localhost, user1@localhost"
LOG_LEVEL: debug
PROSODY_ADMINS: "admin@localhost, admin2@localhost"
extra_hosts:
- "conference.localhost:127.0.0.1"
- "pubsub.localhost:127.0.0.1"
- "proxy.localhost:127.0.0.1"
- "upload.localhost:127.0.0.1"
volumes:
- ./certs:/usr/local/etc/prosody/certs

25
tests/readme.md Normal file
View file

@ -0,0 +1,25 @@
# Tests
## Dependencies
* docker
* docker-compose
* python 3
## Run tests
Execute [`test.bash`](test.bash).
## Upgrade python packages
The following will install the newest version of packages in requirements.txt.
``` bash
cat requirements.txt | sed 's/==.*//g' | xargs pip install -U
```
If updates are available --> update and create new version with:
``` bash
pip-chill > requirements.txt
```

3
tests/requirements.txt Normal file
View file

@ -0,0 +1,3 @@
aioxmpp==0.11.0
pip-chill==1.0.0
pytest-asyncio==0.14.0

45
tests/test.bash Executable file
View file

@ -0,0 +1,45 @@
#!/bin/bash
set -e
# generate certs for testing
generateCert() {
DOMAIN="$1"
if [[ ! -d certs/"$DOMAIN" ]] ; then
mkdir -p certs/"$DOMAIN"
cd certs/"$DOMAIN"
openssl req -x509 -newkey rsa:4096 -keyout privkey.pem -out fullchain.pem -days 365 -subj "/CN=$DOMAIN" -nodes
chmod 777 *.pem
cd ../../
fi
}
generateCert "localhost"
generateCert "conference.localhost"
generateCert "proxy.localhost"
generateCert "pubsub.localhost"
generateCert "upload.localhost"
sudo docker-compose down \
&& sudo docker-compose up -d \
\
&& sudo docker exec tests_prosody_1 /bin/bash -c "/entrypoint.sh register admin localhost 12345678" \
&& sudo docker exec tests_prosody_1 /bin/bash -c "/entrypoint.sh register user1 localhost 12345678" \
&& sudo docker exec tests_prosody_1 /bin/bash -c "/entrypoint.sh register user2 localhost 12345678" \
&& sudo docker exec tests_prosody_1 /bin/bash -c "/entrypoint.sh register user3 localhost 12345678" \
\
&& python --version \
&& python3 --version \
&& python3 -m venv venv \
&& source venv/bin/activate \
&& python --version \
&& pip --version \
&& pip install -r requirements.txt \
&& pytest \
&& deactivate \
&& sleep 5 \
&& sudo docker-compose logs \
&& ./bats/bats-core/bin/bats tests.bats
sudo docker-compose down

119
tests/test_prosody.py Normal file
View file

@ -0,0 +1,119 @@
import aiosasl
import aioxmpp
import aioxmpp.dispatcher
import asyncio
import pytest
@pytest.fixture
def client(client_username, password):
jid = aioxmpp.JID.fromstr(client_username)
client = aioxmpp.PresenceManagedClient(
jid,
aioxmpp.make_security_layer(
password,
no_verify=True
),
)
return client
@pytest.fixture
def client_with_message_dispatcher(client):
def message_received(msg):
print(msg)
print(msg.body)
assert msg.body == "Hello World!"
# obtain an instance of the service
message_dispatcher = client.summon(
aioxmpp.dispatcher.SimpleMessageDispatcher
)
# register a message callback here
message_dispatcher.register_callback(
aioxmpp.MessageType.CHAT,
None,
message_received,
)
return client
@pytest.mark.asyncio
@pytest.mark.parametrize("client_username, password", [("admin@localhost", "12345678")])
async def test_send_message_from_admin_to_user1(client):
recipient_jid = aioxmpp.JID.fromstr("user1@localhost")
async with client.connected() as stream:
msg = aioxmpp.Message(
to=recipient_jid,
type_=aioxmpp.MessageType.CHAT,
)
# None is for "default language"
msg.body[None] = "Hello World!"
await client.send(msg)
@pytest.mark.asyncio
@pytest.mark.parametrize("client_username, password", [("admin@localhost", "12345678")])
async def test_send_message_from_admin_to_user2(client):
recipient_jid = aioxmpp.JID.fromstr("user2@localhost")
async with client.connected() as stream:
msg = aioxmpp.Message(
to=recipient_jid,
type_=aioxmpp.MessageType.CHAT,
)
msg.body[None] = "Hello World!"
await client.send(msg)
@pytest.mark.asyncio
@pytest.mark.parametrize("client_username, password", [("user1@localhost", "12345678")])
async def test_send_message_from_user1_to_user2(client):
recipient_jid = aioxmpp.JID.fromstr("user2@localhost")
async with client.connected() as stream:
msg = aioxmpp.Message(
to=recipient_jid,
type_=aioxmpp.MessageType.CHAT,
)
msg.body[None] = "Hello World!"
await client.send(msg)
@pytest.mark.asyncio
@pytest.mark.parametrize("client_username, password", [("user2@localhost", "12345678")])
async def test_send_message_from_user2_to_user3(client):
recipient_jid = aioxmpp.JID.fromstr("user3@localhost")
async with client.connected() as stream:
msg = aioxmpp.Message(
to=recipient_jid,
type_=aioxmpp.MessageType.CHAT,
)
msg.body[None] = "Hello World!"
await client.send(msg)
@pytest.mark.asyncio
@pytest.mark.parametrize("client_username, password", [("user2@localhost", "12345678")])
async def test_send_message_from_user2_to_nonexisting(client):
recipient_jid = aioxmpp.JID.fromstr("nonexisting@localhost")
async with client.connected() as stream:
msg = aioxmpp.Message(
to=recipient_jid,
type_=aioxmpp.MessageType.CHAT,
)
msg.body[None] = "Hello World!"
await client.send(msg)
@pytest.mark.asyncio
@pytest.mark.parametrize("client_username, password", [("user2@localhost", "wrong password")])
async def test_can_not_log_in_with_wrong_password(client):
with pytest.raises(aiosasl.AuthenticationFailure):
recipient_jid = aioxmpp.JID.fromstr("nonexisting@localhost")
async with client.connected() as stream:
msg = aioxmpp.Message(
to=recipient_jid,
type_=aioxmpp.MessageType.CHAT,
)
msg.body[None] = "Hello World!"
await client.send(msg)

95
tests/tests.bats Normal file
View file

@ -0,0 +1,95 @@
# For tests with pipes see: https://github.com/sstephenson/bats/issues/10
load 'bats/bats-support/load'
load 'bats/bats-assert/load'
# group alternation in regex because the xml properties switch around. sometimes 'type=...' comes after 'to=...' and sometimes before
@test "Should send 5 messages" {
run bash -c "sudo docker-compose logs | grep -E \"Received\[c2s\]: <message (type='chat'|to='.*@localhost'|id=':.*') (type='chat'|to='.*@localhost'|id=':.*') (type='chat'|to='.*@localhost'|id=':.*')>\" | wc -l"
assert_success
assert_output "5"
}
@test "Should select certificate for localhost" {
run bash -c "sudo docker-compose logs | grep \"Selecting certificate /usr/local/etc/prosody/certs/localhost/fullchain.pem with key /usr/local/etc/prosody/certs/localhost/privkey.pem for localhost\" | wc -l"
assert_success
assert_output "3"
}
@test "Should select certificate for conference.localhost" {
run bash -c "sudo docker-compose logs | grep \"Selecting certificate /usr/local/etc/prosody/certs/conference.localhost/fullchain.pem with key /usr/local/etc/prosody/certs/conference.localhost/privkey.pem for conference.localhost\" | wc -l"
assert_success
assert_output "3"
}
@test "Should select certificate for proxy.localhost" {
run bash -c "sudo docker-compose logs | grep \"Selecting certificate /usr/local/etc/prosody/certs/proxy.localhost/fullchain.pem with key /usr/local/etc/prosody/certs/proxy.localhost/privkey.pem for proxy.localhost\" | wc -l"
assert_success
assert_output "3"
}
@test "Should select certificate for pubsub.localhost" {
run bash -c "sudo docker-compose logs | grep \"Selecting certificate /usr/local/etc/prosody/certs/pubsub.localhost/fullchain.pem with key /usr/local/etc/prosody/certs/pubsub.localhost/privkey.pem for pubsub.localhost\" | wc -l"
assert_success
assert_output "3"
}
@test "Should select certificate for upload.localhost" {
run bash -c "sudo docker-compose logs | grep \"Selecting certificate /usr/local/etc/prosody/certs/upload.localhost/fullchain.pem with key /usr/local/etc/prosody/certs/upload.localhost/privkey.pem for upload.localhost\" | wc -l"
assert_success
assert_output "3"
}
@test "Should log error for user with wrong password" {
run bash -c "sudo docker-compose logs | grep \"Session closed by remote with error: undefined-condition (user intervention: authentication failed: authentication aborted by user)\""
assert_success
assert_output
}
@test "Should activate s2s" {
run bash -c "sudo docker-compose logs | grep -E \"Activated service 's2s' on (\[::\]:5269|\[\*\]:5269), (\[::\]:5269|\[\*\]:5269)\""
assert_success
assert_output
}
@test "Should activate c2s" {
run bash -c "sudo docker-compose logs | grep -E \"Activated service 'c2s' on (\[::\]:5222|\[\*\]:5222), (\[::\]:5222|\[\*\]:5222)\""
assert_success
assert_output
}
@test "Should activate legacy_ssl" {
run bash -c "sudo docker-compose logs | grep -E \"Activated service 'legacy_ssl' on (\[::\]:5223|\[\*\]:5223), (\[::\]:5223|\[\*\]:5223)\""
assert_success
assert_output
}
@test "Should activate proxy65" {
run bash -c "sudo docker-compose logs | grep -E \"Activated service 'proxy65' on (\[::\]:5000|\[\*\]:5000), (\[::\]:5000|\[\*\]:5000)\""
assert_success
assert_output
}
@test "Should activate http" {
run bash -c "sudo docker-compose logs | grep -E \"Activated service 'http' on (\[::\]:5280|\[\*\]:5280), (\[::\]:5280|\[\*\]:5280)\""
assert_success
assert_output
}
@test "Should activate https" {
run bash -c "sudo docker-compose logs | grep -E \"Activated service 'https' on (\[::\]:5281|\[\*\]:5281), (\[::\]:5281|\[\*\]:5281)\""
assert_success
assert_output
}
@test "Should load module cloud_notify" {
run bash -c "sudo docker-compose logs | grep \"localhost:cloud_notify.*info.*Module loaded\""
assert_success
assert_output
}
@test "Should show upload URL" {
run bash -c "sudo docker-compose logs | grep \"URL: <https:\/\/upload.localhost:5281\/upload> - Ensure this can be reached by users\""
assert_success
assert_output
}