2017-06-21 07:08:28 +02:00
|
|
|
import json
|
2019-01-05 19:19:58 +01:00
|
|
|
import threading
|
2017-06-22 16:36:08 +02:00
|
|
|
from datetime import timedelta
|
2017-08-08 19:03:42 +02:00
|
|
|
from unittest import mock
|
2017-06-21 07:08:28 +02:00
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
from channels.channel import Group
|
|
|
|
from channels.test import ChannelTestCase, WSClient
|
2017-06-21 07:08:28 +02:00
|
|
|
from django.contrib.auth.models import AnonymousUser, Permission, User
|
|
|
|
from django.test import Client
|
2017-06-22 16:36:08 +02:00
|
|
|
from django.utils import timezone
|
2017-06-21 07:08:28 +02:00
|
|
|
|
2019-01-05 19:19:58 +01:00
|
|
|
from . import OpenKfet
|
2017-06-21 07:08:28 +02:00
|
|
|
from .consumers import OpenKfetConsumer
|
|
|
|
|
|
|
|
|
|
|
|
class OpenKfetTest(ChannelTestCase):
|
|
|
|
"""OpenKfet object unit-tests suite."""
|
|
|
|
|
|
|
|
def setUp(self):
|
2019-01-05 19:19:58 +01:00
|
|
|
self.kfet_open = OpenKfet(
|
|
|
|
cache_prefix="test_kfetopen_%s" % threading.get_ident()
|
|
|
|
)
|
|
|
|
self.addCleanup(self.kfet_open.clear_cache)
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
def test_defaults(self):
|
|
|
|
"""Default values."""
|
|
|
|
self.assertFalse(self.kfet_open.raw_open)
|
|
|
|
self.assertIsNone(self.kfet_open.last_update)
|
|
|
|
self.assertFalse(self.kfet_open.force_close)
|
|
|
|
self.assertFalse(self.kfet_open.is_open)
|
|
|
|
|
|
|
|
def test_raw_open(self):
|
|
|
|
"""Get and set raw_open; last_update is renewed."""
|
|
|
|
for raw_open in [True, False]:
|
|
|
|
prev_update = self.kfet_open.last_update
|
|
|
|
self.kfet_open.raw_open = raw_open
|
|
|
|
self.assertEqual(raw_open, self.kfet_open.raw_open)
|
|
|
|
self.assertNotEqual(prev_update, self.kfet_open.last_update)
|
|
|
|
|
|
|
|
def test_force_close(self):
|
|
|
|
"""Get and set force_close."""
|
|
|
|
for force_close in [True, False]:
|
|
|
|
self.kfet_open.force_close = force_close
|
|
|
|
self.assertEqual(force_close, self.kfet_open.force_close)
|
|
|
|
|
|
|
|
def test_is_open(self):
|
|
|
|
"""If force_close is disabled, is_open is raw_open."""
|
|
|
|
self.kfet_open.force_close = False
|
|
|
|
for raw_open in [True, False]:
|
|
|
|
self.kfet_open.raw_open = raw_open
|
|
|
|
self.assertEqual(raw_open, self.kfet_open.is_open)
|
|
|
|
|
|
|
|
def test_is_open_force_close(self):
|
|
|
|
"""If force_close is enabled, is_open is False."""
|
|
|
|
self.kfet_open.force_close = True
|
|
|
|
for raw_open in [True, False]:
|
|
|
|
self.kfet_open.raw_open = raw_open
|
|
|
|
self.assertFalse(self.kfet_open.is_open)
|
|
|
|
|
2017-06-22 16:36:08 +02:00
|
|
|
def test_status(self):
|
|
|
|
# (raw_open, force_close, expected status, expected admin)
|
|
|
|
cases = [
|
|
|
|
(False, False, OpenKfet.CLOSED, OpenKfet.CLOSED),
|
|
|
|
(False, True, OpenKfet.CLOSED, OpenKfet.CLOSED),
|
|
|
|
(True, False, OpenKfet.OPENED, OpenKfet.OPENED),
|
|
|
|
(True, True, OpenKfet.CLOSED, OpenKfet.FAKE_CLOSED),
|
|
|
|
]
|
|
|
|
for raw_open, force_close, exp_stat, exp_adm_stat in cases:
|
|
|
|
self.kfet_open.raw_open = raw_open
|
|
|
|
self.kfet_open.force_close = force_close
|
|
|
|
self.assertEqual(exp_stat, self.kfet_open.status())
|
|
|
|
self.assertEqual(exp_adm_stat, self.kfet_open.admin_status())
|
|
|
|
|
|
|
|
def test_status_unknown(self):
|
|
|
|
self.kfet_open.raw_open = True
|
|
|
|
self.kfet_open._last_update = timezone.now() - timedelta(days=30)
|
|
|
|
self.assertEqual(OpenKfet.UNKNOWN, self.kfet_open.status())
|
|
|
|
|
2017-06-21 07:08:28 +02:00
|
|
|
def test_export_user(self):
|
|
|
|
"""Export is limited for an anonymous user."""
|
|
|
|
export = self.kfet_open.export(AnonymousUser())
|
2018-10-06 12:35:49 +02:00
|
|
|
self.assertSetEqual(set(["status"]), set(export))
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
def test_export_team(self):
|
|
|
|
"""Export all values for a team member."""
|
2018-10-06 12:35:49 +02:00
|
|
|
user = User.objects.create_user("team", "", "team")
|
|
|
|
user.user_permissions.add(Permission.objects.get(codename="is_team"))
|
2017-06-21 07:08:28 +02:00
|
|
|
export = self.kfet_open.export(user)
|
2018-10-06 12:35:49 +02:00
|
|
|
self.assertSetEqual(set(["status", "admin_status", "force_close"]), set(export))
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
def test_send_ws(self):
|
2018-10-06 12:35:49 +02:00
|
|
|
Group("kfet.open.base").add("test.open.base")
|
|
|
|
Group("kfet.open.team").add("test.open.team")
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
self.kfet_open.send_ws()
|
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
recv_base = self.get_next_message("test.open.base", require=True)
|
|
|
|
base = json.loads(recv_base["text"])
|
|
|
|
self.assertSetEqual(set(["status"]), set(base))
|
2017-06-21 07:08:28 +02:00
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
recv_admin = self.get_next_message("test.open.team", require=True)
|
|
|
|
admin = json.loads(recv_admin["text"])
|
|
|
|
self.assertSetEqual(set(["status", "admin_status", "force_close"]), set(admin))
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
|
|
|
|
class OpenKfetViewsTest(ChannelTestCase):
|
|
|
|
"""OpenKfet views unit-tests suite."""
|
|
|
|
|
|
|
|
def setUp(self):
|
2017-08-08 19:03:42 +02:00
|
|
|
# Need this (and here) because of '<client>.login' in setUp
|
2018-10-06 12:35:49 +02:00
|
|
|
patcher_messages = mock.patch("gestioncof.signals.messages")
|
2017-08-08 19:03:42 +02:00
|
|
|
patcher_messages.start()
|
|
|
|
self.addCleanup(patcher_messages.stop)
|
|
|
|
|
2017-06-21 07:08:28 +02:00
|
|
|
# get some permissions
|
|
|
|
perms = {
|
2018-10-06 12:35:49 +02:00
|
|
|
"kfet.is_team": Permission.objects.get(codename="is_team"),
|
|
|
|
"kfet.can_force_close": Permission.objects.get(codename="can_force_close"),
|
2017-06-21 07:08:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# authenticated user and its client
|
2018-10-06 12:35:49 +02:00
|
|
|
self.u = User.objects.create_user("user", "", "user")
|
2017-06-21 07:08:28 +02:00
|
|
|
self.c = Client()
|
2018-10-06 12:35:49 +02:00
|
|
|
self.c.login(username="user", password="user")
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
# team user and its clients
|
2018-10-06 12:35:49 +02:00
|
|
|
self.t = User.objects.create_user("team", "", "team")
|
|
|
|
self.t.user_permissions.add(perms["kfet.is_team"])
|
2017-06-21 07:08:28 +02:00
|
|
|
self.c_t = Client()
|
2018-10-06 12:35:49 +02:00
|
|
|
self.c_t.login(username="team", password="team")
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
# admin user and its client
|
2018-10-06 12:35:49 +02:00
|
|
|
self.a = User.objects.create_user("admin", "", "admin")
|
2017-06-21 07:08:28 +02:00
|
|
|
self.a.user_permissions.add(
|
2018-10-06 12:35:49 +02:00
|
|
|
perms["kfet.is_team"], perms["kfet.can_force_close"]
|
2017-06-21 07:08:28 +02:00
|
|
|
)
|
|
|
|
self.c_a = Client()
|
2018-10-06 12:35:49 +02:00
|
|
|
self.c_a.login(username="admin", password="admin")
|
2017-06-21 07:08:28 +02:00
|
|
|
|
2019-01-05 19:19:58 +01:00
|
|
|
self.kfet_open = OpenKfet(
|
|
|
|
cache_prefix="test_kfetopen_%s" % threading.get_ident()
|
|
|
|
)
|
|
|
|
self.addCleanup(self.kfet_open.clear_cache)
|
|
|
|
|
|
|
|
views_patcher = mock.patch("kfet.open.views.kfet_open", self.kfet_open)
|
|
|
|
views_patcher.start()
|
|
|
|
self.addCleanup(views_patcher.stop)
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
def test_door(self):
|
|
|
|
"""Edit raw_status."""
|
|
|
|
for sent, expected in [(1, True), (0, False)]:
|
2018-10-06 12:35:49 +02:00
|
|
|
resp = Client().post(
|
|
|
|
"/k-fet/open/raw_open", {"raw_open": sent, "token": "plop"}
|
|
|
|
)
|
2017-06-21 07:08:28 +02:00
|
|
|
self.assertEqual(200, resp.status_code)
|
2019-01-05 19:19:58 +01:00
|
|
|
self.assertEqual(expected, self.kfet_open.raw_open)
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
def test_force_close(self):
|
|
|
|
"""Edit force_close."""
|
|
|
|
for sent, expected in [(1, True), (0, False)]:
|
2018-10-06 12:35:49 +02:00
|
|
|
resp = self.c_a.post("/k-fet/open/force_close", {"force_close": sent})
|
2017-06-21 07:08:28 +02:00
|
|
|
self.assertEqual(200, resp.status_code)
|
2019-01-05 19:19:58 +01:00
|
|
|
self.assertEqual(expected, self.kfet_open.force_close)
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
def test_force_close_forbidden(self):
|
|
|
|
"""Can't edit force_close without kfet.can_force_close permission."""
|
|
|
|
clients = [Client(), self.c, self.c_t]
|
|
|
|
for client in clients:
|
2018-10-06 12:35:49 +02:00
|
|
|
resp = client.post("/k-fet/open/force_close", {"force_close": 0})
|
2017-06-21 07:08:28 +02:00
|
|
|
self.assertEqual(403, resp.status_code)
|
|
|
|
|
|
|
|
|
|
|
|
class OpenKfetConsumerTest(ChannelTestCase):
|
|
|
|
"""OpenKfet consumer unit-tests suite."""
|
|
|
|
|
|
|
|
def test_standard_user(self):
|
|
|
|
"""Lambda user is added to kfet.open.base group."""
|
|
|
|
# setup anonymous client
|
|
|
|
c = WSClient()
|
|
|
|
|
|
|
|
# connect
|
2018-10-06 12:35:49 +02:00
|
|
|
c.send_and_consume(
|
|
|
|
"websocket.connect", path="/ws/k-fet/open", fail_on_none=True
|
|
|
|
)
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
# initialization data is replied on connection
|
|
|
|
self.assertIsNotNone(c.receive())
|
|
|
|
|
|
|
|
# client belongs to the 'kfet.open' group...
|
2018-10-06 12:35:49 +02:00
|
|
|
OpenKfetConsumer.group_send("kfet.open.base", {"test": "plop"})
|
|
|
|
self.assertEqual(c.receive(), {"test": "plop"})
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
# ...but not to the 'kfet.open.admin' one
|
2018-10-06 12:35:49 +02:00
|
|
|
OpenKfetConsumer.group_send("kfet.open.team", {"test": "plop"})
|
2017-06-21 07:08:28 +02:00
|
|
|
self.assertIsNone(c.receive())
|
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
@mock.patch("gestioncof.signals.messages")
|
2017-08-08 19:03:42 +02:00
|
|
|
def test_team_user(self, mock_messages):
|
2017-06-21 07:08:28 +02:00
|
|
|
"""Team user is added to kfet.open.team group."""
|
|
|
|
# setup team user and its client
|
2018-10-06 12:35:49 +02:00
|
|
|
t = User.objects.create_user("team", "", "team")
|
|
|
|
t.user_permissions.add(Permission.objects.get(codename="is_team"))
|
2017-06-21 07:08:28 +02:00
|
|
|
c = WSClient()
|
|
|
|
c.force_login(t)
|
|
|
|
|
|
|
|
# connect
|
2018-10-06 12:35:49 +02:00
|
|
|
c.send_and_consume(
|
|
|
|
"websocket.connect", path="/ws/k-fet/open", fail_on_none=True
|
|
|
|
)
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
# initialization data is replied on connection
|
|
|
|
self.assertIsNotNone(c.receive())
|
|
|
|
|
|
|
|
# client belongs to the 'kfet.open.admin' group...
|
2018-10-06 12:35:49 +02:00
|
|
|
OpenKfetConsumer.group_send("kfet.open.team", {"test": "plop"})
|
|
|
|
self.assertEqual(c.receive(), {"test": "plop"})
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
# ... but not to the 'kfet.open' one
|
2018-10-06 12:35:49 +02:00
|
|
|
OpenKfetConsumer.group_send("kfet.open.base", {"test": "plop"})
|
2017-06-21 07:08:28 +02:00
|
|
|
self.assertIsNone(c.receive())
|
|
|
|
|
|
|
|
|
|
|
|
class OpenKfetScenarioTest(ChannelTestCase):
|
|
|
|
"""OpenKfet functionnal tests suite."""
|
|
|
|
|
|
|
|
def setUp(self):
|
2017-08-08 19:03:42 +02:00
|
|
|
# Need this (and here) because of '<client>.login' in setUp
|
2018-10-06 12:35:49 +02:00
|
|
|
patcher_messages = mock.patch("gestioncof.signals.messages")
|
2017-08-08 19:03:42 +02:00
|
|
|
patcher_messages.start()
|
|
|
|
self.addCleanup(patcher_messages.stop)
|
|
|
|
|
2017-06-21 07:08:28 +02:00
|
|
|
# anonymous client (for views)
|
|
|
|
self.c = Client()
|
|
|
|
# anonymous client (for websockets)
|
|
|
|
self.c_ws = WSClient()
|
|
|
|
|
|
|
|
# root user
|
2018-10-06 12:35:49 +02:00
|
|
|
self.r = User.objects.create_superuser("root", "", "root")
|
2017-06-21 07:08:28 +02:00
|
|
|
# its client (for views)
|
|
|
|
self.r_c = Client()
|
2018-10-06 12:35:49 +02:00
|
|
|
self.r_c.login(username="root", password="root")
|
2017-06-21 07:08:28 +02:00
|
|
|
# its client (for websockets)
|
|
|
|
self.r_c_ws = WSClient()
|
|
|
|
self.r_c_ws.force_login(self.r)
|
|
|
|
|
2019-01-05 19:19:58 +01:00
|
|
|
self.kfet_open = OpenKfet(
|
|
|
|
cache_prefix="test_kfetopen_%s" % threading.get_ident()
|
|
|
|
)
|
|
|
|
self.addCleanup(self.kfet_open.clear_cache)
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
def ws_connect(self, ws_client):
|
|
|
|
ws_client.send_and_consume(
|
2018-10-06 12:35:49 +02:00
|
|
|
"websocket.connect", path="/ws/k-fet/open", fail_on_none=True
|
2017-06-21 07:08:28 +02:00
|
|
|
)
|
|
|
|
return ws_client.receive(json=True)
|
|
|
|
|
|
|
|
def test_scenario_0(self):
|
|
|
|
"""Clients connect."""
|
|
|
|
# test for anonymous user
|
|
|
|
msg = self.ws_connect(self.c_ws)
|
2018-10-06 12:35:49 +02:00
|
|
|
self.assertSetEqual(set(["status"]), set(msg))
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
# test for root user
|
|
|
|
msg = self.ws_connect(self.r_c_ws)
|
2018-10-06 12:35:49 +02:00
|
|
|
self.assertSetEqual(set(["status", "admin_status", "force_close"]), set(msg))
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
def test_scenario_1(self):
|
|
|
|
"""Clients connect, door opens, enable force close."""
|
|
|
|
self.ws_connect(self.c_ws)
|
|
|
|
self.ws_connect(self.r_c_ws)
|
|
|
|
|
|
|
|
# door sent "I'm open!"
|
2018-10-06 12:35:49 +02:00
|
|
|
self.c.post("/k-fet/open/raw_open", {"raw_open": True, "token": "plop"})
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
# anonymous user agree
|
|
|
|
msg = self.c_ws.receive(json=True)
|
2018-10-06 12:35:49 +02:00
|
|
|
self.assertEqual(OpenKfet.OPENED, msg["status"])
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
# root user too
|
|
|
|
msg = self.r_c_ws.receive(json=True)
|
2018-10-06 12:35:49 +02:00
|
|
|
self.assertEqual(OpenKfet.OPENED, msg["status"])
|
|
|
|
self.assertEqual(OpenKfet.OPENED, msg["admin_status"])
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
# admin says "no it's closed"
|
2018-10-06 12:35:49 +02:00
|
|
|
self.r_c.post("/k-fet/open/force_close", {"force_close": True})
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
# so anonymous user see it's closed
|
|
|
|
msg = self.c_ws.receive(json=True)
|
2018-10-06 12:35:49 +02:00
|
|
|
self.assertEqual(OpenKfet.CLOSED, msg["status"])
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
# root user too
|
|
|
|
msg = self.r_c_ws.receive(json=True)
|
2018-10-06 12:35:49 +02:00
|
|
|
self.assertEqual(OpenKfet.CLOSED, msg["status"])
|
2017-06-21 07:08:28 +02:00
|
|
|
# but root knows things
|
2018-10-06 12:35:49 +02:00
|
|
|
self.assertEqual(OpenKfet.FAKE_CLOSED, msg["admin_status"])
|
|
|
|
self.assertTrue(msg["force_close"])
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
def test_scenario_2(self):
|
|
|
|
"""Starting falsely closed, clients connect, disable force close."""
|
2019-01-05 19:19:58 +01:00
|
|
|
self.kfet_open.raw_open = True
|
|
|
|
self.kfet_open.force_close = True
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
msg = self.ws_connect(self.c_ws)
|
2018-10-06 12:35:49 +02:00
|
|
|
self.assertEqual(OpenKfet.CLOSED, msg["status"])
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
msg = self.ws_connect(self.r_c_ws)
|
2018-10-06 12:35:49 +02:00
|
|
|
self.assertEqual(OpenKfet.CLOSED, msg["status"])
|
|
|
|
self.assertEqual(OpenKfet.FAKE_CLOSED, msg["admin_status"])
|
|
|
|
self.assertTrue(msg["force_close"])
|
2017-06-21 07:08:28 +02:00
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
self.r_c.post("/k-fet/open/force_close", {"force_close": False})
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
msg = self.c_ws.receive(json=True)
|
2018-10-06 12:35:49 +02:00
|
|
|
self.assertEqual(OpenKfet.OPENED, msg["status"])
|
2017-06-21 07:08:28 +02:00
|
|
|
|
|
|
|
msg = self.r_c_ws.receive(json=True)
|
2018-10-06 12:35:49 +02:00
|
|
|
self.assertEqual(OpenKfet.OPENED, msg["status"])
|
|
|
|
self.assertEqual(OpenKfet.OPENED, msg["admin_status"])
|
|
|
|
self.assertFalse(msg["force_close"])
|