@ -1,58 +0,0 @@ | |||||
from django.test.utils import override_settings | |||||
from hc.api.models import Channel | |||||
from hc.test import BaseTestCase | |||||
@override_settings(PUSHOVER_API_TOKEN="token", PUSHOVER_SUBSCRIPTION_URL="url") | |||||
class AddChannelTestCase(BaseTestCase): | |||||
def test_it_adds_email(self): | |||||
url = "/integrations/add/" | |||||
form = {"kind": "email", "value": "[email protected]"} | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.post(url, form) | |||||
self.assertRedirects(r, "/integrations/") | |||||
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): | |||||
""" Leading and trailing whitespace should get trimmed. """ | |||||
url = "/integrations/add/" | |||||
form = {"kind": "email", "value": " [email protected] "} | |||||
self.client.login(username="[email protected]", password="password") | |||||
self.client.post(url, form) | |||||
q = Channel.objects.filter(value="[email protected]") | |||||
self.assertEqual(q.count(), 1) | |||||
def test_it_rejects_bad_kind(self): | |||||
url = "/integrations/add/" | |||||
form = {"kind": "dog", "value": "Lassie"} | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.post(url, form) | |||||
assert r.status_code == 400, r.status_code | |||||
def test_instructions_work(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
kinds = ("email", "webhook", "pd", "pushover", "hipchat", "victorops") | |||||
for frag in kinds: | |||||
url = "/integrations/add_%s/" % frag | |||||
r = self.client.get(url) | |||||
self.assertContains(r, "Integration Settings", status_code=200) |
@ -0,0 +1,49 @@ | |||||
from hc.api.models import Channel | |||||
from hc.test import BaseTestCase | |||||
class AddPdTestCase(BaseTestCase): | |||||
url = "/integrations/add_email/" | |||||
def test_instructions_work(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.get(self.url) | |||||
self.assertContains(r, "Get an email message") | |||||
def test_it_creates_channel(self): | |||||
form = {"value": "[email protected]"} | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.post(self.url, form) | |||||
self.assertRedirects(r, "/integrations/") | |||||
c = Channel.objects.get() | |||||
self.assertEqual(c.kind, "email") | |||||
self.assertEqual(c.value, "[email protected]") | |||||
self.assertFalse(c.email_verified) | |||||
def test_team_access_works(self): | |||||
form = {"value": "[email protected]"} | |||||
self.client.login(username="[email protected]", password="password") | |||||
self.client.post(self.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_rejects_bad_email(self): | |||||
form = {"value": "not an email address"} | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.post(self.url, form) | |||||
self.assertContains(r, "Enter a valid email address.") | |||||
def test_it_trims_whitespace(self): | |||||
form = {"value": " [email protected] "} | |||||
self.client.login(username="[email protected]", password="password") | |||||
self.client.post(self.url, form) | |||||
c = Channel.objects.get() | |||||
self.assertEqual(c.value, "[email protected]") |
@ -0,0 +1,38 @@ | |||||
from hc.api.models import Channel | |||||
from hc.test import BaseTestCase | |||||
class AddHipChatTestCase(BaseTestCase): | |||||
url = "/integrations/add_hipchat/" | |||||
def test_instructions_work(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.get(self.url) | |||||
self.assertContains(r, "appropriate HipChat room") | |||||
def test_it_works(self): | |||||
form = {"value": "http://example.org"} | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.post(self.url, form) | |||||
self.assertRedirects(r, "/integrations/") | |||||
c = Channel.objects.get() | |||||
self.assertEqual(c.kind, "hipchat") | |||||
self.assertEqual(c.value, "http://example.org") | |||||
def test_it_rejects_bad_url(self): | |||||
form = {"value": "not an URL"} | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.post(self.url, form) | |||||
self.assertContains(r, "Enter a valid URL") | |||||
def test_it_trims_whitespace(self): | |||||
form = {"value": " http://example.org "} | |||||
self.client.login(username="[email protected]", password="password") | |||||
self.client.post(self.url, form) | |||||
c = Channel.objects.get() | |||||
self.assertEqual(c.value, "http://example.org") |
@ -0,0 +1,31 @@ | |||||
from hc.api.models import Channel | |||||
from hc.test import BaseTestCase | |||||
class AddPdTestCase(BaseTestCase): | |||||
url = "/integrations/add_pd/" | |||||
def test_instructions_work(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.get(self.url) | |||||
self.assertContains(r, "incident management system") | |||||
def test_it_works(self): | |||||
form = {"value": "123456"} | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.post(self.url, form) | |||||
self.assertRedirects(r, "/integrations/") | |||||
c = Channel.objects.get() | |||||
self.assertEqual(c.kind, "pd") | |||||
self.assertEqual(c.value, "123456") | |||||
def test_it_trims_whitespace(self): | |||||
form = {"value": " 123456 "} | |||||
self.client.login(username="[email protected]", password="password") | |||||
self.client.post(self.url, form) | |||||
c = Channel.objects.get() | |||||
self.assertEqual(c.value, "123456") |
@ -5,6 +5,11 @@ from hc.test import BaseTestCase | |||||
@override_settings(PUSHOVER_API_TOKEN="token", PUSHOVER_SUBSCRIPTION_URL="url") | @override_settings(PUSHOVER_API_TOKEN="token", PUSHOVER_SUBSCRIPTION_URL="url") | ||||
class AddPushoverTestCase(BaseTestCase): | class AddPushoverTestCase(BaseTestCase): | ||||
def test_instructions_work(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.get("/integrations/add_pushover/") | |||||
self.assertContains(r, "Subscribe with Pushover") | |||||
def test_it_adds_channel(self): | def test_it_adds_channel(self): | ||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
@ -8,16 +8,22 @@ from mock import patch | |||||
@override_settings(PUSHBULLET_CLIENT_ID="t1", PUSHBULLET_CLIENT_SECRET="s1") | @override_settings(PUSHBULLET_CLIENT_ID="t1", PUSHBULLET_CLIENT_SECRET="s1") | ||||
class AddPushbulletTestCase(BaseTestCase): | class AddPushbulletTestCase(BaseTestCase): | ||||
url = "/integrations/add_pushbullet/" | |||||
def test_instructions_work(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.get(self.url) | |||||
self.assertContains(r, "Connect Pushbullet") | |||||
def test_it_shows_instructions(self): | def test_it_shows_instructions(self): | ||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
r = self.client.get("/integrations/add_pushbullet/") | |||||
r = self.client.get(self.url) | |||||
self.assertContains(r, "www.pushbullet.com/authorize", status_code=200) | self.assertContains(r, "www.pushbullet.com/authorize", status_code=200) | ||||
@override_settings(PUSHBULLET_CLIENT_ID=None) | @override_settings(PUSHBULLET_CLIENT_ID=None) | ||||
def test_it_requires_client_id(self): | def test_it_requires_client_id(self): | ||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
r = self.client.get("/integrations/add_pushbullet/") | |||||
r = self.client.get(self.url) | |||||
self.assertEqual(r.status_code, 404) | self.assertEqual(r.status_code, 404) | ||||
@patch("hc.front.views.requests.post") | @patch("hc.front.views.requests.post") | ||||
@ -27,7 +33,7 @@ class AddPushbulletTestCase(BaseTestCase): | |||||
mock_post.return_value.text = json.dumps(oauth_response) | mock_post.return_value.text = json.dumps(oauth_response) | ||||
mock_post.return_value.json.return_value = oauth_response | mock_post.return_value.json.return_value = oauth_response | ||||
url = "/integrations/add_pushbullet/?code=12345678" | |||||
url = self.url + "?code=12345678" | |||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
r = self.client.get(url, follow=True) | r = self.client.get(url, follow=True) | ||||
@ -1,70 +1,32 @@ | |||||
import json | |||||
from django.test.utils import override_settings | from django.test.utils import override_settings | ||||
from hc.api.models import Channel | from hc.api.models import Channel | ||||
from hc.test import BaseTestCase | from hc.test import BaseTestCase | ||||
from mock import patch | |||||
class AddSlackTestCase(BaseTestCase): | class AddSlackTestCase(BaseTestCase): | ||||
@override_settings(SLACK_CLIENT_ID=None) | @override_settings(SLACK_CLIENT_ID=None) | ||||
def test_webhook_instructions_work(self): | |||||
def test_instructions_work(self): | |||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
r = self.client.get("/integrations/add_slack/") | r = self.client.get("/integrations/add_slack/") | ||||
self.assertContains(r, "Integration Settings", status_code=200) | self.assertContains(r, "Integration Settings", status_code=200) | ||||
@override_settings(SLACK_CLIENT_ID="foo") | |||||
def test_slack_button(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.get("/integrations/add_slack/") | |||||
self.assertContains(r, "slack.com/oauth/authorize", status_code=200) | |||||
@override_settings(SLACK_CLIENT_ID="foo") | |||||
def test_landing_page(self): | |||||
r = self.client.get("/integrations/add_slack/") | |||||
self.assertContains(r, "Before adding Slack integration", | |||||
status_code=200) | |||||
@patch("hc.front.views.requests.post") | |||||
def test_it_handles_oauth_response(self, mock_post): | |||||
oauth_response = { | |||||
"ok": True, | |||||
"team_name": "foo", | |||||
"incoming_webhook": { | |||||
"url": "http://example.org", | |||||
"channel": "bar" | |||||
} | |||||
} | |||||
mock_post.return_value.text = json.dumps(oauth_response) | |||||
mock_post.return_value.json.return_value = oauth_response | |||||
url = "/integrations/add_slack_btn/?code=12345678" | |||||
@override_settings(SLACK_CLIENT_ID=None) | |||||
def test_it_works(self): | |||||
form = {"value": "http://example.org"} | |||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
r = self.client.get(url, follow=True) | |||||
r = self.client.post("/integrations/add_slack/", form) | |||||
self.assertRedirects(r, "/integrations/") | self.assertRedirects(r, "/integrations/") | ||||
self.assertContains(r, "The Slack integration has been added!") | |||||
ch = Channel.objects.get() | |||||
self.assertEqual(ch.slack_team, "foo") | |||||
self.assertEqual(ch.slack_channel, "bar") | |||||
self.assertEqual(ch.slack_webhook_url, "http://example.org") | |||||
@patch("hc.front.views.requests.post") | |||||
def test_it_handles_oauth_error(self, mock_post): | |||||
oauth_response = { | |||||
"ok": False, | |||||
"error": "something went wrong" | |||||
} | |||||
c = Channel.objects.get() | |||||
self.assertEqual(c.kind, "slack") | |||||
self.assertEqual(c.value, "http://example.org") | |||||
mock_post.return_value.text = json.dumps(oauth_response) | |||||
mock_post.return_value.json.return_value = oauth_response | |||||
url = "/integrations/add_slack_btn/?code=12345678" | |||||
@override_settings(SLACK_CLIENT_ID=None) | |||||
def test_it_rejects_bad_url(self): | |||||
form = {"value": "not an URL"} | |||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
r = self.client.get(url, follow=True) | |||||
self.assertRedirects(r, "/integrations/") | |||||
self.assertContains(r, "something went wrong") | |||||
r = self.client.post("/integrations/add_slack/", form) | |||||
self.assertContains(r, "Enter a valid URL") |
@ -0,0 +1,64 @@ | |||||
import json | |||||
from django.test.utils import override_settings | |||||
from hc.api.models import Channel | |||||
from hc.test import BaseTestCase | |||||
from mock import patch | |||||
class AddSlackBtnTestCase(BaseTestCase): | |||||
@override_settings(SLACK_CLIENT_ID="foo") | |||||
def test_instructions_work(self): | |||||
r = self.client.get("/integrations/add_slack/") | |||||
self.assertContains(r, "Before adding Slack integration", | |||||
status_code=200) | |||||
@override_settings(SLACK_CLIENT_ID="foo") | |||||
def test_slack_button(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.get("/integrations/add_slack/") | |||||
self.assertContains(r, "slack.com/oauth/authorize", status_code=200) | |||||
@patch("hc.front.views.requests.post") | |||||
def test_it_handles_oauth_response(self, mock_post): | |||||
oauth_response = { | |||||
"ok": True, | |||||
"team_name": "foo", | |||||
"incoming_webhook": { | |||||
"url": "http://example.org", | |||||
"channel": "bar" | |||||
} | |||||
} | |||||
mock_post.return_value.text = json.dumps(oauth_response) | |||||
mock_post.return_value.json.return_value = oauth_response | |||||
url = "/integrations/add_slack_btn/?code=12345678" | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.get(url, follow=True) | |||||
self.assertRedirects(r, "/integrations/") | |||||
self.assertContains(r, "The Slack integration has been added!") | |||||
ch = Channel.objects.get() | |||||
self.assertEqual(ch.slack_team, "foo") | |||||
self.assertEqual(ch.slack_channel, "bar") | |||||
self.assertEqual(ch.slack_webhook_url, "http://example.org") | |||||
@patch("hc.front.views.requests.post") | |||||
def test_it_handles_oauth_error(self, mock_post): | |||||
oauth_response = { | |||||
"ok": False, | |||||
"error": "something went wrong" | |||||
} | |||||
mock_post.return_value.text = json.dumps(oauth_response) | |||||
mock_post.return_value.json.return_value = oauth_response | |||||
url = "/integrations/add_slack_btn/?code=12345678" | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.get(url, follow=True) | |||||
self.assertRedirects(r, "/integrations/") | |||||
self.assertContains(r, "something went wrong") |
@ -0,0 +1,29 @@ | |||||
from hc.api.models import Channel | |||||
from hc.test import BaseTestCase | |||||
class AddVictorOpsTestCase(BaseTestCase): | |||||
url = "/integrations/add_victorops/" | |||||
def test_instructions_work(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.get(self.url) | |||||
self.assertContains(r, "incident management system") | |||||
def test_it_works(self): | |||||
form = {"value": "http://example.org"} | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.post(self.url, form) | |||||
self.assertRedirects(r, "/integrations/") | |||||
c = Channel.objects.get() | |||||
self.assertEqual(c.kind, "victorops") | |||||
self.assertEqual(c.value, "http://example.org") | |||||
def test_it_rejects_bad_url(self): | |||||
form = {"value": "not an URL"} | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.post(self.url, form) | |||||
self.assertContains(r, "Enter a valid URL") |
@ -3,12 +3,18 @@ from hc.test import BaseTestCase | |||||
class AddWebhookTestCase(BaseTestCase): | class AddWebhookTestCase(BaseTestCase): | ||||
url = "/integrations/add_webhook/" | |||||
def test_instructions_work(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
r = self.client.get(self.url) | |||||
self.assertContains(r, "Webhooks are a simple way") | |||||
def test_it_adds_two_webhook_urls_and_redirects(self): | def test_it_adds_two_webhook_urls_and_redirects(self): | ||||
form = {"value_down": "http://foo.com", "value_up": "https://bar.com"} | form = {"value_down": "http://foo.com", "value_up": "https://bar.com"} | ||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
r = self.client.post("/integrations/add_webhook/", form) | |||||
r = self.client.post(self.url, form) | |||||
self.assertRedirects(r, "/integrations/") | self.assertRedirects(r, "/integrations/") | ||||
c = Channel.objects.get() | c = Channel.objects.get() | ||||
@ -20,26 +26,37 @@ class AddWebhookTestCase(BaseTestCase): | |||||
# Logging in as bob, not alice. Bob has team access so this | # Logging in as bob, not alice. Bob has team access so this | ||||
# should work. | # should work. | ||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
self.client.post("/integrations/add_webhook/", form) | |||||
self.client.post(self.url, form) | |||||
c = Channel.objects.get() | c = Channel.objects.get() | ||||
self.assertEqual(c.user, self.alice) | self.assertEqual(c.user, self.alice) | ||||
self.assertEqual(c.value, "http://foo.com\nhttps://bar.com") | 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"} | |||||
def test_it_rejects_bad_urls(self): | |||||
urls = [ | |||||
# clearly not an URL | |||||
"foo", | |||||
# FTP addresses not allowed | |||||
"ftp://example.org", | |||||
# no loopback | |||||
"http://localhost:1234/endpoint", | |||||
"http://127.0.0.1/endpoint" | |||||
] | |||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
r = self.client.post("/integrations/add_webhook/", form) | |||||
self.assertContains(r, "Enter a valid URL.") | |||||
for url in urls: | |||||
form = {"value_down": url, "value_up": ""} | |||||
r = self.client.post(self.url, form) | |||||
self.assertContains(r, "Enter a valid URL.", msg_prefix=url) | |||||
self.assertEqual(Channel.objects.count(), 0) | |||||
self.assertEqual(Channel.objects.count(), 0) | |||||
def test_it_handles_empty_down_url(self): | def test_it_handles_empty_down_url(self): | ||||
form = {"value_down": "", "value_up": "http://foo.com"} | form = {"value_down": "", "value_up": "http://foo.com"} | ||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
self.client.post("/integrations/add_webhook/", form) | |||||
self.client.post(self.url, form) | |||||
c = Channel.objects.get() | c = Channel.objects.get() | ||||
self.assertEqual(c.value, "\nhttp://foo.com") | self.assertEqual(c.value, "\nhttp://foo.com") |
@ -0,0 +1,14 @@ | |||||
from django.core.exceptions import ValidationError | |||||
from six.moves.urllib_parse import urlparse | |||||
class WebhookValidator(object): | |||||
message = "Enter a valid URL." | |||||
def __call__(self, value): | |||||
parsed = urlparse(value) | |||||
if parsed.scheme not in ("http", "https"): | |||||
raise ValidationError(message=self.message) | |||||
if parsed.hostname in ("127.0.0.1", "localhost"): | |||||
raise ValidationError(message=self.message) |
@ -24,10 +24,9 @@ | |||||
<h2>Integration Settings</h2> | <h2>Integration Settings</h2> | ||||
<form method="post" class="form-horizontal" action="{% url 'hc-add-channel' %}"> | |||||
<form method="post" class="form-horizontal" action="{% url 'hc-add-email' %}"> | |||||
{% csrf_token %} | {% csrf_token %} | ||||
<input type="hidden" name="kind" value="email" /> | |||||
<div class="form-group"> | |||||
<div class="form-group {{ form.value.css_classes }}"> | |||||
<label for="id_email" class="col-sm-2 control-label">Email</label> | <label for="id_email" class="col-sm-2 control-label">Email</label> | ||||
<div class="col-sm-3"> | <div class="col-sm-3"> | ||||
<input | <input | ||||
@ -35,7 +34,14 @@ | |||||
type="email" | type="email" | ||||
class="form-control" | class="form-control" | ||||
name="value" | name="value" | ||||
placeholder="[email protected]"> | |||||
placeholder="[email protected]" | |||||
value="{{ form.value.value|default:"" }}"> | |||||
{% if form.value.errors %} | |||||
<div class="help-block"> | |||||
{{ form.value.errors|join:"" }} | |||||
</div> | |||||
{% endif %} | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group"> | <div class="form-group"> | ||||