From feb2294a7e5da7bed9049b87daba3ace8186105f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C4=93teris=20Caune?= Date: Mon, 9 May 2016 17:29:41 +0300 Subject: [PATCH] Tests for team access. --- hc/accounts/tests/test_profile.py | 18 ++++++++-------- hc/accounts/tests/test_switch_team.py | 30 +++++++-------------------- hc/accounts/views.py | 8 ++++++- hc/api/tests/test_list_checks.py | 15 +++++++------- hc/front/tests/test_add_channel.py | 23 ++++++++++++++++++++ hc/front/tests/test_add_check.py | 9 ++++++++ hc/front/tests/test_channel_checks.py | 9 ++++++++ hc/front/tests/test_log.py | 9 ++++++++ hc/front/tests/test_my_checks.py | 7 ++++--- hc/front/tests/test_remove_channel.py | 7 +++++++ hc/front/tests/test_remove_check.py | 9 ++++++++ hc/front/tests/test_update_channel.py | 12 +++++++++++ hc/front/tests/test_update_name.py | 12 +++++++++++ hc/front/tests/test_update_timeout.py | 12 +++++++++++ hc/test.py | 18 +++++++++++++--- 15 files changed, 152 insertions(+), 46 deletions(-) diff --git a/hc/accounts/tests/test_profile.py b/hc/accounts/tests/test_profile.py index 97cabc55..9ef12cd1 100644 --- a/hc/accounts/tests/test_profile.py +++ b/hc/accounts/tests/test_profile.py @@ -62,13 +62,16 @@ class ProfileTestCase(BaseTestCase): def test_it_adds_team_member(self): self.client.login(username="alice@example.org", password="password") - form = {"invite_team_member": "1", "email": "bob@example.org"} + form = {"invite_team_member": "1", "email": "frank@example.org"} r = self.client.post("/accounts/profile/", form) assert r.status_code == 200 - member = self.alice.profile.member_set.get() + member_emails = set() + for member in self.alice.profile.member_set.all(): + member_emails.add(member.user.email) - self.assertEqual(member.user.email, "bob@example.org") + self.assertEqual(len(member_emails), 2) + self.assertTrue("frank@example.org" in member_emails) # And an email should have been sent subj = ('You have been invited to join' @@ -78,18 +81,15 @@ class ProfileTestCase(BaseTestCase): def test_it_removes_team_member(self): self.client.login(username="alice@example.org", password="password") - bob = User(username="bob", email="bob@example.org") - bob.save() - - m = Member(team=self.alice.profile, user=bob) - m.save() - form = {"remove_team_member": "1", "email": "bob@example.org"} r = self.client.post("/accounts/profile/", form) assert r.status_code == 200 self.assertEqual(Member.objects.count(), 0) + self.bobs_profile.refresh_from_db() + self.assertEqual(self.bobs_profile.current_team, None) + def test_it_sets_team_name(self): self.client.login(username="alice@example.org", password="password") diff --git a/hc/accounts/tests/test_switch_team.py b/hc/accounts/tests/test_switch_team.py index c9e37f39..6bac3835 100644 --- a/hc/accounts/tests/test_switch_team.py +++ b/hc/accounts/tests/test_switch_team.py @@ -1,37 +1,23 @@ -from django.contrib.auth.models import User - from hc.test import BaseTestCase -from hc.accounts.models import Member, Profile +from hc.api.models import Check class SwitchTeamTestCase(BaseTestCase): - def setUp(self): - super(SwitchTeamTestCase, self).setUp() - - self.bob = User(username="bob", email="bob@example.org") - self.bob.set_password("password") - self.bob.save() - - bobs_profile = Profile(user=self.bob) - bobs_profile.save() - - - m = Member(team=bobs_profile, user=self.alice) - m.save() - def test_it_switches(self): - self.client.login(username="alice@example.org", password="password") + c = Check(user=self.alice, name="This belongs to Alice") + c.save() - url = "/accounts/switch_team/%s/" % self.bob.username - r = self.client.get(url, follow=True) + self.client.login(username="bob@example.org", password="password") - self.assertContains(r, "bob@example.org") + url = "/accounts/switch_team/%s/" % self.alice.username + r = self.client.get(url, follow=True) + self.assertContains(r, "This belongs to Alice") def test_it_checks_team_membership(self): self.client.login(username="charlie@example.org", password="password") - url = "/accounts/switch_team/%s/" % self.bob.username + url = "/accounts/switch_team/%s/" % self.alice.username r = self.client.get(url) self.assertEqual(r.status_code, 403) diff --git a/hc/accounts/views.py b/hc/accounts/views.py index 5078eac6..011bebdf 100644 --- a/hc/accounts/views.py +++ b/hc/accounts/views.py @@ -160,7 +160,13 @@ def profile(request): if form.is_valid(): email = form.cleaned_data["email"] - Member.objects.filter(team=profile, user__email=email).delete() + farewell_user = User.objects.get(email=email) + farewell_user.profile.current_team = None + farewell_user.profile.save() + + Member.objects.filter(team=profile, + user=farewell_user).delete() + messages.info(request, "%s removed from team!" % email) elif "set_team_name" in request.POST: form = TeamNameForm(request.POST) diff --git a/hc/api/tests/test_list_checks.py b/hc/api/tests/test_list_checks.py index 2ee8563b..2be3f77b 100644 --- a/hc/api/tests/test_list_checks.py +++ b/hc/api/tests/test_list_checks.py @@ -1,7 +1,7 @@ import json from datetime import timedelta as td -from hc.api.models import Check, User +from hc.api.models import Check from hc.test import BaseTestCase @@ -36,13 +36,12 @@ class ListChecksTestCase(BaseTestCase): self.assertEqual(checks["Alice 2"]["ping_url"], self.checks[1].url()) def test_it_shows_only_users_checks(self): - bob = User(username="bob", email="bob@example.com") - bob.save() - bob_check = Check(user=bob, name="Bob 1") - bob_check.save() + bobs_check = Check(user=self.bob, name="Bob 1") + bobs_check.save() r = self.get("/api/v1/checks/", {"api_key": "abc"}) - self.assertEqual(len(r.json()["checks"]), 2) - checks = { check["name"]: check for check in r.json()["checks"] } - self.assertNotIn("Bob 1", checks) + data = r.json() + self.assertEqual(len(data["checks"]), 2) + for check in data["checks"]: + self.assertNotEqual(check["name"], "Bob 1") diff --git a/hc/front/tests/test_add_channel.py b/hc/front/tests/test_add_channel.py index 8d7953fd..8d415487 100644 --- a/hc/front/tests/test_add_channel.py +++ b/hc/front/tests/test_add_channel.py @@ -17,6 +17,17 @@ class AddChannelTestCase(BaseTestCase): self.assertRedirects(r, "/integrations/") assert Channel.objects.count() == 1 + def test_team_access_works(self): + url = "/integrations/add/" + form = {"kind": "email", "value": "bob@example.org"} + + self.client.login(username="bob@example.org", password="password") + self.client.post(url, form) + + ch = Channel.objects.get() + # Added by bob, but should belong to alice (bob has team access) + self.assertEqual(ch.user, self.alice) + def test_it_trims_whitespace(self): """ Leading and trailing whitespace should get trimmed. """ @@ -92,6 +103,18 @@ class AddChannelTestCase(BaseTestCase): c = Channel.objects.get() self.assertEqual(c.value, "http://foo.com\nhttps://bar.com") + def test_it_adds_webhook_using_team_access(self): + form = {"value_down": "http://foo.com", "value_up": "https://bar.com"} + + # Logging in as bob, not alice. Bob has team access so this + # should work. + self.client.login(username="bob@example.org", password="password") + self.client.post("/integrations/add_webhook/", form) + + c = Channel.objects.get() + self.assertEqual(c.user, self.alice) + self.assertEqual(c.value, "http://foo.com\nhttps://bar.com") + def test_it_rejects_non_http_webhook_urls(self): form = {"value_down": "foo", "value_up": "bar"} diff --git a/hc/front/tests/test_add_check.py b/hc/front/tests/test_add_check.py index 0bb813a9..c792eddf 100644 --- a/hc/front/tests/test_add_check.py +++ b/hc/front/tests/test_add_check.py @@ -10,3 +10,12 @@ class AddCheckTestCase(BaseTestCase): r = self.client.post(url) self.assertRedirects(r, "/checks/") assert Check.objects.count() == 1 + + def test_team_access_works(self): + url = "/checks/add/" + self.client.login(username="bob@example.org", password="password") + self.client.post(url) + + check = Check.objects.get() + # Added by bob, but should belong to alice (bob has team access) + self.assertEqual(check.user, self.alice) diff --git a/hc/front/tests/test_channel_checks.py b/hc/front/tests/test_channel_checks.py index 1f6c8672..63474c48 100644 --- a/hc/front/tests/test_channel_checks.py +++ b/hc/front/tests/test_channel_checks.py @@ -17,6 +17,15 @@ class ChannelChecksTestCase(BaseTestCase): r = self.client.get(url) self.assertContains(r, "Assign Checks to Channel", status_code=200) + def test_team_access_works(self): + url = "/integrations/%s/checks/" % self.channel.code + + # Logging in as bob, not alice. Bob has team access so this + # should work. + self.client.login(username="bob@example.org", password="password") + r = self.client.get(url) + self.assertContains(r, "Assign Checks to Channel", status_code=200) + def test_it_checks_owner(self): # channel does not belong to mallory so this should come back # with 403 Forbidden: diff --git a/hc/front/tests/test_log.py b/hc/front/tests/test_log.py index c39d4145..886a5350 100644 --- a/hc/front/tests/test_log.py +++ b/hc/front/tests/test_log.py @@ -19,6 +19,15 @@ class LogTestCase(BaseTestCase): r = self.client.get(url) self.assertContains(r, "Dates and times are", status_code=200) + def test_team_access_works(self): + url = "/checks/%s/log/" % self.check.code + + # Logging in as bob, not alice. Bob has team access so this + # should work. + self.client.login(username="bob@example.org", password="password") + r = self.client.get(url) + self.assertEqual(r.status_code, 200) + def test_it_handles_bad_uuid(self): url = "/checks/not-uuid/log/" diff --git a/hc/front/tests/test_my_checks.py b/hc/front/tests/test_my_checks.py index 389aab42..5e3e704b 100644 --- a/hc/front/tests/test_my_checks.py +++ b/hc/front/tests/test_my_checks.py @@ -10,6 +10,7 @@ class MyChecksTestCase(BaseTestCase): self.check.save() def test_it_works(self): - self.client.login(username="alice@example.org", password="password") - r = self.client.get("/checks/") - self.assertContains(r, "Alice Was Here", status_code=200) + for email in ("alice@example.org", "bob@example.org"): + self.client.login(username=email, password="password") + r = self.client.get("/checks/") + self.assertContains(r, "Alice Was Here", status_code=200) diff --git a/hc/front/tests/test_remove_channel.py b/hc/front/tests/test_remove_channel.py index aa083b43..7f54a741 100644 --- a/hc/front/tests/test_remove_channel.py +++ b/hc/front/tests/test_remove_channel.py @@ -19,6 +19,13 @@ class RemoveChannelTestCase(BaseTestCase): assert Channel.objects.count() == 0 + def test_team_access_works(self): + url = "/integrations/%s/remove/" % self.channel.code + + self.client.login(username="bob@example.org", password="password") + self.client.post(url) + assert Channel.objects.count() == 0 + def test_it_handles_bad_uuid(self): url = "/integrations/not-uuid/remove/" diff --git a/hc/front/tests/test_remove_check.py b/hc/front/tests/test_remove_check.py index c0d5277e..eca3c7d1 100644 --- a/hc/front/tests/test_remove_check.py +++ b/hc/front/tests/test_remove_check.py @@ -18,6 +18,15 @@ class RemoveCheckTestCase(BaseTestCase): assert Check.objects.count() == 0 + def test_team_access_works(self): + url = "/checks/%s/remove/" % self.check.code + + # Logging in as bob, not alice. Bob has team access so this + # should work. + self.client.login(username="bob@example.org", password="password") + self.client.post(url) + assert Check.objects.count() == 0 + def test_it_handles_bad_uuid(self): url = "/checks/not-uuid/remove/" diff --git a/hc/front/tests/test_update_channel.py b/hc/front/tests/test_update_channel.py index 6eeb5108..050dfbc2 100644 --- a/hc/front/tests/test_update_channel.py +++ b/hc/front/tests/test_update_channel.py @@ -28,6 +28,18 @@ class UpdateChannelTestCase(BaseTestCase): assert len(checks) == 1 assert checks[0].code == self.check.code + def test_team_access_works(self): + payload = { + "channel": self.channel.code, + "check-%s" % self.check.code: True + } + + # Logging in as bob, not alice. Bob has team access so this + # should work. + self.client.login(username="bob@example.org", password="password") + r = self.client.post("/integrations/", data=payload, follow=True) + self.assertEqual(r.status_code, 200) + def test_it_checks_channel_user(self): payload = {"channel": self.channel.code} diff --git a/hc/front/tests/test_update_name.py b/hc/front/tests/test_update_name.py index 78035468..2c2fef64 100644 --- a/hc/front/tests/test_update_name.py +++ b/hc/front/tests/test_update_name.py @@ -20,6 +20,18 @@ class UpdateNameTestCase(BaseTestCase): check = Check.objects.get(code=self.check.code) assert check.name == "Alice Was Here" + def test_team_access_works(self): + url = "/checks/%s/name/" % self.check.code + payload = {"name": "Bob Was Here"} + + # Logging in as bob, not alice. Bob has team access so this + # should work. + self.client.login(username="bob@example.org", password="password") + self.client.post(url, data=payload) + + check = Check.objects.get(code=self.check.code) + assert check.name == "Bob Was Here" + def test_it_checks_ownership(self): url = "/checks/%s/name/" % self.check.code payload = {"name": "Charlie Sent This"} diff --git a/hc/front/tests/test_update_timeout.py b/hc/front/tests/test_update_timeout.py index 5daeb213..06ccad38 100644 --- a/hc/front/tests/test_update_timeout.py +++ b/hc/front/tests/test_update_timeout.py @@ -21,6 +21,18 @@ class UpdateTimeoutTestCase(BaseTestCase): assert check.timeout.total_seconds() == 3600 assert check.grace.total_seconds() == 60 + def test_team_access_works(self): + url = "/checks/%s/timeout/" % self.check.code + payload = {"timeout": 7200, "grace": 60} + + # Logging in as bob, not alice. Bob has team access so this + # should work. + self.client.login(username="bob@example.org", password="password") + self.client.post(url, data=payload) + + check = Check.objects.get(code=self.check.code) + assert check.timeout.total_seconds() == 7200 + def test_it_handles_bad_uuid(self): url = "/checks/not-uuid/timeout/" payload = {"timeout": 3600, "grace": 60} diff --git a/hc/test.py b/hc/test.py index 2b1ee979..9844f66b 100644 --- a/hc/test.py +++ b/hc/test.py @@ -1,7 +1,7 @@ from django.contrib.auth.models import User from django.test import TestCase -from hc.accounts.models import Profile +from hc.accounts.models import Member, Profile class BaseTestCase(TestCase): @@ -9,7 +9,7 @@ class BaseTestCase(TestCase): def setUp(self): super(BaseTestCase, self).setUp() - # Normal user for tests + # Alice is a normal user for tests self.alice = User(username="alice", email="alice@example.org") self.alice.set_password("password") self.alice.save() @@ -17,7 +17,19 @@ class BaseTestCase(TestCase): self.profile = Profile(user=self.alice, api_key="abc") self.profile.save() - # "malicious user for tests + # Bob is on Alice's team and should have access to her stuff + self.bob = User(username="bob", email="bob@example.org") + self.bob.set_password("password") + self.bob.save() + + self.bobs_profile = Profile(user=self.bob) + self.bobs_profile.current_team = self.profile + self.bobs_profile.save() + + m = Member(team=self.profile, user=self.bob) + m.save() + + # Charlie should have no access to Alice's stuff self.charlie = User(username="charlie", email="charlie@example.org") self.charlie.set_password("password") self.charlie.save()