|
4 | 4 | from django.urls import reverse |
5 | 5 | from json import JSONDecodeError |
6 | 6 | from unittest.mock import MagicMock, patch |
| 7 | +from waffle.models import Flag |
7 | 8 | import uuid |
8 | 9 |
|
9 | 10 | from django.conf import settings |
| 11 | +from django.core.exceptions import SuspiciousOperation |
10 | 12 | from urllib.parse import quote |
11 | 13 | from django.test import Client as RequestClient, override_settings |
12 | 14 | from rest_framework.test import APITestCase, APIClient |
@@ -353,3 +355,85 @@ def test_missing_emails_just_error_out(self): |
353 | 355 | self.assertEqual('no-email', resp_data.get('type')) |
354 | 356 | test_entry = AllowListEntry.objects.filter(email=email).first() |
355 | 357 | self.assertIsNone(test_entry) |
| 358 | + |
| 359 | + |
| 360 | +class WaffleFlagsTestcase(APITestCase): |
| 361 | + def setUp(self): |
| 362 | + self.client = APIClient() |
| 363 | + self.url = reverse('api_waffle_flags') |
| 364 | + self.user = User.objects.create( |
| 365 | + oidc_id=str(uuid.uuid4()), |
| 366 | + recovery_email=f'{uuid.uuid4()}@example.com', |
| 367 | + username=f'{uuid.uuid4()}@example.org', |
| 368 | + ) |
| 369 | + |
| 370 | + Flag.objects.create(name='flag-on-for-everyone', everyone=True) |
| 371 | + Flag.objects.create(name='flag-off-for-everyone', everyone=False) |
| 372 | + Flag.objects.create(name='flag-on-for-authenticated', authenticated=True) |
| 373 | + |
| 374 | + # Due to the endpoint being gated by OIDCAuthentication |
| 375 | + patcher = patch( |
| 376 | + 'thunderbird_accounts.authentication.middleware.AccountsOIDCBackend.get_userinfo', |
| 377 | + side_effect=self._fake_userinfo, |
| 378 | + ) |
| 379 | + patcher.start() |
| 380 | + self.addCleanup(patcher.stop) |
| 381 | + |
| 382 | + @staticmethod |
| 383 | + def _fake_userinfo(access_token, id_token, payload): |
| 384 | + # Mimic a real OIDC provider, which would reject unrecognized/invalid |
| 385 | + # access tokens rather than happily returning userinfo for anything. |
| 386 | + if not User.objects.filter(oidc_id=access_token).exists(): |
| 387 | + raise SuspiciousOperation('invalid access token') |
| 388 | + |
| 389 | + return { |
| 390 | + 'sub': access_token, |
| 391 | + 'email': f'{access_token}@example.org', |
| 392 | + 'email_verified': True, |
| 393 | + 'preferred_username': f'{access_token}@example.org', |
| 394 | + } |
| 395 | + |
| 396 | + def test_returns_active_flags_for_authenticated_user(self): |
| 397 | + response = self.client.get(self.url, headers={'authorization': f'Bearer {self.user.oidc_id}'}) |
| 398 | + self.assertEqual(200, response.status_code, response.content) |
| 399 | + |
| 400 | + flags = response.json().get('flags') |
| 401 | + self.assertEqual( |
| 402 | + { |
| 403 | + 'flag-on-for-everyone', |
| 404 | + 'flag-off-for-everyone', |
| 405 | + 'flag-on-for-authenticated', |
| 406 | + }, |
| 407 | + flags.keys(), |
| 408 | + ) |
| 409 | + self.assertTrue(flags['flag-on-for-everyone']['is_active']) |
| 410 | + self.assertFalse(flags['flag-off-for-everyone']['is_active']) |
| 411 | + self.assertTrue(flags['flag-on-for-authenticated']['is_active']) |
| 412 | + |
| 413 | + def test_returns_active_flag_for_specific_user_only(self): |
| 414 | + other_user = User.objects.create( |
| 415 | + oidc_id=str(uuid.uuid4()), |
| 416 | + recovery_email=f'{uuid.uuid4()}@example.com', |
| 417 | + username=f'{uuid.uuid4()}@example.org', |
| 418 | + ) |
| 419 | + |
| 420 | + flag = Flag.objects.create(name='flag-on-for-specific-user') |
| 421 | + flag.users.add(self.user) |
| 422 | + |
| 423 | + # Authenticate as the user created in the setup step and check that the flag is active |
| 424 | + response = self.client.get(self.url, headers={'authorization': f'Bearer {self.user.oidc_id}'}) |
| 425 | + self.assertEqual(200, response.status_code, response.content) |
| 426 | + self.assertTrue(response.json()['flags']['flag-on-for-specific-user']['is_active']) |
| 427 | + |
| 428 | + # Authenticate as the other user and check that the flag is not active |
| 429 | + response = self.client.get(self.url, headers={'authorization': f'Bearer {other_user.oidc_id}'}) |
| 430 | + self.assertEqual(200, response.status_code, response.content) |
| 431 | + self.assertFalse(response.json()['flags']['flag-on-for-specific-user']['is_active']) |
| 432 | + |
| 433 | + def test_requires_authentication(self): |
| 434 | + response = self.client.get(self.url) |
| 435 | + self.assertEqual(401, response.status_code) |
| 436 | + |
| 437 | + def test_returns_401_for_invalid_token(self): |
| 438 | + response = self.client.get(self.url, headers={'authorization': 'Bearer invalid-token'}) |
| 439 | + self.assertEqual(401, response.status_code) |
0 commit comments