Skip to content

Commit

Permalink
Add Today-based ConditionSets
Browse files Browse the repository at this point in the history
  • Loading branch information
nkovshov authored and Adam Chainz committed Nov 30, 2016
1 parent 2e28d1a commit 465407b
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 4 deletions.
3 changes: 3 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ Pending Release
---------------

* New release notes here
* Added three built-in condition sets for checking if it's before or after the
current date - ``UTCTodayConditionSet``, ``AppTodayConditionSet``, and
``ActiveTimezoneTodayConditionSet``.

1.2.6 (2016-08-03)
------------------
Expand Down
76 changes: 75 additions & 1 deletion gargoyle/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@
import socket
import struct

from datetime import datetime
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AnonymousUser
from django.core.validators import validate_ipv4_address
from django.utils import timezone

from gargoyle import gargoyle
from gargoyle.conditions import (
Boolean, ConditionSet, ModelConditionSet, OnOrAfterDate, Percent, RequestConditionSet, String
BeforeDate, Boolean, ConditionSet, ModelConditionSet,
OnOrAfterDate, Percent, RequestConditionSet, String
)

User = get_user_model()
Expand Down Expand Up @@ -109,3 +112,74 @@ def get_field_value(self, instance, field_name):

def get_group_label(self):
return 'Host'


@gargoyle.register
class UTCTodayConditionSet(ConditionSet):
"""
Checks conditions against current time in UTC
"""
today_is_on_or_after = OnOrAfterDate('in UTC on or after')
today_is_before = BeforeDate('in UTC before')

def get_namespace(self):
return 'now_utc'

def can_execute(self, instance):
return instance is None

def get_field_value(self, instance, field_name):
return datetime.utcnow()

def get_group_label(self):
return 'Today'


@gargoyle.register
class AppTodayConditionSet(ConditionSet):
"""
Checks conditions against current app timezone time or
against current server time if Django timezone support disabled (USE_TZ=False)
"""
today_is_on_or_after = OnOrAfterDate('in default timezone on or after')
today_is_before = BeforeDate('in default timezone before')

def get_namespace(self):
return 'now_app_tz'

def can_execute(self, instance):
return instance is None

def get_field_value(self, instance, field_name):
now_dt = timezone.now()
if timezone.is_aware(now_dt):
now_dt = timezone.make_naive(now_dt, timezone.get_default_timezone())
return now_dt

def get_group_label(self):
return 'Today'


@gargoyle.register
class ActiveTimezoneTodayConditionSet(ConditionSet):
"""
Checks conditions against current time of active timezone or
against current server time if Django timezone support disabled (USE_TZ=False)
"""
today_is_on_or_after = OnOrAfterDate('in active timezone on or after')
today_is_before = BeforeDate('in active timezone before')

def get_namespace(self):
return 'now_active_tz'

def can_execute(self, instance):
return instance is None

def get_field_value(self, instance, field_name):
now_dt = timezone.now()
if timezone.is_aware(now_dt):
now_dt = timezone.make_naive(now_dt)
return now_dt

def get_group_label(self):
return 'Today'
2 changes: 2 additions & 0 deletions requirements.in
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
docutils
flake8
freezegun
isort
multilint
Pygments
pytz
pytest
pytest-cov
pytest-django
Expand Down
4 changes: 4 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ coverage==4.2 # via pytest-cov
docutils==0.12
enum34==1.1.6 # via flake8
flake8==3.2.1
freezegun==0.3.8
isort==4.2.5
mccabe==0.5.2 # via flake8
multilint==2.0.1
Expand All @@ -19,4 +20,7 @@ Pygments==2.1.3
pytest-cov==2.4.0
pytest-django==3.1.2
pytest==3.0.4
python-dateutil==2.6.0 # via freezegun
pytz==2016.7
six==1.10.0 # via freezegun, python-dateutil
sqlparse==0.2.2
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ add_imports =
from __future__ import division
from __future__ import print_function
known_first_party = gargoyle,testapp
known_third_party = django,nexus
known_third_party = django,nexus,pytz
line_length = 120
multi_line_output = 5
not_skip = __init__.py
Expand Down
148 changes: 146 additions & 2 deletions tests/testapp/test_builtins.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
from __future__ import absolute_import, division, print_function, unicode_literals

