Commit ad2f0586 authored by Elena Grandi's avatar Elena Grandi

flake8

parent cf217ce8
......@@ -29,7 +29,7 @@ setup(
'Framework :: Twisted',
'Intended Audience :: Education',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)',
'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)', # noqa: E501
'Operating System :: POSIX :: Linux',
'Programming Language :: Python :: 3 :: Only',
'Topic :: System :: Systems Administration',
......
......@@ -31,6 +31,7 @@ class TestDataSourceMixin:
Start a data source on setUp and stop it when StopTest is posted on the
event hub
"""
def setUp(self, *args, **kw):
super().setUp(*args, **kw)
self.event_hub = events.Hub()
......@@ -50,6 +51,7 @@ class FussTestNetwork:
Raise SkipTest unless the fuss-test-network VMs are up and running
"""
import socket
try:
conn = socket.create_connection(("192.168.123.2", 22), timeout=0.1)
except (ConnectionRefusedError, OSError):
......@@ -60,12 +62,16 @@ class FussTestNetwork:
def write_inventory(self, fd, group_name="test"):
print("[{}]".format(group_name), file=fd)
for name, ip in (
("test1", "192.168.123.2"),
("test2", "192.168.123.3"),
):
print(('{name} ansible_host={ip} ansible_user=root'
' ansible_ssh_extra_args="-oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no"'
).format(name=name, ip=ip), file=fd)
("test1", "192.168.123.2"),
("test2", "192.168.123.3"),
):
print(
(
'{name} ansible_host={ip} ansible_user=root'
' ansible_ssh_extra_args="-oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no"' # noqa: E501
).format(name=name, ip=ip),
file=fd,
)
class InotifyTestCase(tornado.testing.AsyncTestCase):
......@@ -80,11 +86,13 @@ class InotifyTestCase(tornado.testing.AsyncTestCase):
# AsyncHTTPClientWithCookies implementation
#
class JarRequestAdapter:
"""
Work around stdlib's cookie jar having a stupidly limited API that works
only with stdlib request/response objects
"""
def __init__(self, tornado_request):
self.tornado_request = tornado_request
self.unverifiable = False
......@@ -105,11 +113,13 @@ class JarResponseAdapter:
Work around stdlib's cookie jar having a stupidly limited API that works
only with stdlib request/response objects
"""
def __init__(self, tornado_response):
self.tornado_response = tornado_response
def info(self):
from email.message import Message
res = Message()
for name, value in self.tornado_response.headers.get_all():
res.add_header(name, value)
......@@ -120,6 +130,7 @@ class AsyncHTTPClientWithCookies:
"""
Wrapper for AsyncHTTPClient which handles cookies between requests
"""
def __init__(self, client):
self.client = client
self.jar = http.cookiejar.CookieJar()
......@@ -135,7 +146,9 @@ class AsyncHTTPClientWithCookies:
if self.xsrf_token is not None:
request.headers["X-XSRFToken"] = self.xsrf_token
response = await self.client.fetch(request, raise_error=raise_error)
self.jar.extract_cookies(JarResponseAdapter(response), JarRequestAdapter(request))
self.jar.extract_cookies(
JarResponseAdapter(response), JarRequestAdapter(request)
)
return response
def get_cookie(self, name):
......
......@@ -8,7 +8,7 @@ import manager.playbook as pb
from .common import (
GatherEvents,
FussTestNetwork,
)
)
from manager import events
from manager.config import Config
from manager.compat import isoparse
......@@ -18,13 +18,18 @@ class TestPlaybook(AsyncTestCase):
"""
Test running ansible playbooks
"""
def setUp(self, *args, **kw):
super().setUp(*args, **kw)
self.workdir = tempfile.TemporaryDirectory()
self.config = Config()
self.config.path_ansible_inventory = os.path.join(self.workdir.name, "inventory")
self.config.path_ansible_inventory = os.path.join(
self.workdir.name, "inventory"
)
self.config.path_playbooks = self.workdir.name
self.config.playbook_log_dir = os.path.join(self.workdir.name, "playbook.log")
self.config.playbook_log_dir = os.path.join(
self.workdir.name, "playbook.log"
)
self.event_hub = events.Hub()
self.ansible = pb.Ansible(self.event_hub, self.config)
......@@ -46,19 +51,25 @@ class TestPlaybook(AsyncTestCase):
write_playbook("subdir/test.yaml", "Test Subdir")
res = self.ansible.list_playbooks()
self.assertEqual(res, [
{"name": "subdir/test.yaml", "title": "Test Subdir"},
{"name": "test1.yaml", "title": "Test 1"},
{"name": "test1.yml", "title": "Test 1 yml"},
{"name": "test2.yaml", "title": "Test 2"},
])
self.assertEqual(
res,
[
{"name": "subdir/test.yaml", "title": "Test Subdir"},
{"name": "test1.yaml", "title": "Test 1"},
{"name": "test1.yml", "title": "Test 1 yml"},
{"name": "test2.yaml", "title": "Test 2"},
],
)
@gen_test(timeout=10)
async def test_run_playbook(self):
net = FussTestNetwork()
with open(os.path.join(self.config.path_playbooks, "test.yaml"), "wt") as fd:
fd.write("""
with open(
os.path.join(self.config.path_playbooks, "test.yaml"), "wt"
) as fd:
fd.write(
"""
---
- name: Test
hosts: all
......@@ -67,14 +78,14 @@ class TestPlaybook(AsyncTestCase):
ping:
- name: Echo
command: echo Test
""")
"""
)
with open(self.config.path_ansible_inventory, "wt") as fd:
net.write_inventory(fd)
evts = GatherEvents(
self.event_hub,
[events.HostEvent, events.AnsibleEvent]
self.event_hub, [events.HostEvent, events.AnsibleEvent]
)
await self.ansible.run_playbook("test.yaml")
......@@ -85,26 +96,29 @@ class TestPlaybook(AsyncTestCase):
self.assertIsInstance(evt, events.AnsiblePlaybookEvent)
self.assertEqual(evt.playbook, "test.yaml")
results = evt.results
self.assertEqual(results["stats"], {
"test1": {
'changed': 1,
'failures': 0,
'ok': 3,
'skipped': 0,
'unreachable': 0,
'ignored': 0,
'rescued': 0,
self.assertEqual(
results["stats"],
{
"test1": {
'changed': 1,
'failures': 0,
'ok': 3,
'skipped': 0,
'unreachable': 0,
'ignored': 0,
'rescued': 0,
},
"test2": {
'changed': 1,
'failures': 0,
'ok': 3,
'skipped': 0,
'unreachable': 0,
'ignored': 0,
'rescued': 0,
"test2": {
'changed': 1,
'failures': 0,
'ok': 3,
'skipped': 0,
'unreachable': 0,
'ignored': 0,
'rescued': 0,
},
})
},
)
plays = results["plays"]
self.assertEqual(len(plays), 1)
play = plays[0]
......@@ -134,7 +148,9 @@ class TestPlaybook(AsyncTestCase):
start = isoparse(play["play"]["duration"]["start"])
end = isoparse(play["play"]["duration"]["end"])
logs = list(self.ansible.playbook_log.list_month(start.year, start.month))
logs = list(
self.ansible.playbook_log.list_month(start.year, start.month)
)
self.assertEqual(len(logs), 1)
self.assertEqual(logs[0]["playbook"], "test.yaml")
self.assertEqual(logs[0]["start"], start.timestamp())
......@@ -147,6 +163,7 @@ class TestSetup(AsyncTestCase):
"""
Test running ansible data collection
"""
def setUp(self, *args, **kw):
super().setUp(*args, **kw)
self.event_hub = events.Hub()
......@@ -154,21 +171,20 @@ class TestSetup(AsyncTestCase):
@gen_test
async def test_run_playbook_fail(self):
with tempfile.NamedTemporaryFile("wt") as inventory:
inventory.write("""
inventory.write(
"""
[tests]
host.invalid
another.invalid
""")
"""
)
inventory.flush()
config = Config()
config.path_ansible_inventory = inventory.name
ansible = pb.Ansible(self.event_hub, config)
evts = GatherEvents(
self.event_hub,
[events.HostEvent]
)
evts = GatherEvents(self.event_hub, [events.HostEvent])
await ansible.gather_facts('host.invalid,another.invalid')
self.assertEqual(len(evts.gathered), 2)
......@@ -184,23 +200,22 @@ another.invalid
@gen_test
async def test_run_playbook_success(self):
net = FussTestNetwork()
net = FussTestNetwork() # noqa: F841
with tempfile.NamedTemporaryFile("wt") as inventory:
inventory.write("""
inventory.write(
"""
[tests]
192.168.123.2
192.168.123.3
""")
"""
)
inventory.flush()
config = Config()
config.path_ansible_inventory = inventory.name
ansible = pb.Ansible(self.event_hub, config)
evts = GatherEvents(
self.event_hub,
[events.HostEvent]
)
evts = GatherEvents(self.event_hub, [events.HostEvent])
await ansible.gather_facts('192.168.123.2,192.168.123.3')
self.assertEqual(len(evts.gathered), 2)
......@@ -219,14 +234,12 @@ another.invalid
config = Config()
ansible = pb.Ansible(self.event_hub, config)
evts = GatherEvents(
self.event_hub,
[events.HostEvent]
)
evts = GatherEvents(self.event_hub, [events.HostEvent])
with mock.patch(
"manager.playbook.FactsCollector.get_cmdline",
return_value=["cat", "tests/data/ansible_setup.txt"]):
"manager.playbook.FactsCollector.get_cmdline",
return_value=["cat", "tests/data/ansible_setup.txt"],
):
await ansible.gather_facts()
self.assertEqual(len(evts.gathered), 3)
......@@ -242,7 +255,9 @@ another.invalid
facts = evts.gathered[1].facts
self.assertIn("ansible_facts", facts)
self.assertIn('epoch', facts['ansible_facts']['ansible_date_time'])
self.assertIn('fuss_server_upgrade', facts['ansible_facts']['ansible_local'])
self.assertIn(
'fuss_server_upgrade', facts['ansible_facts']['ansible_local']
)
self.assertIsInstance(evts.gathered[2], events.HostFactsFailed)
self.assertEqual(evts.gathered[2].name, "invalid")
......@@ -253,6 +268,7 @@ class TestWakeOnLan(AsyncTestCase):
"""
Test running ansible wakeonlan module
"""
def setUp(self, *args, **kw):
super().setUp(*args, **kw)
self.event_hub = events.Hub()
......@@ -261,6 +277,8 @@ class TestWakeOnLan(AsyncTestCase):
@gen_test
async def test_run_playbook(self):
await self.ansible.wake_on_lan(["02:00:00:01:02:01", "02:00:00:01:02:02"])
await self.ansible.wake_on_lan(
["02:00:00:01:02:01", "02:00:00:01:02:02"]
)
# no output is saved, and there is really nothing to test
# (unless we check the network for the magic packet).
......@@ -2,7 +2,11 @@ import tempfile
from unittest import mock
import contextlib
from tornado.testing import AsyncTestCase, gen_test
from manager.web.session import SessionManager, MemorySessionManager, FilesystemSessionManager
from manager.web.session import (
SessionManager,
MemorySessionManager,
FilesystemSessionManager,
)
from manager.config import MockConfig
......@@ -88,7 +92,9 @@ class SessionTestCommon:
self.assertEqual(session1.time_saved, 200)
class TestMemorySessionManager(SessionTestMixin, SessionTestCommon, AsyncTestCase):
class TestMemorySessionManager(
SessionTestMixin, SessionTestCommon, AsyncTestCase
):
@contextlib.contextmanager
def session_manager(self) -> SessionManager:
config = MockConfig()
......@@ -101,7 +107,9 @@ class TestMemorySessionManager(SessionTestMixin, SessionTestCommon, AsyncTestCas
self.assertTrue(await MemorySessionManager.is_viable(config))
class TestFilesystemSessionManager(SessionTestMixin, SessionTestCommon, AsyncTestCase):
class TestFilesystemSessionManager(
SessionTestMixin, SessionTestCommon, AsyncTestCase
):
@contextlib.contextmanager
def session_manager(self) -> SessionManager:
config = MockConfig()
......
from unittest import TestCase, SkipTest
from unittest import mock
from manager.signing import HAVE_SIGNING, loads, dumps, BadSignature, SignatureExpired
from manager.signing import (
HAVE_SIGNING,
loads,
dumps,
BadSignature,
SignatureExpired,
)
import datetime
......@@ -47,9 +53,19 @@ class TestSigning(TestCase):
loads(token, key="testkey", salt="foo", max_age=100)
with mock.patch("django.core.signing.time.time", return_value=1100):
res = loads(token, key="testkey", salt="foo", max_age=datetime.timedelta(seconds=100))
res = loads(
token,
key="testkey",
salt="foo",
max_age=datetime.timedelta(seconds=100),
)
self.assertEqual(res, {"test": 1})
with mock.patch("django.core.signing.time.time", return_value=1101):
with self.assertRaises(SignatureExpired):
loads(token, key="testkey", salt="foo", max_age=datetime.timedelta(seconds=100))
loads(
token,
key="testkey",
salt="foo",
max_age=datetime.timedelta(seconds=100),
)
......@@ -10,7 +10,7 @@ from .common import (
StopTest,
GatherEvents,
InotifyTestCase,
)
)
from manager import compat
......@@ -18,12 +18,11 @@ class TestArpwatchDataSource(TestDataSourceMixin, InotifyTestCase):
"""
test a data source that checks an arpwatch file.
"""
def make_datasource(self):
config = Config()
return ds.ArpwatchDataSource(
event_hub=self.event_hub,
config=config,
datafile=self.tmpfile.name
event_hub=self.event_hub, config=config, datafile=self.tmpfile.name
)
def setUp(self, *args, **kw):
......@@ -42,16 +41,15 @@ class TestArpwatchDataSource(TestDataSourceMixin, InotifyTestCase):
def test():
yield from self.ds.wait_until_started()
with open(self.tmpfile.name, "wb") as out:
out.write(b"52:54:00:5e:76:10 192.168.7.241 1549968902 server eth0\n")
out.write(b"52:54:00:4e:b3:61 192.168.7.1 1549968902 eth0\n")
out.write(b"52:54:00:5e:76:10 192.168.7.241 1549968902 server eth0\n") # noqa: E501
out.write(b"52:54:00:4e:b3:61 192.168.7.1 1549968902 eth0\n") # noqa: E501
os.fdatasync(out.fileno())
# Wait until changes start to be reported
yield from events.received_first
yield from self.event_hub.publish(StopTest(None))
await asyncio.gather(
compat.create_task(self.ds.run()),
compat.create_task(test()),
compat.create_task(self.ds.run()), compat.create_task(test()),
)
events = events.gathered
......
......@@ -38,10 +38,8 @@ class TestWebAPI(ApplicationTestBase):
url += "?" + urlencode(data)
headers = {}
response = await self.http_client.fetch(
self.get_url(url),
headers=headers,
raise_error=False,
)
self.get_url(url), headers=headers, raise_error=False,
)
content_type = response.headers.get("Content-Type")
self.assertIn("application/json", content_type)
self.assertEqual(response.code, expected_code)
......@@ -58,8 +56,8 @@ class TestWebAPI(ApplicationTestBase):
method="POST",
headers=headers,
body=body,
raise_error=False
)
raise_error=False,
)
content_type = response.headers.get("Content-Type")
if "application/json" not in content_type:
print("*** Response with unexpected content type", content_type)
......@@ -71,9 +69,7 @@ class TestWebAPI(ApplicationTestBase):
async def api_login(self, username):
# Make a GET request to get XSRF cookie
await self.http_client.fetch(
self.get_url("/login"),
method="GET",
raise_error=True
self.get_url("/login"), method="GET", raise_error=True
)
self.http_client.enable_xsrf_header()
if not username:
......@@ -81,11 +77,8 @@ class TestWebAPI(ApplicationTestBase):
response = await self.http_client.fetch(
self.get_url("/login"),
method="POST",
body=urlencode({
"username": username,
"password": username,
}),
raise_error=True
body=urlencode({"username": username, "password": username}),
raise_error=True,
)
return response.code == 200
......@@ -100,10 +93,7 @@ class TestWebAPI(ApplicationTestBase):
await self.api_login(user)
with mock.patch("time.time", return_value=100):
res = await self.api_get("ping")
self.assertEqual(res, {
"pong": True,
"time": 100,
})
self.assertEqual(res, {"pong": True, "time": 100})
@gen_test
async def test_async_ping(self):
......@@ -115,35 +105,38 @@ class TestWebAPI(ApplicationTestBase):
await self.api_login(user)
with mock.patch("time.time", return_value=100):
res = await self.api_get("async_ping")
self.assertEqual(res, {
"pong": True,
"time": 100,
})
self.assertEqual(res, {"pong": True, "time": 100})
@gen_test
async def test_whoami(self):
sid = "1234567890"
with mock.patch("manager.web.session.SessionManager._get_random_string", return_value=sid):
with mock.patch(
"manager.web.session.SessionManager._get_random_string",
return_value=sid,
):
with mock.patch("time.time", return_value=100):
res = await self.api_get("whoami")
self.assertEqual(res, {
"user": None,
"time": 100,
})
self.assertEqual(res, {"user": None, "time": 100})
await self.api_login('root')
with mock.patch("time.time", return_value=100):
res = await self.api_get("whoami")
self.assertEqual(res, {
"user": {
'name': 'root',
'display_name': 'Root',
'id': 452,
'groups': [{'id': 452, 'name': 'root'}, {'id': 521, 'name': 'admin'}],
self.assertEqual(
res,
{
"user": {
'name': 'root',
'display_name': 'Root',
'id': 452,
'groups': [
{'id': 452, 'name': 'root'},
{'id': 521, 'name': 'admin'},
],
},
"time": 100,
},
"time": 100,
})
)
@gen_test
async def test_machines(self):
......@@ -164,57 +157,61 @@ class TestWebAPI(ApplicationTestBase):
await self.api_login(user)
with mock.patch("time.time", return_value=100):
res = await self.api_get(
"machine/11:22:33:44:55:66",
expected_code=403
)
"machine/11:22:33:44:55:66", expected_code=403
)
for user in ['admin', 'user']:
await self.api_login(user)
with mock.patch("time.time", return_value=100):
res = await self.api_get(
"machine/11:22:33:44:55:66",
expected_code=404
)
self.assertEqual(res, {
"code": 404,
"error": True,
"message": "machine not found",
"time": 100,
})
"machine/11:22:33:44:55:66", expected_code=404
)
self.assertEqual(
res,
{
"code": 404,
"error": True,
"message": "machine not found",
"time": 100,
},
)
@gen_test
async def test_operation(self):
# Make a GET request to get XSRF cookie
await self.http_client.fetch(
self.get_url("/login"),
method="GET",
raise_error=True
self.get_url("/login"), method="GET", raise_error=True
)
self.http_client.enable_xsrf_header()
with mock.patch("time.time", return_value=100):
res = await self.api_post(
"operation",
data={"op": {"name": "Noop"}}
)
self.assertEqual(res, {
"time": 100,
})
"operation", data={"op": {"name": "Noop"}}
)
self.assertEqual(res, {"time": 100})
@gen_test
async def test_auth_forward(self):
from manager import signing
if not signing.HAVE_SIGNING:
raise SkipTest("signing module is not available")
token = signing.dumps({
"url": "/test",
"user": {
"name": "test",
"id": 2,
"display_name": "Test User",
"groups": [{"name": "test", "id": 1}, {"name": "users", "id": 2}],
token = signing.dumps(
{
"url": "/test",
"user": {
"name": "test",
"id": 2,
"display_name": "Test User",
"groups": [
{"name": "test", "id": 1},
{"name": "users", "id": 2},