From 01c39088ecc86e88025b8f803ff53a7b6f4e44b9 Mon Sep 17 00:00:00 2001 From: smilerz Date: Tue, 12 Mar 2024 09:14:23 -0500 Subject: [PATCH 1/6] moved deprecated setting STATICFILES_STORAGE to STORAGE['staticfiles'] moved deprecated setting DEFAULT_FILE_STORAGE to STORAGE['default'] --- recipes/settings.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/recipes/settings.py b/recipes/settings.py index a624288182..6a64393967 100644 --- a/recipes/settings.py +++ b/recipes/settings.py @@ -416,8 +416,18 @@ AWS_ENABLED = True if os.getenv('S3_ACCESS_KEY', False) else False +STORAGES = { + "default": { + "BACKEND": "django.core.files.storage.FileSystemStorage", + }, + # Serve static files with gzip + "staticfiles": { + "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage", + }, +} + if os.getenv('S3_ACCESS_KEY', ''): - DEFAULT_FILE_STORAGE = 'cookbook.helper.CustomStorageClass.CachedS3Boto3Storage' + STORAGES['default']['BACKEND'] = 'cookbook.helper.CustomStorageClass.CachedS3Boto3Storage' AWS_ACCESS_KEY_ID = os.getenv('S3_ACCESS_KEY', '') AWS_SECRET_ACCESS_KEY = os.getenv('S3_SECRET_ACCESS_KEY', '') @@ -438,9 +448,6 @@ MEDIA_URL = os.getenv('MEDIA_URL', '/media/') MEDIA_ROOT = os.getenv('MEDIA_ROOT', os.path.join(BASE_DIR, "mediafiles")) -# Serve static files with gzip -STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' - TEST_RUNNER = "cookbook.helper.CustomTestRunner.CustomTestRunner" # settings for cross site origin (CORS) From 688cacc08c10abaaed954258384eaaa4cde1a4cb Mon Sep 17 00:00:00 2001 From: smilerz Date: Tue, 12 Mar 2024 09:31:50 -0500 Subject: [PATCH 2/6] removed deprecated setting I10N --- recipes/settings.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/recipes/settings.py b/recipes/settings.py index 6a64393967..6d53123e24 100644 --- a/recipes/settings.py +++ b/recipes/settings.py @@ -395,8 +395,6 @@ USE_I18N = True -USE_L10N = True - USE_TZ = True LANGUAGES = [('hy', _('Armenian ')), ('bg', _('Bulgarian')), ('ca', _('Catalan')), ('cs', _('Czech')), ('da', _('Danish')), ('nl', _('Dutch')), ('en', _('English')), From 7877b2ab6a53d3edb8558b14730f2f0434be37b4 Mon Sep 17 00:00:00 2001 From: smilerz Date: Wed, 13 Mar 2024 13:10:13 -0500 Subject: [PATCH 3/6] address deprecated .save() in Factory._after_postgeneration --- cookbook/tests/factories/__init__.py | 175 ++++++++++----------------- docs/tests/pytest-badge.svg | 1 - 2 files changed, 67 insertions(+), 109 deletions(-) delete mode 100644 docs/tests/pytest-badge.svg diff --git a/cookbook/tests/factories/__init__.py b/cookbook/tests/factories/__init__.py index 81af9f3fb2..85f14e44ae 100644 --- a/cookbook/tests/factories/__init__.py +++ b/cookbook/tests/factories/__init__.py @@ -1,4 +1,3 @@ - import inspect from datetime import date from decimal import Decimal @@ -45,10 +44,8 @@ class Meta: @register class UserFactory(factory.django.DjangoModelFactory): - """User factory.""" - username = factory.LazyAttribute( - lambda x: faker.simple_profile()['username']) + username = factory.LazyAttribute(lambda x: faker.simple_profile()['username']) first_name = factory.LazyAttribute(lambda x: faker.first_name()) last_name = factory.LazyAttribute(lambda x: faker.last_name()) email = factory.LazyAttribute(lambda x: faker.email()) @@ -60,9 +57,9 @@ def groups(self, create, extracted, **kwargs): return if extracted: - us = UserSpace.objects.create( - space=self.space, user=self, active=True) + us = UserSpace.objects.create(space=self.space, user=self, active=True) us.groups.add(Group.objects.get(name=extracted)) + self.save() @factory.post_generation def userpreference(self, create, extracted, **kwargs): @@ -73,10 +70,12 @@ def userpreference(self, create, extracted, **kwargs): for prefs in extracted: # intentionally break so it can be debugged later self.userpreference[prefs] = extracted[prefs] / 0 + self.save() class Meta: model = User - django_get_or_create = ('username', 'space',) + django_get_or_create = ('username', 'space', ) + skip_postgeneration_save = True @register @@ -88,28 +87,21 @@ class SupermarketCategoryFactory(factory.django.DjangoModelFactory): class Meta: model = 'cookbook.SupermarketCategory' - django_get_or_create = ('name', 'space',) + django_get_or_create = ('name', 'space', ) @register class FoodFactory(factory.django.DjangoModelFactory): """Food factory.""" name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10)[:128]) - plural_name = factory.LazyAttribute( - lambda x: faker.sentence(nb_words=3, variable_nb_words=False)) + plural_name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=3, variable_nb_words=False)) description = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10)) - supermarket_category = factory.Maybe( - factory.LazyAttribute(lambda x: x.has_category), - yes_declaration=factory.SubFactory( - SupermarketCategoryFactory, space=factory.SelfAttribute('..space')), - no_declaration=None - ) - recipe = factory.Maybe( - factory.LazyAttribute(lambda x: x.has_recipe), - yes_declaration=factory.SubFactory( - 'cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')), - no_declaration=None - ) + supermarket_category = factory.Maybe(factory.LazyAttribute(lambda x: x.has_category), + yes_declaration=factory.SubFactory(SupermarketCategoryFactory, space=factory.SelfAttribute('..space')), + no_declaration=None) + recipe = factory.Maybe(factory.LazyAttribute(lambda x: x.has_recipe), + yes_declaration=factory.SubFactory('cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')), + no_declaration=None) path = factory.LazyAttribute(lambda x: faker.numerify(text='%###')) space = factory.SubFactory(SpaceFactory) @@ -121,6 +113,7 @@ def users_onhand(self, create, extracted, **kwargs): if extracted: for user in extracted: self.onhand_users.add(user) + self.save() class Params: has_category = False @@ -128,36 +121,33 @@ class Params: class Meta: model = 'cookbook.Food' - django_get_or_create = ('name', 'plural_name', 'path', 'space',) + django_get_or_create = ('name', 'plural_name', 'path', 'space', ) + skip_postgeneration_save = True @register class RecipeBookFactory(factory.django.DjangoModelFactory): """RecipeBook factory.""" - name = factory.LazyAttribute(lambda x: faker.sentence( - nb_words=3, variable_nb_words=False)) + name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=3, variable_nb_words=False)) description = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10)) - # shared = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) - created_by = factory.SubFactory( - UserFactory, space=factory.SelfAttribute('..space')) + created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) filter = None space = factory.SubFactory(SpaceFactory) class Meta: model = 'cookbook.RecipeBook' - django_get_or_create = ('name', 'space',) + django_get_or_create = ('name', 'space', ) @register class RecipeBookEntryFactory(factory.django.DjangoModelFactory): """RecipeBookEntry factory.""" - book = factory.SubFactory( - RecipeBookFactory, space=factory.SelfAttribute('..recipe.space')) + book = factory.SubFactory(RecipeBookFactory, space=factory.SelfAttribute('..recipe.space')) recipe = None class Meta: model = 'cookbook.RecipeBookEntry' - django_get_or_create = ('book', 'recipe',) + django_get_or_create = ('book', 'recipe', ) @register @@ -170,15 +160,13 @@ class UnitFactory(factory.django.DjangoModelFactory): class Meta: model = 'cookbook.Unit' - django_get_or_create = ('name', 'plural_name', 'space',) + django_get_or_create = ('name', 'plural_name', 'space', ) @register class KeywordFactory(factory.django.DjangoModelFactory): """Keyword factory.""" - name = factory.LazyAttribute(lambda x: faker.sentence( - nb_words=2, variable_nb_words=False)) - # icon = models.CharField(max_length=16, blank=True, null=True) + name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=2, variable_nb_words=False)) description = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10)) space = factory.SubFactory(SpaceFactory) num = None # used on upstream factories to generate num keywords @@ -195,10 +183,8 @@ class Meta: @register class IngredientFactory(factory.django.DjangoModelFactory): """Ingredient factory.""" - food = factory.SubFactory( - FoodFactory, space=factory.SelfAttribute('..space')) - unit = factory.SubFactory( - UnitFactory, space=factory.SelfAttribute('..space')) + food = factory.SubFactory(FoodFactory, space=factory.SelfAttribute('..space')) + unit = factory.SubFactory(UnitFactory, space=factory.SelfAttribute('..space')) amount = factory.LazyAttribute(lambda x: faker.random_int(min=1, max=10)) note = factory.LazyAttribute(lambda x: faker.sentence(nb_words=8)) is_header = False @@ -216,8 +202,7 @@ class MealTypeFactory(factory.django.DjangoModelFactory): # icon = color = factory.LazyAttribute(lambda x: faker.safe_hex_color()) default = False - created_by = factory.SubFactory( - UserFactory, space=factory.SelfAttribute('..space')) + created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) space = factory.SubFactory(SpaceFactory) class Meta: @@ -226,19 +211,13 @@ class Meta: @register class MealPlanFactory(factory.django.DjangoModelFactory): - recipe = factory.Maybe( - factory.LazyAttribute(lambda x: x.has_recipe), - yes_declaration=factory.SubFactory( - 'cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')), - no_declaration=None - ) - servings = factory.LazyAttribute( - lambda x: Decimal(faker.random_int(min=1, max=1000) / 100)) + recipe = factory.Maybe(factory.LazyAttribute(lambda x: x.has_recipe), + yes_declaration=factory.SubFactory('cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')), + no_declaration=None) + servings = factory.LazyAttribute(lambda x: Decimal(faker.random_int(min=1, max=1000) / 100)) title = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5)) - created_by = factory.SubFactory( - UserFactory, space=factory.SelfAttribute('..space')) - meal_type = factory.SubFactory( - MealTypeFactory, space=factory.SelfAttribute('..space')) + created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) + meal_type = factory.SubFactory(MealTypeFactory, space=factory.SelfAttribute('..space')) note = factory.LazyAttribute(lambda x: faker.paragraph()) from_date = factory.LazyAttribute(lambda x: faker.future_date()) to_date = factory.LazyAttribute(lambda x: faker.future_date()) @@ -254,15 +233,11 @@ class Meta: @register class ShoppingListRecipeFactory(factory.django.DjangoModelFactory): name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5)) - recipe = factory.Maybe( - factory.LazyAttribute(lambda x: x.has_recipe), - yes_declaration=factory.SubFactory( - 'cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')), - no_declaration=None - ) + recipe = factory.Maybe(factory.LazyAttribute(lambda x: x.has_recipe), + yes_declaration=factory.SubFactory('cookbook.tests.factories.RecipeFactory', space=factory.SelfAttribute('..space')), + no_declaration=None) servings = factory.LazyAttribute(lambda x: faker.random_int(min=1, max=10)) - mealplan = factory.SubFactory( - MealPlanFactory, space=factory.SelfAttribute('..space')) + mealplan = factory.SubFactory(MealPlanFactory, space=factory.SelfAttribute('..space')) space = factory.SubFactory(SpaceFactory) class Params: @@ -276,23 +251,16 @@ class Meta: class ShoppingListEntryFactory(factory.django.DjangoModelFactory): """ShoppingListEntry factory.""" - list_recipe = factory.Maybe( - factory.LazyAttribute(lambda x: x.has_mealplan), - yes_declaration=factory.SubFactory( - ShoppingListRecipeFactory, space=factory.SelfAttribute('..space')), - no_declaration=None - ) - food = factory.SubFactory( - FoodFactory, space=factory.SelfAttribute('..space')) - unit = factory.SubFactory( - UnitFactory, space=factory.SelfAttribute('..space')) - # # ingredient = factory.SubFactory(IngredientFactory) - amount = factory.LazyAttribute( - lambda x: Decimal(faker.random_int(min=1, max=100)) / 10) + list_recipe = factory.Maybe(factory.LazyAttribute(lambda x: x.has_mealplan), + yes_declaration=factory.SubFactory(ShoppingListRecipeFactory, space=factory.SelfAttribute('..space')), + no_declaration=None) + food = factory.SubFactory(FoodFactory, space=factory.SelfAttribute('..space')) + unit = factory.SubFactory(UnitFactory, space=factory.SelfAttribute('..space')) + # ingredient = factory.SubFactory(IngredientFactory) + amount = factory.LazyAttribute(lambda x: Decimal(faker.random_int(min=1, max=100)) / 10) order = factory.Sequence(int) checked = False - created_by = factory.SubFactory( - UserFactory, space=factory.SelfAttribute('..space')) + created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) created_at = factory.LazyAttribute(lambda x: faker.past_date()) completed_at = None delay_until = None @@ -302,8 +270,7 @@ class ShoppingListEntryFactory(factory.django.DjangoModelFactory): # override create to prevent auto_add_now from changing the created_at date def _create(cls, target_class, *args, **kwargs): created_at = kwargs.pop('created_at', None) - obj = super(ShoppingListEntryFactory, cls)._create( - target_class, *args, **kwargs) + obj = super(ShoppingListEntryFactory, cls)._create(target_class, *args, **kwargs) if created_at is not None: obj.created_at = created_at obj.save() @@ -319,8 +286,7 @@ class Meta: @register class StepFactory(factory.django.DjangoModelFactory): name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5)) - instruction = factory.LazyAttribute( - lambda x: ''.join(faker.paragraphs(nb=5))) + instruction = factory.LazyAttribute(lambda x: ''.join(faker.paragraphs(nb=5))) # TODO add optional recipe food, make dependent on recipe, make number of recipes a Params ingredients__count = 10 # default number of ingredients to add ingredients__header = 0 @@ -342,6 +308,7 @@ def step_recipe(self, create, extracted, **kwargs): self.step_recipe = RecipeFactory(space=self.space) elif extracted: self.step_recipe = extracted + self.save() @factory.post_generation def ingredients(self, create, extracted, **kwargs): @@ -357,19 +324,19 @@ def ingredients(self, create, extracted, **kwargs): num_food_recipe = num_food_recipe - 1 else: has_recipe = False - self.ingredients.add(IngredientFactory( - space=self.space, food__has_recipe=has_recipe)) + self.ingredients.add(IngredientFactory(space=self.space, food__has_recipe=has_recipe)) num_header = kwargs.get('header', 0) if num_header > 0: for i in range(num_header): - self.ingredients.add(IngredientFactory( - food=None, unit=None, amount=0, is_header=True, space=self.space)) + self.ingredients.add(IngredientFactory(food=None, unit=None, amount=0, is_header=True, space=self.space)) elif extracted: for ing in extracted: self.ingredients.add(ing) + self.save() class Meta: model = 'cookbook.Step' + skip_postgeneration_save = True @register @@ -384,15 +351,11 @@ class RecipeFactory(factory.django.DjangoModelFactory): steps__recipe_count = 0 # default number of step recipes to create # by default, don't create food recipes, to override {'steps__food_recipe_count': {'step': 0, 'count': 1}} steps__food_recipe_count = {} - working_time = factory.LazyAttribute( - lambda x: faker.random_int(min=0, max=360)) - waiting_time = factory.LazyAttribute( - lambda x: faker.random_int(min=0, max=360)) + working_time = factory.LazyAttribute(lambda x: faker.random_int(min=0, max=360)) + waiting_time = factory.LazyAttribute(lambda x: faker.random_int(min=0, max=360)) internal = False - created_by = factory.SubFactory( - UserFactory, space=factory.SelfAttribute('..space')) - created_at = factory.LazyAttribute(lambda x: faker.date_between_dates( - date_start=date(2000, 1, 1), date_end=date(2020, 12, 31))) + created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) + created_at = factory.LazyAttribute(lambda x: faker.date_between_dates(date_start=date(2000, 1, 1), date_end=date(2020, 12, 31))) space = factory.SubFactory(SpaceFactory) @classmethod @@ -419,6 +382,7 @@ def keywords(self, create, extracted, **kwargs): elif extracted: for kw in extracted: self.keywords.add(kw) + self.save() @factory.post_generation def steps(self, create, extracted, **kwargs): @@ -434,28 +398,26 @@ def steps(self, create, extracted, **kwargs): ing_recipe_count = 0 if food_recipe_count.get('step', None) == i: ing_recipe_count = food_recipe_count.get('count', 0) - self.steps.add(StepFactory( - space=self.space, ingredients__food_recipe_count=ing_recipe_count, ingredients__header=num_ing_headers)) - num_ing_headers + - 1 + self.steps.add(StepFactory(space=self.space, ingredients__food_recipe_count=ing_recipe_count, ingredients__header=num_ing_headers)) + num_ing_headers + -1 if num_recipe_steps > 0: for j in range(num_recipe_steps): - self.steps.add(StepFactory( - space=self.space, step_recipe__has_recipe=True, ingredients__count=0)) + self.steps.add(StepFactory(space=self.space, step_recipe__has_recipe=True, ingredients__count=0)) if extracted and (num_steps + num_recipe_steps == 0): for step in extracted: self.steps.add(step) + self.save() class Meta: model = 'cookbook.Recipe' + skip_postgeneration_save = True @register class CookLogFactory(factory.django.DjangoModelFactory): """CookLog factory.""" - recipe = factory.SubFactory( - RecipeFactory, space=factory.SelfAttribute('..space')) - created_by = factory.SubFactory( - UserFactory, space=factory.SelfAttribute('..space')) + recipe = factory.SubFactory(RecipeFactory, space=factory.SelfAttribute('..space')) + created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) created_at = factory.LazyAttribute(lambda x: faker.date_this_decade()) rating = factory.LazyAttribute(lambda x: faker.random_int(min=1, max=5)) servings = factory.LazyAttribute(lambda x: faker.random_int(min=1, max=32)) @@ -478,12 +440,9 @@ class Meta: @register class ViewLogFactory(factory.django.DjangoModelFactory): """ViewLog factory.""" - recipe = factory.SubFactory( - RecipeFactory, space=factory.SelfAttribute('..space')) - created_by = factory.SubFactory( - UserFactory, space=factory.SelfAttribute('..space')) - created_at = factory.LazyAttribute( - lambda x: faker.past_datetime(start_date='-365d')) + recipe = factory.SubFactory(RecipeFactory, space=factory.SelfAttribute('..space')) + created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) + created_at = factory.LazyAttribute(lambda x: faker.past_datetime(start_date='-365d')) space = factory.SubFactory(SpaceFactory) @classmethod diff --git a/docs/tests/pytest-badge.svg b/docs/tests/pytest-badge.svg deleted file mode 100644 index 7a41b959f0..0000000000 --- a/docs/tests/pytest-badge.svg +++ /dev/null @@ -1 +0,0 @@ -tests: 785tests785 \ No newline at end of file From 5cb7272801a39673982d0cce641671f88e5f6f79 Mon Sep 17 00:00:00 2001 From: smilerz Date: Wed, 13 Mar 2024 16:09:25 -0500 Subject: [PATCH 4/6] change all naive datetimes to timezone aware dateimes --- cookbook/tests/api/test_api_meal_plan.py | 17 +++---- cookbook/tests/api/test_api_plan_ical.py | 44 +++++++++++-------- .../tests/api/test_api_shopping_recipe.py | 2 +- cookbook/tests/factories/__init__.py | 9 ++-- .../other/test_recipe_full_text_search.py | 6 +-- recipes/settings.py | 9 ++-- 6 files changed, 47 insertions(+), 40 deletions(-) diff --git a/cookbook/tests/api/test_api_meal_plan.py b/cookbook/tests/api/test_api_meal_plan.py index 3faebf19e3..b44b011d91 100644 --- a/cookbook/tests/api/test_api_meal_plan.py +++ b/cookbook/tests/api/test_api_meal_plan.py @@ -1,10 +1,11 @@ import json -from datetime import datetime, timedelta +from datetime import timedelta import pytest from django.contrib import auth from django.urls import reverse from django_scopes import scope, scopes_disabled +from django.utils import timezone from cookbook.models import MealPlan, MealType from cookbook.tests.factories import RecipeFactory @@ -23,13 +24,13 @@ def meal_type(space_1, u1_s1): @pytest.fixture() def obj_1(space_1, recipe_1_s1, meal_type, u1_s1): - return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=datetime.now(), to_date=datetime.now(), + return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=timezone.now(), to_date=timezone.now(), created_by=auth.get_user(u1_s1)) @pytest.fixture def obj_2(space_1, recipe_1_s1, meal_type, u1_s1): - return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=datetime.now(), to_date=datetime.now(), + return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=timezone.now(), to_date=timezone.now(), created_by=auth.get_user(u1_s1)) @@ -68,15 +69,15 @@ def test_list_filter(obj_1, u1_s1): assert len(response) == 0 response = json.loads( - u1_s1.get(f'{reverse(LIST_URL)}?from_date={(datetime.now() + timedelta(days=2)).strftime("%Y-%m-%d")}').content) + u1_s1.get(f'{reverse(LIST_URL)}?from_date={(timezone.now() + timedelta(days=2)).strftime("%Y-%m-%d")}').content) assert len(response) == 0 response = json.loads( - u1_s1.get(f'{reverse(LIST_URL)}?to_date={(datetime.now() - timedelta(days=2)).strftime("%Y-%m-%d")}').content) + u1_s1.get(f'{reverse(LIST_URL)}?to_date={(timezone.now() - timedelta(days=2)).strftime("%Y-%m-%d")}').content) assert len(response) == 0 response = json.loads(u1_s1.get( - f'{reverse(LIST_URL)}?from_date={(datetime.now() - timedelta(days=2)).strftime("%Y-%m-%d")}&to_date={(datetime.now() + timedelta(days=2)).strftime("%Y-%m-%d")}').content) + f'{reverse(LIST_URL)}?from_date={(timezone.now() - timedelta(days=2)).strftime("%Y-%m-%d")}&to_date={(timezone.now() + timedelta(days=2)).strftime("%Y-%m-%d")}').content) assert len(response) == 1 @@ -116,7 +117,7 @@ def test_add(arg, request, u1_s2, recipe_1_s1, meal_type): r = c.post( reverse(LIST_URL), {'recipe': {'id': recipe_1_s1.id, 'name': recipe_1_s1.name, 'keywords': []}, 'meal_type': {'id': meal_type.id, 'name': meal_type.name}, - 'from_date': (datetime.now()).strftime("%Y-%m-%d"), 'to_date': (datetime.now()).strftime("%Y-%m-%d"), 'servings': 1, 'title': 'test', 'shared': []}, + 'from_date': (timezone.now()).strftime("%Y-%m-%d"), 'to_date': (timezone.now()).strftime("%Y-%m-%d"), 'servings': 1, 'title': 'test', 'shared': []}, content_type='application/json' ) response = json.loads(r.content) @@ -158,7 +159,7 @@ def test_add_with_shopping(u1_s1, meal_type): u1_s1.post( reverse(LIST_URL), {'recipe': {'id': recipe.id, 'name': recipe.name, 'keywords': []}, 'meal_type': {'id': meal_type.id, 'name': meal_type.name}, - 'from_date': (datetime.now()).strftime("%Y-%m-%d"), 'to_date': (datetime.now()).strftime("%Y-%m-%d"), 'servings': 1, 'title': 'test', 'shared': [], 'addshopping': True}, + 'from_date': (timezone.now()).strftime("%Y-%m-%d"), 'to_date': (timezone.now()).strftime("%Y-%m-%d"), 'servings': 1, 'title': 'test', 'shared': [], 'addshopping': True}, content_type='application/json' ) diff --git a/cookbook/tests/api/test_api_plan_ical.py b/cookbook/tests/api/test_api_plan_ical.py index f871d4b48b..18e1e1b227 100644 --- a/cookbook/tests/api/test_api_plan_ical.py +++ b/cookbook/tests/api/test_api_plan_ical.py @@ -1,8 +1,9 @@ -from datetime import datetime, timedelta +from datetime import timedelta import pytest from django.contrib import auth from django.urls import reverse +from django.utils import timezone from icalendar import Calendar from cookbook.models import MealPlan, MealType @@ -19,31 +20,35 @@ def meal_type(space_1, u1_s1): @pytest.fixture() def obj_1(space_1, recipe_1_s1, meal_type, u1_s1): - return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=datetime.now(), to_date=datetime.now(), - created_by=auth.get_user(u1_s1)) + return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=timezone.now(), to_date=timezone.now(), created_by=auth.get_user(u1_s1)) @pytest.fixture def obj_2(space_1, recipe_1_s1, meal_type, u1_s1): - return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=datetime.now()+timedelta(days=30), to_date=datetime.now()+timedelta(days=30), + return MealPlan.objects.create(recipe=recipe_1_s1, + space=space_1, + meal_type=meal_type, + from_date=timezone.now() + timedelta(days=30), + to_date=timezone.now() + timedelta(days=30), created_by=auth.get_user(u1_s1)) + @pytest.fixture def obj_3(space_1, recipe_1_s1, meal_type, u1_s1): - return MealPlan.objects.create(recipe=recipe_1_s1, space=space_1, meal_type=meal_type, from_date=datetime.now()+timedelta(days=-30), to_date=datetime.now()+timedelta(days=-1), + return MealPlan.objects.create(recipe=recipe_1_s1, + space=space_1, + meal_type=meal_type, + from_date=timezone.now() + timedelta(days=-30), + to_date=timezone.now() + timedelta(days=-1), created_by=auth.get_user(u1_s1)) -@pytest.mark.parametrize("arg", [ - ['a_u', 403], - ['g1_s1', 403], - ['u1_s1', 200], - ['a1_s1', 200], -]) +@pytest.mark.parametrize("arg", [['a_u', 403], ['g1_s1', 403], ['u1_s1', 200], ['a1_s1', 200], ]) def test_permissions(arg, request): c = request.getfixturevalue(arg[0]) assert c.get(reverse(FUTURE_URL)).status_code == arg[1] + def test_future(obj_1, obj_2, obj_3, u1_s1): r = u1_s1.get(reverse(FUTURE_URL)) assert r.status_code == 200 @@ -52,8 +57,9 @@ def test_future(obj_1, obj_2, obj_3, u1_s1): events = cal.walk('VEVENT') assert len(events) == 2 + def test_from(obj_1, obj_2, obj_3, u1_s1): - from_date_slug = (datetime.now()+timedelta(days=1)).strftime("%Y-%m-%d") + from_date_slug = (timezone.now() + timedelta(days=1)).strftime("%Y-%m-%d") r = u1_s1.get(reverse(FROM_URL, kwargs={'from_date': from_date_slug})) assert r.status_code == 200 @@ -61,9 +67,10 @@ def test_from(obj_1, obj_2, obj_3, u1_s1): events = cal.walk('VEVENT') assert len(events) == 1 + def test_bound(obj_1, obj_2, obj_3, u1_s1): - from_date_slug = (datetime.now()+timedelta(days=-1)).strftime("%Y-%m-%d") - to_date_slug = (datetime.now()+timedelta(days=1)).strftime("%Y-%m-%d") + from_date_slug = (timezone.now() + timedelta(days=-1)).strftime("%Y-%m-%d") + to_date_slug = (timezone.now() + timedelta(days=1)).strftime("%Y-%m-%d") r = u1_s1.get(reverse(BOUND_URL, kwargs={'from_date': from_date_slug, 'to_date': to_date_slug})) assert r.status_code == 200 @@ -71,9 +78,10 @@ def test_bound(obj_1, obj_2, obj_3, u1_s1): events = cal.walk('VEVENT') assert len(events) == 1 + def test_event(obj_1, u1_s1): - from_date_slug = (datetime.now()+timedelta(days=-1)).strftime("%Y-%m-%d") - to_date_slug = (datetime.now()+timedelta(days=1)).strftime("%Y-%m-%d") + from_date_slug = (timezone.now() + timedelta(days=-1)).strftime("%Y-%m-%d") + to_date_slug = (timezone.now() + timedelta(days=1)).strftime("%Y-%m-%d") r = u1_s1.get(reverse(BOUND_URL, kwargs={'from_date': from_date_slug, 'to_date': to_date_slug})) cal = Calendar.from_ical(r.getvalue().decode('UTF-8')) @@ -84,5 +92,5 @@ def test_event(obj_1, u1_s1): assert int(event['uid']) == obj_1.id assert event['summary'] == f'{obj_1.meal_type.name}: {obj_1.get_label()}' assert event['description'] == obj_1.note - assert event.decoded('dtstart') == datetime.now().date() - assert event.decoded('dtend') == datetime.now().date() + assert event.decoded('dtstart') == timezone.now().date() + assert event.decoded('dtend') == timezone.now().date() diff --git a/cookbook/tests/api/test_api_shopping_recipe.py b/cookbook/tests/api/test_api_shopping_recipe.py index 5001aca228..ad5cecfe50 100644 --- a/cookbook/tests/api/test_api_shopping_recipe.py +++ b/cookbook/tests/api/test_api_shopping_recipe.py @@ -7,7 +7,7 @@ from django.urls import reverse from django_scopes import scopes_disabled -from cookbook.models import Food, Ingredient, ShoppingListRecipe, ShoppingListEntry +from cookbook.models import Food, Ingredient, ShoppingListEntry from cookbook.tests.factories import MealPlanFactory, RecipeFactory, StepFactory, UserFactory if settings.DATABASES['default']['ENGINE'] == 'django.db.backends.postgresql': diff --git a/cookbook/tests/factories/__init__.py b/cookbook/tests/factories/__init__.py index 85f14e44ae..b12ffd11ee 100644 --- a/cookbook/tests/factories/__init__.py +++ b/cookbook/tests/factories/__init__.py @@ -4,6 +4,7 @@ import factory import pytest +import pytz from django.contrib.auth.models import Group, User from django_scopes import scopes_disabled from faker import Factory as FakerFactory @@ -219,8 +220,8 @@ class MealPlanFactory(factory.django.DjangoModelFactory): created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) meal_type = factory.SubFactory(MealTypeFactory, space=factory.SelfAttribute('..space')) note = factory.LazyAttribute(lambda x: faker.paragraph()) - from_date = factory.LazyAttribute(lambda x: faker.future_date()) - to_date = factory.LazyAttribute(lambda x: faker.future_date()) + from_date = factory.LazyAttribute(lambda x: faker.future_date(tzinfo=pytz.UTC)) + to_date = factory.LazyAttribute(lambda x: faker.future_date(tzinfo=pytz.UTC)) space = factory.SubFactory(SpaceFactory) class Params: @@ -261,7 +262,7 @@ class ShoppingListEntryFactory(factory.django.DjangoModelFactory): order = factory.Sequence(int) checked = False created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) - created_at = factory.LazyAttribute(lambda x: faker.past_date()) + created_at = factory.LazyAttribute(lambda x: faker.past_date(tzinfo=pytz.UTC)) completed_at = None delay_until = None space = factory.SubFactory(SpaceFactory) @@ -355,7 +356,7 @@ class RecipeFactory(factory.django.DjangoModelFactory): waiting_time = factory.LazyAttribute(lambda x: faker.random_int(min=0, max=360)) internal = False created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) - created_at = factory.LazyAttribute(lambda x: faker.date_between_dates(date_start=date(2000, 1, 1), date_end=date(2020, 12, 31))) + created_at = factory.LazyAttribute(lambda x: faker.date_between_dates(date_start=pytz.UTC.localize(date(2000, 1, 1)), date_end=pytz.UTC.localize(date(2020, 12, 31)))) space = factory.SubFactory(SpaceFactory) @classmethod diff --git a/cookbook/tests/other/test_recipe_full_text_search.py b/cookbook/tests/other/test_recipe_full_text_search.py index b6b7a858fc..ef95e39674 100644 --- a/cookbook/tests/other/test_recipe_full_text_search.py +++ b/cookbook/tests/other/test_recipe_full_text_search.py @@ -1,9 +1,9 @@ import itertools import json -from datetime import timedelta, datetime +from datetime import timedelta import pytest -import pytz + from django.conf import settings from django.contrib import auth from django.urls import reverse @@ -344,7 +344,7 @@ def test_search_date(found_recipe, recipes, param_type, result, u1_s1, u2_s1, sp Recipe.objects.filter(id=recipe.id).update( updated_at=recipe.created_at) - date = (datetime.now() - timedelta(days=15)).strftime("%Y-%m-%d") + date = (timezone.now() - timedelta(days=15)).strftime("%Y-%m-%d") param1 = f"?{param_type}={date}" param2 = f"?{param_type}=-{date}" r = json.loads(u1_s1.get(reverse(LIST_URL) + f'{param1}').content) diff --git a/recipes/settings.py b/recipes/settings.py index 6d53123e24..14451ffe99 100644 --- a/recipes/settings.py +++ b/recipes/settings.py @@ -440,13 +440,10 @@ if os.getenv('S3_CUSTOM_DOMAIN', ''): AWS_S3_CUSTOM_DOMAIN = os.getenv('S3_CUSTOM_DOMAIN', '') - MEDIA_URL = os.getenv('MEDIA_URL', '/media/') - MEDIA_ROOT = os.getenv('MEDIA_ROOT', os.path.join(BASE_DIR, "mediafiles")) -else: - MEDIA_URL = os.getenv('MEDIA_URL', '/media/') - MEDIA_ROOT = os.getenv('MEDIA_ROOT', os.path.join(BASE_DIR, "mediafiles")) +MEDIA_URL = os.getenv('MEDIA_URL', '/media/') +MEDIA_ROOT = os.getenv('MEDIA_ROOT', os.path.join(BASE_DIR, "mediafiles")) -TEST_RUNNER = "cookbook.helper.CustomTestRunner.CustomTestRunner" +# TEST_RUNNER = "cookbook.helper.CustomTestRunner.CustomTestRunner" # settings for cross site origin (CORS) # all origins allowed to support bookmarklet From bcf4843b256d628c6ff43bfc67372b1b293d49ba Mon Sep 17 00:00:00 2001 From: smilerz Date: Wed, 13 Mar 2024 16:10:16 -0500 Subject: [PATCH 5/6] add ability to run tests in parrallel --- .vscode/launch.json | 52 ++++++++++++++++++++++++++++++--------------- pytest.ini | 3 ++- requirements.txt | 1 + 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index e1c25328c0..0f90ec420b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,18 +1,36 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - - { - "name": "Python Debugger: Django", - "type": "debugpy", - "request": "launch", - "program": "${workspaceFolder}/manage.py", - "args": ["runserver"], - "django": true, - "justMyCode": true - } - ] - } \ No newline at end of file + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: Django", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/manage.py", + "args": [ + "runserver" + ], + "django": true, + "justMyCode": true + }, + { + "name": "Python: Debug Tests", + "type": "debugpy", + "request": "launch", + "program": "${file}", + "purpose": [ + "debug-test" + ], + "console": "integratedTerminal", + "env": { + // coverage and pytest can't both be running at the same time + "PYTEST_ADDOPTS": "--no-cov", + "DATABASES": "{'default': {'ENGINE': 'django.db.backends.sqlite3'}}" + }, + "django": true, + "justMyCode": true + }, + ] +} diff --git a/pytest.ini b/pytest.ini index c1b192b408..98f4f73f1b 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,4 +1,5 @@ [pytest] DJANGO_SETTINGS_MODULE = recipes.settings +testpaths = cookbook/tests python_files = tests.py test_*.py *_tests.py -addopts = --cov=. --cov-report=html:docs/reports/coverage --cov-report=xml:docs/reports/coverage/coverage.xml --junitxml=docs/reports/tests/pytest.xml --html=docs/reports/tests/tests.html +addopts = -n auto --durations=0 --cov=. --cov-report=html:docs/reports/coverage --cov-report=xml:docs/reports/coverage/coverage.xml --junitxml=docs/reports/tests/pytest.xml --html=docs/reports/tests/tests.html diff --git a/requirements.txt b/requirements.txt index 23315b785c..43dd1e9cbc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -52,3 +52,4 @@ pytest-cov===4.1.0 pytest-factoryboy==2.6.0 pytest-html==4.1.1 pytest-asyncio==0.23.5 +pytest-xdist==3.5.0 From 98654d9aca275409a83af5aae574fc0f86323bed Mon Sep 17 00:00:00 2001 From: smilerz Date: Thu, 14 Mar 2024 08:36:16 -0500 Subject: [PATCH 6/6] fixed timezone aware setup in factories --- cookbook/tests/factories/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cookbook/tests/factories/__init__.py b/cookbook/tests/factories/__init__.py index b12ffd11ee..022386aa34 100644 --- a/cookbook/tests/factories/__init__.py +++ b/cookbook/tests/factories/__init__.py @@ -1,5 +1,5 @@ import inspect -from datetime import date +from datetime import datetime from decimal import Decimal import factory @@ -356,7 +356,7 @@ class RecipeFactory(factory.django.DjangoModelFactory): waiting_time = factory.LazyAttribute(lambda x: faker.random_int(min=0, max=360)) internal = False created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) - created_at = factory.LazyAttribute(lambda x: faker.date_between_dates(date_start=pytz.UTC.localize(date(2000, 1, 1)), date_end=pytz.UTC.localize(date(2020, 12, 31)))) + created_at = factory.LazyAttribute(lambda x: faker.date_between_dates(date_start=pytz.UTC.localize(datetime(2000, 1, 1)), date_end=pytz.UTC.localize(datetime(2020, 12, 31)))) space = factory.SubFactory(SpaceFactory) @classmethod