import datetime
import socket

import pytz
from django.test import RequestFactory, TestCase
from django.test.utils import override_settings
from django.utils import timezone

from gargoyle.builtins import HostConditionSet, IPAddressConditionSet
from freezegun import freeze_time

from gargoyle.builtins import (
ActiveTimezoneTodayConditionSet, AppTodayConditionSet, HostConditionSet, IPAddressConditionSet,
UTCTodayConditionSet
)
from gargoyle.manager import SwitchManager
from gargoyle.models import SELECTIVE, Switch

Expand Down Expand Up @@ -87,7 +95,7 @@ def test_not_internal_ip(self):
assert self.gargoyle.is_active('test', request)


class HostConditionSetTest(TestCase):
class HostConditionSetTests(TestCase):
def setUp(self):
self.gargoyle = SwitchManager(Switch, key='key', value='value', instances=True, auto_create=True)
self.gargoyle.register(HostConditionSet())
Expand All @@ -111,3 +119,139 @@ def test_simple(self):
)

assert self.gargoyle.is_active('test')


class UTCTodayConditionSetTests(TestCase):
def setUp(self):
"""
Assume we have:
- server with `America/Chicago` timezone
- app with `America/New_York` timezone (if Django timezone support enabled)
- current timezone `Europe/Moscow` (if active)
- then it is 2016-01-01T00:00:00 at server
"""
self.condition_set = UTCTodayConditionSet()
self.server_dt = datetime.datetime(2016, 1, 1, 0, 0, 0)
self.server_tz = pytz.timezone('America/Chicago')
self.server_dt_aware = self.server_tz.localize(self.server_dt)
self.server_tz_offset = -6
self.utc_dt = self.server_dt - datetime.timedelta(hours=self.server_tz_offset)

@override_settings(USE_TZ=True, TIME_ZONE="America/New_York")
@timezone.override('Europe/Moscow')
def test_use_tz_with_active(self):
with freeze_time(self.server_dt_aware, tz_offset=self.server_tz_offset):
assert self.condition_set.get_field_value(None, 'now_is_on_or_after') == self.utc_dt

@override_settings(USE_TZ=True, TIME_ZONE="America/New_York")
@timezone.override(None)
def test_use_tz_no_active(self):
with freeze_time(self.server_dt_aware, tz_offset=self.server_tz_offset):
assert self.condition_set.get_field_value(None, 'now_is_on_or_after') == self.utc_dt

@override_settings(USE_TZ=False, TIME_ZONE=None)
@timezone.override('Europe/Moscow')
def test_no_use_tz_with_active(self):
with freeze_time(self.server_dt_aware, tz_offset=self.server_tz_offset):
assert self.condition_set.get_field_value(None, 'now_is_on_or_after') == self.utc_dt

@override_settings(USE_TZ=False, TIME_ZONE=None)
@timezone.override(None)
def test_no_use_tz_without_active(self):
with freeze_time(self.server_dt_aware, tz_offset=self.server_tz_offset):
assert self.condition_set.get_field_value(None, 'now_is_on_or_after') == self.utc_dt


class AppTodayConditionSetTests(TestCase):
def setUp(self):
"""
Assume we have:
- server with `America/Chicago` timezone
- app with `America/New_York` timezone (if Django timezone support enabled)
- current timezone `Europe/Moscow` (if active)
- then it is 2016-01-01T00:00:00 at server
"""
self.condition_set = AppTodayConditionSet()
self.server_dt = datetime.datetime(2016, 1, 1, 0, 0, 0)
self.server_tz = pytz.timezone('America/Chicago')
self.server_dt_aware = self.server_tz.localize(self.server_dt)
self.server_tz_offset = -6
self.app_to_server_tz_offset = datetime.timedelta(hours=1)

