mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-19 10:59:21 +02:00
Remove WaffleSwitch, WaffleSample, and unit tests
This commit is contained in:
parent
271641d22c
commit
fcacc0d786
10 changed files with 10 additions and 334 deletions
|
@ -20,9 +20,6 @@ Follow these steps to achieve this:
|
|||
5. Rename the copied migration to match the increment. For instance, if `0091_create_waffle_flags_v01` exists, you will rename your migration to `0091_create_waffle_flags_v02`.
|
||||
6. Modify the migration dependency to match the last migration in the stack.
|
||||
|
||||
## Modifying an existing feature flag through the CLI
|
||||
Waffle comes with built in management commands that you can use to update records remotely. [Read here](https://waffle.readthedocs.io/en/stable/usage/cli.html) for information on how to use them.
|
||||
|
||||
## Using feature flags as boolean values
|
||||
Waffle [provides a boolean](https://waffle.readthedocs.io/en/stable/usage/views.html) called `flag_is_active` that you can use as you otherwise would a boolean. This boolean requires a request object and the flag name.
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@ from django.contrib.contenttypes.models import ContentType
|
|||
from django.urls import reverse
|
||||
from dateutil.relativedelta import relativedelta # type: ignore
|
||||
from epplibwrapper.errors import ErrorCode, RegistryError
|
||||
from waffle.admin import FlagAdmin, SampleAdmin, SwitchAdmin
|
||||
from waffle.admin import FlagAdmin
|
||||
from waffle.models import Sample, Switch
|
||||
from registrar.models import Contact, Domain, DomainRequest, DraftDomain, User, Website
|
||||
from registrar.utility.errors import FSMDomainRequestError, FSMErrorCodes
|
||||
from registrar.views.utility.mixins import OrderableFieldsMixin
|
||||
|
@ -2166,23 +2167,6 @@ class WaffleFlagAdmin(FlagAdmin):
|
|||
model = models.WaffleFlag
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class WaffleSwitchAdmin(SwitchAdmin):
|
||||
class Meta:
|
||||
"""Contains meta information about this class"""
|
||||
|
||||
model = models.WaffleSwitch
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class WaffleSampleAdmin(SampleAdmin):
|
||||
class Meta:
|
||||
"""Contains meta information about this class"""
|
||||
|
||||
model = models.WaffleSample
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
admin.site.unregister(LogEntry) # Unregister the default registration
|
||||
|
||||
admin.site.register(LogEntry, CustomLogEntryAdmin)
|
||||
|
@ -2209,5 +2193,7 @@ admin.site.register(models.VerifiedByStaff, VerifiedByStaffAdmin)
|
|||
|
||||
# Register our custom waffle implementations
|
||||
admin.site.register(models.WaffleFlag, WaffleFlagAdmin)
|
||||
admin.site.register(models.WaffleSample, WaffleSampleAdmin)
|
||||
admin.site.register(models.WaffleSwitch, WaffleSwitchAdmin)
|
||||
|
||||
# Unregister Sample and Switch from the waffle library
|
||||
admin.site.unregister(Sample)
|
||||
admin.site.unregister(Switch)
|
||||
|
|
|
@ -331,14 +331,6 @@ WAFFLE_CREATE_MISSING_FLAGS = False
|
|||
# Used to replace the default flag class (for customization purposes).
|
||||
WAFFLE_FLAG_MODEL = "registrar.WaffleFlag"
|
||||
|
||||
# The model that will be used to keep track of switches. Extends AbstractBaseSwitch.
|
||||
# Used to replace the default switch class (for customization purposes).
|
||||
WAFFLE_SWITCH_MODEL = "registrar.WaffleSwitch"
|
||||
|
||||
# The model that will be used to keep track of samples. Extends AbstractBaseSample.
|
||||
# Used to replace the default sample class (for customization purposes).
|
||||
WAFFLE_SAMPLE_MODEL = "registrar.WaffleSample"
|
||||
|
||||
# endregion
|
||||
|
||||
# region: Headers-----------------------------------------------------------###
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 4.2.10 on 2024-05-01 15:10
|
||||
# Generated by Django 4.2.10 on 2024-05-02 17:47
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
@ -13,93 +13,6 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="WaffleSample",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
(
|
||||
"name",
|
||||
models.CharField(
|
||||
help_text="The human/computer readable name.", max_length=100, unique=True, verbose_name="Name"
|
||||
),
|
||||
),
|
||||
(
|
||||
"percent",
|
||||
models.DecimalField(
|
||||
decimal_places=1,
|
||||
help_text="A number between 0.0 and 100.0 to indicate a percentage of the time this sample will be active.",
|
||||
max_digits=4,
|
||||
verbose_name="Percent",
|
||||
),
|
||||
),
|
||||
(
|
||||
"note",
|
||||
models.TextField(blank=True, help_text="Note where this Sample is used.", verbose_name="Note"),
|
||||
),
|
||||
(
|
||||
"created",
|
||||
models.DateTimeField(
|
||||
db_index=True,
|
||||
default=django.utils.timezone.now,
|
||||
help_text="Date when this Sample was created.",
|
||||
verbose_name="Created",
|
||||
),
|
||||
),
|
||||
(
|
||||
"modified",
|
||||
models.DateTimeField(
|
||||
default=django.utils.timezone.now,
|
||||
help_text="Date when this Sample was last modified.",
|
||||
verbose_name="Modified",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "waffle sample",
|
||||
"verbose_name_plural": "Waffle samples",
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="WaffleSwitch",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
(
|
||||
"name",
|
||||
models.CharField(
|
||||
help_text="The human/computer readable name.", max_length=100, unique=True, verbose_name="Name"
|
||||
),
|
||||
),
|
||||
(
|
||||
"active",
|
||||
models.BooleanField(default=False, help_text="Is this switch active?", verbose_name="Active"),
|
||||
),
|
||||
(
|
||||
"note",
|
||||
models.TextField(blank=True, help_text="Note where this Switch is used.", verbose_name="Note"),
|
||||
),
|
||||
(
|
||||
"created",
|
||||
models.DateTimeField(
|
||||
db_index=True,
|
||||
default=django.utils.timezone.now,
|
||||
help_text="Date when this Switch was created.",
|
||||
verbose_name="Created",
|
||||
),
|
||||
),
|
||||
(
|
||||
"modified",
|
||||
models.DateTimeField(
|
||||
default=django.utils.timezone.now,
|
||||
help_text="Date when this Switch was last modified.",
|
||||
verbose_name="Modified",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "waffle switch",
|
||||
"verbose_name_plural": "Waffle switches",
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="WaffleFlag",
|
||||
fields=[
|
|
@ -33,7 +33,7 @@ def delete_flags(apps, schema_editor):
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("registrar", "0090_wafflesample_waffleswitch_waffleflag"),
|
||||
("registrar", "0090_waffleflag"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
|
|
@ -16,8 +16,7 @@ from .website import Website
|
|||
from .transition_domain import TransitionDomain
|
||||
from .verified_by_staff import VerifiedByStaff
|
||||
from .waffle_flag import WaffleFlag
|
||||
from .waffle_sample import WaffleSample
|
||||
from .waffle_switch import WaffleSwitch
|
||||
|
||||
|
||||
__all__ = [
|
||||
"Contact",
|
||||
|
@ -37,8 +36,6 @@ __all__ = [
|
|||
"TransitionDomain",
|
||||
"VerifiedByStaff",
|
||||
"WaffleFlag",
|
||||
"WaffleSwitch",
|
||||
"WaffleSample",
|
||||
]
|
||||
|
||||
auditlog.register(Contact)
|
||||
|
@ -58,5 +55,3 @@ auditlog.register(Website)
|
|||
auditlog.register(TransitionDomain)
|
||||
auditlog.register(VerifiedByStaff)
|
||||
auditlog.register(WaffleFlag)
|
||||
auditlog.register(WaffleSample)
|
||||
auditlog.register(WaffleSwitch)
|
||||
|
|
|
@ -41,9 +41,7 @@ class WaffleFlag(AbstractUserFlag):
|
|||
"""
|
||||
logger.info("Creating default waffle flags...")
|
||||
WaffleFlag = apps.get_model("registrar", "WaffleFlag")
|
||||
# Flags can be changed through the command line or through django admin.
|
||||
# To keep the scope of this function minimal and simple, if we require additional
|
||||
# config on these flag, it should be done in a seperate function or as a command.
|
||||
# Flags can be changed through django admin if necessary.
|
||||
for flag_name, flag_note in default_waffle_flags:
|
||||
try:
|
||||
WaffleFlag.objects.update_or_create(
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
from waffle.models import AbstractBaseSample
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WaffleSample(AbstractBaseSample):
|
||||
"""
|
||||
Custom implementation of django-waffles 'sample' object.
|
||||
Read more here: https://waffle.readthedocs.io/en/stable/types/sample.html
|
||||
|
||||
Use this class when dealing with samples.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
"""Contains meta information about this class"""
|
||||
|
||||
verbose_name = "waffle sample"
|
||||
verbose_name_plural = "Waffle samples"
|
|
@ -1,19 +0,0 @@
|
|||
from waffle.models import AbstractBaseSwitch
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WaffleSwitch(AbstractBaseSwitch):
|
||||
"""
|
||||
Custom implementation of django-waffles 'switch' object.
|
||||
Read more here: https://waffle.readthedocs.io/en/stable/types/switch.html
|
||||
|
||||
Use this class when dealing with switches.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
"""Contains meta information about this class"""
|
||||
|
||||
verbose_name = "waffle switch"
|
||||
verbose_name_plural = "Waffle switches"
|
|
@ -1,167 +0,0 @@
|
|||
from waffle.decorators import flag_is_active
|
||||
from django.test import TestCase, Client, RequestFactory
|
||||
from registrar.models import (
|
||||
WaffleFlag,
|
||||
User,
|
||||
Contact,
|
||||
UserGroup,
|
||||
)
|
||||
from registrar.tests.common import create_superuser, create_staffuser, create_user
|
||||
|
||||
|
||||
class TestFeatureFlags(TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.client = Client(HTTP_HOST="localhost:8080")
|
||||
self.factory = RequestFactory()
|
||||
self.superuser = create_superuser()
|
||||
|
||||
# For testing purposes, lets set this to false.
|
||||
self.superuser.is_staff = False
|
||||
self.superuser.save()
|
||||
|
||||
self.staffuser = create_staffuser()
|
||||
self.user = create_user()
|
||||
|
||||
def tearDown(self):
|
||||
super().tearDown()
|
||||
WaffleFlag.objects.all().delete()
|
||||
User.objects.all().delete()
|
||||
Contact.objects.all().delete()
|
||||
|
||||
def assert_flag_active(self, request_user, flag_name, location="/"):
|
||||
"""
|
||||
Checks if the given `request_user` has `flag_name` active
|
||||
using waffles `flag_is_active` function.
|
||||
"""
|
||||
request = self.factory.get(location)
|
||||
request.user = request_user
|
||||
self.assertTrue(flag_is_active(request, flag_name))
|
||||
|
||||
def assert_flag_not_active(self, request_user, flag_name, location="/"):
|
||||
"""
|
||||
Checks if the given `request_user` has `flag_name` not active
|
||||
using waffles `flag_is_active` function.
|
||||
"""
|
||||
request = self.factory.get(location)
|
||||
request.user = request_user
|
||||
self.assertFalse(flag_is_active(request, flag_name))
|
||||
|
||||
def test_flag_active_for_superuser(self):
|
||||
"""
|
||||
Tests flag_is_active for a flag with `superuser = True`
|
||||
"""
|
||||
flag, _ = WaffleFlag.objects.get_or_create(
|
||||
name="test_superuser_flag",
|
||||
superusers=True,
|
||||
staff=False,
|
||||
)
|
||||
# Test if superusers can access this flag
|
||||
self.assert_flag_active(request_user=self.superuser, flag_name=flag.name)
|
||||
|
||||
# Ensure that regular staff cannot access this flag
|
||||
self.assert_flag_not_active(request_user=self.staffuser, flag_name=flag.name)
|
||||
|
||||
# Ensure that a normal user also can't access this flag
|
||||
self.assert_flag_not_active(request_user=self.user, flag_name=flag.name)
|
||||
|
||||
def test_flag_active_for_is_staff(self):
|
||||
"""
|
||||
Tests flag_is_active for a flag with `is_staff = True`
|
||||
"""
|
||||
# We should actually expect superusers
|
||||
# to not see this feature - otherwise the two distinct booleans aren't useful.
|
||||
# In practice, we would usually use groups for toggling features.
|
||||
flag, _ = WaffleFlag.objects.get_or_create(
|
||||
name="test_superuser_flag",
|
||||
superusers=False,
|
||||
staff=True,
|
||||
)
|
||||
|
||||
# Ensure that regular staff can access this flag
|
||||
self.assert_flag_active(request_user=self.staffuser, flag_name=flag.name)
|
||||
|
||||
# Ensure that superusers cannot access this flag
|
||||
self.assert_flag_not_active(request_user=self.superuser, flag_name=flag.name)
|
||||
|
||||
# Ensure that a normal user also can't access this flag
|
||||
self.assert_flag_not_active(request_user=self.user, flag_name=flag.name)
|
||||
|
||||
def test_flag_active_for_everyone(self):
|
||||
"""
|
||||
Tests flag_is_active for a flag with `everyone = True`
|
||||
"""
|
||||
flag, _ = WaffleFlag.objects.get_or_create(
|
||||
name="test_superuser_flag",
|
||||
everyone=True,
|
||||
)
|
||||
|
||||
# Ensure that regular staff can access this flag
|
||||
self.assert_flag_active(request_user=self.staffuser, flag_name=flag.name)
|
||||
|
||||
# Ensure that superusers can access this flag
|
||||
self.assert_flag_active(request_user=self.superuser, flag_name=flag.name)
|
||||
|
||||
# Ensure that normal users can access this flag
|
||||
self.assert_flag_active(request_user=self.user, flag_name=flag.name)
|
||||
|
||||
def test_flag_active_for_everyone_is_false(self):
|
||||
"""
|
||||
Tests flag_is_active for a flag with `everyone = False`
|
||||
"""
|
||||
flag, _ = WaffleFlag.objects.get_or_create(
|
||||
name="test_superuser_flag",
|
||||
everyone=False,
|
||||
)
|
||||
|
||||
# Ensure that regular staff cannot access this flag
|
||||
self.assert_flag_not_active(request_user=self.staffuser, flag_name=flag.name)
|
||||
|
||||
# Ensure that superusers cannot access this flag
|
||||
self.assert_flag_not_active(request_user=self.superuser, flag_name=flag.name)
|
||||
|
||||
# Ensure that normal users cannot access this flag
|
||||
self.assert_flag_not_active(request_user=self.user, flag_name=flag.name)
|
||||
|
||||
def test_admin_group(self):
|
||||
"""
|
||||
Tests flag_is_active for the admin user group
|
||||
"""
|
||||
flag, _ = WaffleFlag.objects.get_or_create(
|
||||
name="test_superuser_flag",
|
||||
)
|
||||
|
||||
# Add the full access group to this flag
|
||||
group, _ = UserGroup.objects.get_or_create(name="full_access_group")
|
||||
flag.groups.set([group])
|
||||
|
||||
# Ensure that regular staff cannot access this flag
|
||||
self.assert_flag_not_active(request_user=self.staffuser, flag_name=flag.name)
|
||||
|
||||
# Ensure that superusers can access this flag
|
||||
self.assert_flag_active(request_user=self.superuser, flag_name=flag.name)
|
||||
|
||||
# Ensure that normal users cannot access this flag
|
||||
self.assert_flag_not_active(request_user=self.user, flag_name=flag.name)
|
||||
|
||||
def test_staff_group(self):
|
||||
"""
|
||||
Tests flag_is_active for the staff user group
|
||||
"""
|
||||
flag, _ = WaffleFlag.objects.get_or_create(
|
||||
name="test_superuser_flag",
|
||||
)
|
||||
|
||||
# Add the analyst group to this flag
|
||||
analyst_group, _ = UserGroup.objects.get_or_create(name="cisa_analysts_group")
|
||||
flag.groups.set([analyst_group])
|
||||
|
||||
# Ensure that regular staff can access this flag
|
||||
self.assert_flag_active(request_user=self.staffuser, flag_name=flag.name)
|
||||
|
||||
# Ensure that superusers can access this flag.
|
||||
# This permission encompasses cisa_analysts_group.
|
||||
self.assert_flag_active(request_user=self.superuser, flag_name=flag.name)
|
||||
|
||||
# Ensure that normal users cannot access this flag
|
||||
self.assert_flag_not_active(request_user=self.user, flag_name=flag.name)
|
Loading…
Add table
Add a link
Reference in a new issue