@ -62,13 +62,16 @@ class ProfileTestCase(BaseTestCase): | |||||
def test_it_adds_team_member(self): | def test_it_adds_team_member(self): | ||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", 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) | r = self.client.post("/accounts/profile/", form) | ||||
assert r.status_code == 200 | 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, "[email protected]") | |||||
self.assertEqual(len(member_emails), 2) | |||||
self.assertTrue("[email protected]" in member_emails) | |||||
# And an email should have been sent | # And an email should have been sent | ||||
subj = ('You have been invited to join' | subj = ('You have been invited to join' | ||||
@ -78,18 +81,15 @@ class ProfileTestCase(BaseTestCase): | |||||
def test_it_removes_team_member(self): | def test_it_removes_team_member(self): | ||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
bob = User(username="bob", email="[email protected]") | |||||
bob.save() | |||||
m = Member(team=self.alice.profile, user=bob) | |||||
m.save() | |||||
form = {"remove_team_member": "1", "email": "[email protected]"} | form = {"remove_team_member": "1", "email": "[email protected]"} | ||||
r = self.client.post("/accounts/profile/", form) | r = self.client.post("/accounts/profile/", form) | ||||
assert r.status_code == 200 | assert r.status_code == 200 | ||||
self.assertEqual(Member.objects.count(), 0) | 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): | def test_it_sets_team_name(self): | ||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
@ -1,37 +1,23 @@ | |||||
from django.contrib.auth.models import User | |||||
from hc.test import BaseTestCase | from hc.test import BaseTestCase | ||||
from hc.accounts.models import Member, Profile | |||||
from hc.api.models import Check | |||||
class SwitchTeamTestCase(BaseTestCase): | class SwitchTeamTestCase(BaseTestCase): | ||||
def setUp(self): | |||||
super(SwitchTeamTestCase, self).setUp() | |||||
self.bob = User(username="bob", email="[email protected]") | |||||
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): | def test_it_switches(self): | ||||
self.client.login(username="[email protected]", 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="[email protected]", password="password") | |||||
self.assertContains(r, "[email protected]") | |||||
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): | def test_it_checks_team_membership(self): | ||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
url = "/accounts/switch_team/%s/" % self.bob.username | |||||
url = "/accounts/switch_team/%s/" % self.alice.username | |||||
r = self.client.get(url) | r = self.client.get(url) | ||||
self.assertEqual(r.status_code, 403) | self.assertEqual(r.status_code, 403) |
@ -1,7 +1,7 @@ | |||||
import json | import json | ||||
from datetime import timedelta as td | from datetime import timedelta as td | ||||
from hc.api.models import Check, User | |||||
from hc.api.models import Check | |||||
from hc.test import BaseTestCase | from hc.test import BaseTestCase | ||||
@ -36,13 +36,12 @@ class ListChecksTestCase(BaseTestCase): | |||||
self.assertEqual(checks["Alice 2"]["ping_url"], self.checks[1].url()) | self.assertEqual(checks["Alice 2"]["ping_url"], self.checks[1].url()) | ||||
def test_it_shows_only_users_checks(self): | def test_it_shows_only_users_checks(self): | ||||
bob = User(username="bob", email="[email protected]") | |||||
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"}) | 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") |
@ -17,6 +17,17 @@ class AddChannelTestCase(BaseTestCase): | |||||
self.assertRedirects(r, "/integrations/") | self.assertRedirects(r, "/integrations/") | ||||
assert Channel.objects.count() == 1 | assert Channel.objects.count() == 1 | ||||
def test_team_access_works(self): | |||||
url = "/integrations/add/" | |||||
form = {"kind": "email", "value": "[email protected]"} | |||||
self.client.login(username="[email protected]", 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): | def test_it_trims_whitespace(self): | ||||
""" Leading and trailing whitespace should get trimmed. """ | """ Leading and trailing whitespace should get trimmed. """ | ||||
@ -92,6 +103,18 @@ class AddChannelTestCase(BaseTestCase): | |||||
c = Channel.objects.get() | c = Channel.objects.get() | ||||
self.assertEqual(c.value, "http://foo.com\nhttps://bar.com") | 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="[email protected]", 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): | def test_it_rejects_non_http_webhook_urls(self): | ||||
form = {"value_down": "foo", "value_up": "bar"} | form = {"value_down": "foo", "value_up": "bar"} | ||||
@ -10,3 +10,12 @@ class AddCheckTestCase(BaseTestCase): | |||||
r = self.client.post(url) | r = self.client.post(url) | ||||
self.assertRedirects(r, "/checks/") | self.assertRedirects(r, "/checks/") | ||||
assert Check.objects.count() == 1 | assert Check.objects.count() == 1 | ||||
def test_team_access_works(self): | |||||
url = "/checks/add/" | |||||
self.client.login(username="[email protected]", 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) |
@ -17,6 +17,15 @@ class ChannelChecksTestCase(BaseTestCase): | |||||
r = self.client.get(url) | r = self.client.get(url) | ||||
self.assertContains(r, "Assign Checks to Channel", status_code=200) | 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="[email protected]", password="password") | |||||
r = self.client.get(url) | |||||
self.assertContains(r, "Assign Checks to Channel", status_code=200) | |||||
def test_it_checks_owner(self): | def test_it_checks_owner(self): | ||||
# channel does not belong to mallory so this should come back | # channel does not belong to mallory so this should come back | ||||
# with 403 Forbidden: | # with 403 Forbidden: | ||||
@ -19,6 +19,15 @@ class LogTestCase(BaseTestCase): | |||||
r = self.client.get(url) | r = self.client.get(url) | ||||
self.assertContains(r, "Dates and times are", status_code=200) | 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="[email protected]", password="password") | |||||
r = self.client.get(url) | |||||
self.assertEqual(r.status_code, 200) | |||||
def test_it_handles_bad_uuid(self): | def test_it_handles_bad_uuid(self): | ||||
url = "/checks/not-uuid/log/" | url = "/checks/not-uuid/log/" | ||||
@ -10,6 +10,7 @@ class MyChecksTestCase(BaseTestCase): | |||||
self.check.save() | self.check.save() | ||||
def test_it_works(self): | def test_it_works(self): | ||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.get("/checks/") | |||||
self.assertContains(r, "Alice Was Here", status_code=200) | |||||
for email in ("[email protected]", "[email protected]"): | |||||
self.client.login(username=email, password="password") | |||||
r = self.client.get("/checks/") | |||||
self.assertContains(r, "Alice Was Here", status_code=200) |
@ -19,6 +19,13 @@ class RemoveChannelTestCase(BaseTestCase): | |||||
assert Channel.objects.count() == 0 | assert Channel.objects.count() == 0 | ||||
def test_team_access_works(self): | |||||
url = "/integrations/%s/remove/" % self.channel.code | |||||
self.client.login(username="[email protected]", password="password") | |||||
self.client.post(url) | |||||
assert Channel.objects.count() == 0 | |||||
def test_it_handles_bad_uuid(self): | def test_it_handles_bad_uuid(self): | ||||
url = "/integrations/not-uuid/remove/" | url = "/integrations/not-uuid/remove/" | ||||
@ -18,6 +18,15 @@ class RemoveCheckTestCase(BaseTestCase): | |||||
assert Check.objects.count() == 0 | 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="[email protected]", password="password") | |||||
self.client.post(url) | |||||
assert Check.objects.count() == 0 | |||||
def test_it_handles_bad_uuid(self): | def test_it_handles_bad_uuid(self): | ||||
url = "/checks/not-uuid/remove/" | url = "/checks/not-uuid/remove/" | ||||
@ -28,6 +28,18 @@ class UpdateChannelTestCase(BaseTestCase): | |||||
assert len(checks) == 1 | assert len(checks) == 1 | ||||
assert checks[0].code == self.check.code | 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="[email protected]", password="password") | |||||
r = self.client.post("/integrations/", data=payload, follow=True) | |||||
self.assertEqual(r.status_code, 200) | |||||
def test_it_checks_channel_user(self): | def test_it_checks_channel_user(self): | ||||
payload = {"channel": self.channel.code} | payload = {"channel": self.channel.code} | ||||
@ -20,6 +20,18 @@ class UpdateNameTestCase(BaseTestCase): | |||||
check = Check.objects.get(code=self.check.code) | check = Check.objects.get(code=self.check.code) | ||||
assert check.name == "Alice Was Here" | 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="[email protected]", 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): | def test_it_checks_ownership(self): | ||||
url = "/checks/%s/name/" % self.check.code | url = "/checks/%s/name/" % self.check.code | ||||
payload = {"name": "Charlie Sent This"} | payload = {"name": "Charlie Sent This"} | ||||
@ -21,6 +21,18 @@ class UpdateTimeoutTestCase(BaseTestCase): | |||||
assert check.timeout.total_seconds() == 3600 | assert check.timeout.total_seconds() == 3600 | ||||
assert check.grace.total_seconds() == 60 | 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="[email protected]", 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): | def test_it_handles_bad_uuid(self): | ||||
url = "/checks/not-uuid/timeout/" | url = "/checks/not-uuid/timeout/" | ||||
payload = {"timeout": 3600, "grace": 60} | payload = {"timeout": 3600, "grace": 60} | ||||
@ -1,7 +1,7 @@ | |||||
from django.contrib.auth.models import User | from django.contrib.auth.models import User | ||||
from django.test import TestCase | from django.test import TestCase | ||||
from hc.accounts.models import Profile | |||||
from hc.accounts.models import Member, Profile | |||||
class BaseTestCase(TestCase): | class BaseTestCase(TestCase): | ||||
@ -9,7 +9,7 @@ class BaseTestCase(TestCase): | |||||
def setUp(self): | def setUp(self): | ||||
super(BaseTestCase, self).setUp() | super(BaseTestCase, self).setUp() | ||||
# Normal user for tests | |||||
# Alice is a normal user for tests | |||||
self.alice = User(username="alice", email="[email protected]") | self.alice = User(username="alice", email="[email protected]") | ||||
self.alice.set_password("password") | self.alice.set_password("password") | ||||
self.alice.save() | self.alice.save() | ||||
@ -17,7 +17,19 @@ class BaseTestCase(TestCase): | |||||
self.profile = Profile(user=self.alice, api_key="abc") | self.profile = Profile(user=self.alice, api_key="abc") | ||||
self.profile.save() | 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="[email protected]") | |||||
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="[email protected]") | self.charlie = User(username="charlie", email="[email protected]") | ||||
self.charlie.set_password("password") | self.charlie.set_password("password") | ||||
self.charlie.save() | self.charlie.save() | ||||