@override_settings(USE_TZ=True, TIME_ZONE="America/New_York")
@timezone.override('Europe/Moscow')
def test_use_tz_with_active(self):
with freeze_time(self.server_dt_aware, tz_offset=self.server_tz_offset):
assert (
self.condition_set.get_field_value(None, 'now_is_on_or_after') ==
self.server_dt + self.app_to_server_tz_offset
)

@override_settings(USE_TZ=True, TIME_ZONE="America/New_York")
@timezone.override(None)
def test_use_tz_no_active(self):
with freeze_time(self.server_dt_aware, tz_offset=self.server_tz_offset):
assert (
self.condition_set.get_field_value(None, 'now_is_on_or_after') ==
self.server_dt + self.app_to_server_tz_offset
)

@override_settings(USE_TZ=False, TIME_ZONE=None)
@timezone.override('Europe/Moscow')
def test_no_use_tz_with_active(self):
with freeze_time(self.server_dt_aware, tz_offset=self.server_tz_offset):
assert self.condition_set.get_field_value(None, 'now_is_on_or_after') == self.server_dt

@override_settings(USE_TZ=False, TIME_ZONE=None)
@timezone.override(None)
def test_no_use_tz_without_active(self):
with freeze_time(self.server_dt_aware, tz_offset=self.server_tz_offset):
assert self.condition_set.get_field_value(None, 'now_is_on_or_after') == self.server_dt


class ActiveTimezoneTodayConditionSetTests(TestCase):
def setUp(self):
"""
Assume we have:
- server with `America/Chicago` timezone
- app with `America/New_York` timezone (if Django timezone support enabled)
- current timezone `Europe/Moscow` (if active)
- then it is 2016-01-01T00:00:00 at server
"""
self.condition_set = ActiveTimezoneTodayConditionSet()
self.server_dt = datetime.datetime(2016, 1, 1, 0, 0, 0)
self.server_tz = pytz.timezone('America/Chicago')
self.server_dt_aware = self.server_tz.localize(self.server_dt)
self.server_tz_offset = -6
self.app_to_server_tz_offset = datetime.timedelta(hours=1)
self.active_to_server_tz_offset = datetime.timedelta(hours=9)

@override_settings(USE_TZ=True, TIME_ZONE="America/New_York")
@timezone.override('Europe/Moscow')
def test_use_tz_with_active(self):
with freeze_time(self.server_dt_aware, tz_offset=self.server_tz_offset):
assert (
self.condition_set.get_field_value(None, 'now_is_on_or_after') ==
self.server_dt + self.active_to_server_tz_offset
)

@override_settings(USE_TZ=True, TIME_ZONE="America/New_York")
@timezone.override(None)
def test_use_tz_no_active(self):
with freeze_time(self.server_dt_aware, tz_offset=self.server_tz_offset):
assert (
self.condition_set.get_field_value(None, 'now_is_on_or_after') ==
self.server_dt + self.app_to_server_tz_offset
)

@override_settings(USE_TZ=False, TIME_ZONE=None)
@timezone.override('Europe/Moscow')
def test_no_use_tz_with_active(self):
with freeze_time(self.server_dt_aware, tz_offset=self.server_tz_offset):
assert self.condition_set.get_field_value(None, 'now_is_on_or_after') == self.server_dt

@override_settings(USE_TZ=False, TIME_ZONE=None)
@timezone.override(None)
def test_no_use_tz_without_active(self):
with freeze_time(self.server_dt_aware, tz_offset=self.server_tz_offset):
assert self.condition_set.get_field_value(None, 'now_is_on_or_after') == self.server_dt

0 comments on commit 465407b

Please sign in to comment.