def setUp(self): self.now = timezone.now() self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.store = StoreFactory(group=self.group) self.series = PickupDateSeriesFactory(max_collectors=3, store=self.store) self.series.update_pickup_dates(start=lambda: self.now)
class PickupDateSeriesReceiverTests(WSTestCase): def setUp(self): super().setUp() self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.store = StoreFactory(group=self.group) # Create far in the future to generate no pickup dates # They would lead to interfering websocket messages self.series = PickupDateSeriesFactory(store=self.store, start_date=timezone.now() + relativedelta(months=2)) def test_receive_series_changes(self): self.client = self.connect_as(self.member) date = faker.future_datetime(end_date='+30d', tzinfo=timezone.utc) + relativedelta(months=2) self.series.start_date = date self.series.save() response = self.client.messages_by_topic.get('pickups:series')[0] self.assertEqual(parse(response['payload']['start_date']), date) self.assertEqual(len(self.client.messages), 1) def test_receive_series_delete(self): self.client = self.connect_as(self.member) id = self.series.id self.series.delete() response = self.client.messages_by_topic.get('pickups:series_deleted')[0] self.assertEqual(response['payload']['id'], id) self.assertEqual(len(self.client.messages), 1)
def setUp(self): self.url = '/api/pickup-dates/' # pickup date for group with one member and one store self.member = UserFactory() self.group = GroupFactory(members=[ self.member, ]) self.store = StoreFactory(group=self.group) self.pickup = PickupDateFactory(store=self.store) # and another store + group + pick-update self.group2 = GroupFactory(members=[ self.member, ]) self.store2 = StoreFactory(group=self.group2) self.pickup2 = PickupDateFactory(store=self.store2) # a pickup date series self.series = PickupDateSeriesFactory(store=self.store) self.series.update_pickup_dates() # another pickup date series self.series2 = PickupDateSeriesFactory(store=self.store) self.series2.update_pickup_dates()
def setUp(self): self.client = WSClient() self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.store = StoreFactory(group=self.group) # Create far in the future to generate no pickup dates # They would lead to interfering websocket messages self.series = PickupDateSeriesFactory(store=self.store, start_date=timezone.now() + relativedelta(months=2))
def setUp(self): self.now = timezone.now() self.url = '/api/stores/' self.member = UserFactory() self.group = GroupFactory(members=[self.member, ]) self.store = StoreFactory(group=self.group) self.store_url = self.url + str(self.store.id) + '/' self.series = PickupDateSeriesFactory(max_collectors=3, store=self.store) self.series.update_pickup_dates(start=lambda: self.now)
class TestStoreChangesPickupDateSeriesAPI(APITestCase, ExtractPaginationMixin): def setUp(self): self.now = timezone.now() self.url = '/api/stores/' self.member = UserFactory() self.group = GroupFactory(members=[self.member, ]) self.store = StoreFactory(group=self.group) self.store_url = self.url + str(self.store.id) + '/' self.series = PickupDateSeriesFactory(max_collectors=3, store=self.store) self.series.update_pickup_dates(start=lambda: self.now) def test_reduce_weeks_in_advance(self): self.client.force_login(user=self.member) url = '/api/pickup-dates/' response = self.get_results(url, {'series': self.series.id, 'date_0': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) response = self.client.patch(self.store_url, {'weeks_in_advance': 2}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['weeks_in_advance'], 2) url = '/api/pickup-dates/' response = self.get_results(url, {'series': self.series.id}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) for _ in response.data: self.assertLessEqual(parse(_['date']), self.now + relativedelta(weeks=2, hours=1)) def test_increase_weeks_in_advance(self): self.client.force_login(user=self.member) url = '/api/pickup-dates/' response = self.get_results(url, {'series': self.series.id, 'date_0': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) original_dates = [parse(_['date']) for _ in response.data] response = self.client.patch(self.store_url, {'weeks_in_advance': 10}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['weeks_in_advance'], 10) url = '/api/pickup-dates/' response = self.get_results(url, {'series': self.series.id}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertGreater(len(response.data), len(original_dates)) for return_date in response.data: self.assertLessEqual(parse(return_date['date']), self.now + relativedelta(weeks=10)) def test_set_weeks_to_invalid_value(self): self.client.force_login(user=self.member) response = self.client.patch(self.store_url, {'weeks_in_advance': 0}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.data)
def test_delete(self): now = timezone.now() two_weeks_ago = now - relativedelta(weeks=2) with freeze_time(two_weeks_ago, tick=True): series = PickupDateSeriesFactory(store=self.store, start_date=two_weeks_ago) pickup_dates = series.pickup_dates.all() past_date_count = pickup_dates.filter(date__lt=now).count() self.assertGreater(pickup_dates.count(), 2) series.delete() upcoming_pickups = PickupDate.objects.filter(date__gte=now, is_disabled=False) self.assertEqual(upcoming_pickups.count(), 0, upcoming_pickups) self.assertEqual(PickupDate.objects.filter(date__lt=now).count(), past_date_count)
def setUp(self): self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.store = StoreFactory(group=self.group) self.pickup = PickupDateFactory(store=self.store) self.pickup_url = '/api/pickup-dates/{}/'.format(self.pickup.id) self.series = PickupDateSeriesFactory(store=self.store) self.series_url = '/api/pickup-date-series/{}/'.format(self.series.id)
def setUp(self): self.url = '/api/pickup-date-series/' self.series = PickupDateSeriesFactory() self.series_url = '/api/pickup-date-series/{}/'.format(self.series.id) self.non_member = UserFactory() self.series_data = { 'store': self.series.store.id, 'rule': 'FREQ=WEEKLY', 'start_date': timezone.now() }
def test_create_all_pickup_dates_inactive_stores(self): self.store.status = StoreStatus.ARCHIVED.value self.store.save() start_date = self.store.group.timezone.localize(datetime.now().replace(2017, 3, 18, 15, 0, 0, 0)) PickupDateSeriesFactory(store=self.store, start_date=start_date) PickupDate.objects.all().delete() PickupDateSeries.objects.update_pickups() self.assertEqual(PickupDate.objects.count(), 0)
def test_daylight_saving_time_to_winter(self): start_date = self.store.group.timezone.localize(datetime.now().replace(2016, 10, 22, 15, 0, 0, 0)) before_dst_switch = timezone.now().replace(2016, 10, 22, 4, 40, 13) with freeze_time(before_dst_switch, tick=True): series = PickupDateSeriesFactory(store=self.store, start_date=start_date) expected_dates = [] for month, day in [(10, 22), (10, 29), (11, 5), (11, 12)]: expected_dates.append(self.store.group.timezone.localize(datetime(2016, month, day, 15, 0))) for actual_date, expected_date in zip(PickupDate.objects.filter(series=series), expected_dates): self.assertEqual(actual_date.date, expected_date)
class PickupDateSeriesReceiverTests(ChannelTestCase): def setUp(self): self.client = WSClient() self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.store = StoreFactory(group=self.group) # Create far in the future to generate no pickup dates # They would lead to interfering websocket messages self.series = PickupDateSeriesFactory(store=self.store, start_date=timezone.now() + relativedelta(months=2)) def test_receive_series_changes(self): self.client.force_login(self.member) self.client.send_and_consume('websocket.connect', path='/') date = faker.future_datetime( end_date='+30d', tzinfo=timezone.utc) + relativedelta(months=2) self.series.start_date = date self.series.save() response = self.client.receive(json=True) self.assertEqual(response['topic'], 'pickups:series') self.assertEqual(parse(response['payload']['start_date']), date) self.assertIsNone(self.client.receive(json=True)) def test_receive_series_delete(self): self.client.force_login(self.member) self.client.send_and_consume('websocket.connect', path='/') id = self.series.id self.series.delete() response = self.client.receive(json=True) self.assertEqual(response['topic'], 'pickups:series_deleted') self.assertEqual(response['payload']['id'], id) self.assertIsNone(self.client.receive(json=True))
def test_delete_stores_as_group_member(self): PickupDateSeriesFactory(store=self.store) PickupDateFactory(store=self.store) self.client.force_login(user=self.member) response = self.client.delete(self.store_url) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) response = self.client.get(self.url) self.assertEqual(len(response.data), 0) # should also delete pickup dates & series response = self.get_results('/api/pickup-dates/') self.assertEqual(len(response.data), 0) response = self.client.get('/api/pickup-date-series/') self.assertEqual(len(response.data), 0)
class TestPickupdatesAPIFilter(APITestCase, ExtractPaginationMixin): def setUp(self): self.url = '/api/pickup-dates/' # pickup date for group with one member and one store self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.store = StoreFactory(group=self.group) self.pickup = PickupDateFactory(store=self.store) # and another store + group + pick-update self.group2 = GroupFactory(members=[self.member]) self.store2 = StoreFactory(group=self.group2) self.pickup2 = PickupDateFactory(store=self.store2) # a pickup date series self.series = PickupDateSeriesFactory(store=self.store) self.series.update_pickup_dates() # another pickup date series self.series2 = PickupDateSeriesFactory(store=self.store) self.series2.update_pickup_dates() def test_filter_by_store(self): self.client.force_login(user=self.member) response = self.get_results(self.url, {'store': self.store.id}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) for _ in response.data: self.assertEqual(_['store'], self.store.id) self.assertEqual(len(response.data), self.store.pickup_dates.count()) def test_filter_by_group(self): self.client.force_login(user=self.member) response = self.get_results(self.url, {'group': self.group.id}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) store_ids = [_.id for _ in self.group.store.all()] for _ in response.data: self.assertTrue(_['store'] in store_ids) self.assertEqual(len(response.data), sum([store.pickup_dates.count() for store in self.group.store.all()])) def test_filter_by_series(self): self.client.force_login(user=self.member) response = self.get_results(self.url, {'series': self.series.id}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) for _ in response.data: self.assertEqual(_['series'], self.series.id) self.assertEqual(len(response.data), self.series.pickup_dates.count()) def test_filter_after_date(self): self.client.force_login(user=self.member) query_date = self.pickup.date + timedelta(days=1) response = self.get_results(self.url, {'date_min': query_date}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) for _ in response.data: self.assertGreater(parse(_['date']), query_date) selected_pickups = PickupDateModel.objects.filter(store__group__members=self.member) \ .filter(date__gte=query_date) self.assertEqual(len(response.data), selected_pickups.count()) def test_filter_before_date(self): self.client.force_login(user=self.member) query_date = self.pickup.date + timedelta(days=10) response = self.get_results(self.url, {'date_max': query_date}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) for _ in response.data: self.assertLess(parse(_['date']), query_date) selected_pickups = PickupDateModel.objects.filter(store__group__members=self.member) \ .filter(date__lte=query_date) self.assertEqual(len(response.data), selected_pickups.count())
def setUp(self): self.url = '/api/pickup-date-series/' self.series = PickupDateSeriesFactory() self.series_url = '/api/pickup-date-series/{}/'.format(self.series.id) self.non_member = UserFactory()
class TestPickupDateSeriesChangeAPI(APITestCase, ExtractPaginationMixin): """ This is an integration test for the pickup-date-series API with pre-created series """ def setUp(self): self.now = timezone.now() self.member = UserFactory() self.group = GroupFactory(members=[ self.member, ]) self.store = StoreFactory(group=self.group) self.series = PickupDateSeriesFactory(max_collectors=3, store=self.store) self.series.update_pickup_dates(start=lambda: self.now) def test_change_max_collectors_for_series(self): "should change all future instances (except for individually changed ones), but not past ones" url = '/api/pickup-date-series/{}/'.format(self.series.id) self.client.force_login(user=self.member) response = self.client.patch(url, {'max_collectors': 99}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['max_collectors'], 99) url = '/api/pickup-dates/' response = self.get_results(url, { 'series': self.series.id, 'date_0': self.now }) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) for _ in response.data: self.assertEqual(_['max_collectors'], 99) def test_change_series_activates_group(self): self.group.status = GroupStatus.INACTIVE.value self.group.save() url = '/api/pickup-date-series/{}/'.format(self.series.id) self.client.force_login(user=self.member) self.client.patch(url, {'max_collectors': 99}) self.group.refresh_from_db() self.assertEqual(self.group.status, GroupStatus.ACTIVE.value) def test_change_start_time(self): self.client.force_login(user=self.member) # get original times url = '/api/pickup-dates/' response = self.get_results(url, { 'series': self.series.id, 'date_0': self.now }) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) original_dates = [parse(_['date']) for _ in response.data] # change times url = '/api/pickup-date-series/{}/'.format(self.series.id) new_startdate = shift_date_in_local_time( self.series.start_date, relativedelta(hours=2, minutes=20), self.group.timezone) response = self.client.patch(url, {'start_date': new_startdate.isoformat()}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(parse(response.data['start_date']), new_startdate) # compare resulting pickups url = '/api/pickup-dates/' response = self.get_results(url, { 'series': self.series.id, 'date_0': self.now }) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) for response_pickup, old_date in zip(response.data, original_dates): self.assertEqual( parse(response_pickup['date']), shift_date_in_local_time(old_date, relativedelta(hours=2, minutes=20), self.group.timezone)) def test_change_start_date_to_future(self): self.client.force_login(user=self.member) # get original dates url = '/api/pickup-dates/' response = self.get_results(url, { 'series': self.series.id, 'date_0': self.now }) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) original_dates = [parse(_['date']) for _ in response.data] # change dates url = '/api/pickup-date-series/{}/'.format(self.series.id) new_startdate = shift_date_in_local_time(self.series.start_date, relativedelta(days=5), self.group.timezone) response = self.client.patch(url, {'start_date': new_startdate.isoformat()}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(parse(response.data['start_date']), new_startdate) # compare resulting pickups url = '/api/pickup-dates/' response = self.get_results(url, { 'series': self.series.id, 'date_0': self.now }) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) for response_pickup, old_date in zip_longest(response.data, original_dates): self.assertEqual( parse(response_pickup['date']), shift_date_in_local_time(old_date, relativedelta(days=5), self.group.timezone)) def test_change_start_date_to_past(self): self.client.force_login(user=self.member) # get original dates url = '/api/pickup-dates/' response = self.get_results(url, { 'series': self.series.id, 'date_0': self.now }) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) original_dates = [parse(_['date']) for _ in response.data] # change dates url = '/api/pickup-date-series/{}/'.format(self.series.id) new_startdate = shift_date_in_local_time(self.series.start_date, relativedelta(days=-5), self.group.timezone) response = self.client.patch(url, {'start_date': new_startdate.isoformat()}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(parse(response.data['start_date']), new_startdate) # compare resulting pickups url = '/api/pickup-dates/' response = self.get_results(url, { 'series': self.series.id, 'date_0': self.now }) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) # shifting 5 days to the past is similar to shifting 2 days to the future for response_pickup, old_date in zip_longest(response.data, original_dates): new_date = shift_date_in_local_time(old_date, relativedelta(days=2), self.group.timezone) if new_date > self.now + relativedelta( weeks=self.store.weeks_in_advance): # date too far in future self.assertIsNone(response_pickup) else: self.assertEqual(parse(response_pickup['date']), new_date) def test_set_end_date(self): self.client.force_login(user=self.member) # change rule url = '/api/pickup-date-series/{}/'.format(self.series.id) rule = rrulestr(self.series.rule, dtstart=self.now) \ .replace(until=self.now + relativedelta(days=8)) response = self.client.patch(url, {'rule': str(rule)}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['rule'], str(rule)) # compare resulting pickups url = '/api/pickup-dates/' response = self.get_results(url, { 'series': self.series.id, 'date_0': self.now }) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(len(response.data), 2, response.data) def test_set_end_date_with_users_have_joined_pickup(self): self.client.force_login(user=self.member) self.series.pickup_dates.last().collectors.add(self.member) # change rule url = '/api/pickup-date-series/{}/'.format(self.series.id) rule = rrulestr(self.series.rule, dtstart=self.now) \ .replace(until=self.now) response = self.client.patch(url, {'rule': str(rule)}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['rule'], str(rule)) # compare resulting pickups url = '/api/pickup-dates/' response = self.get_results(url, { 'series': self.series.id, 'date_0': self.now }) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(len(response.data), 1, response.data) def test_delete_pickup_series(self): "the series should get removed, as well as all upcoming pickups if they don't have collectors" self.client.force_login(user=self.member) joined_pickup = self.series.pickup_dates.last() joined_pickup.collectors.add(self.member) url = '/api/pickup-date-series/{}/'.format(self.series.id) response = self.client.delete(url) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT, response.data) url = '/api/pickup-dates/' response = self.get_results(url, { 'series': self.series.id, 'date_0': self.now }) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(len(response.data), 0, response.data) url = '/api/pickup-dates/{}/'.format(joined_pickup.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['collector_ids'], [ self.member.id, ]) def test_change_max_collectors_to_invalid_number_fails(self): self.client.force_login(user=self.member) url = '/api/pickup-date-series/{}/'.format(self.series.id) response = self.client.patch(url, {'max_collectors': -1}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.data) def test_set_invalid_store_fails(self): unrelated_store = StoreFactory() self.client.force_login(user=self.member) url = '/api/pickup-date-series/{}/'.format(self.series.id) response = self.client.patch(url, {'store': unrelated_store.id}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.data) self.assertEqual( response.data, {'store': ["You are not member of the store's group."]}) def test_set_multiple_rules_fails(self): self.client.force_login(user=self.member) url = '/api/pickup-date-series/{}/'.format(self.series.id) response = self.client.patch( url, {'rule': 'RRULE:FREQ=WEEKLY;BYDAY=MO\nRRULE:FREQ=MONTHLY'}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.data) self.assertEqual( response.data, {'rule': ['Only single recurrence rules are allowed.']}) def test_keep_changes_to_max_collectors(self): self.client.force_login(user=self.member) pickup_under_test = self.series.pickup_dates.first() url = '/api/pickup-dates/{}/'.format(pickup_under_test.id) # change setting of pickup response = self.client.patch(url, {'max_collectors': 666}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['max_collectors'], 666) # run regular update command of series self.series.update_pickup_dates() # check if changes persist url = '/api/pickup-dates/{}/'.format(pickup_under_test.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['max_collectors'], 666) def test_keep_changes_to_date(self): self.client.force_login(user=self.member) pickup_under_test = self.series.pickup_dates.first() url = '/api/pickup-dates/{}/'.format(pickup_under_test.id) # change setting of pickup target_date = timezone.now() + relativedelta(hours=2) response = self.client.patch(url, {'date': target_date}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(parse(response.data['date']), target_date) # run regular update command of series self.series.update_pickup_dates() # check if changes persist url = '/api/pickup-dates/{}/'.format(pickup_under_test.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(parse(response.data['date']), target_date) def test_keep_changes_to_description(self): self.client.force_login(user=self.member) pickup_under_test = self.series.pickup_dates.first() url = '/api/pickup-dates/{}/'.format(pickup_under_test.id) # change setting of pickup response = self.client.patch(url, {'description': 'asdf'}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['description'], 'asdf') # run regular update command of series self.series.update_pickup_dates() # check if changes persist url = '/api/pickup-dates/{}/'.format(pickup_under_test.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['description'], 'asdf') def test_dont_mark_as_changed_if_data_is_equal(self): self.client.force_login(user=self.member) pickup_under_test = self.series.pickup_dates.first() url = '/api/pickup-dates/{}/'.format(pickup_under_test.id) # change setting of pickup response = self.client.patch( url, { 'date': pickup_under_test.date, 'max_collectors': pickup_under_test.max_collectors }) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) pickup_under_test = PickupDate.objects.get(id=pickup_under_test.id) self.assertFalse(pickup_under_test.is_max_collectors_changed) self.assertFalse(pickup_under_test.is_date_changed) def test_keep_date_if_pickup_has_collectors(self): """ https://github.com/yunity/foodsaving-frontend/issues/596 It's unexpected if the date changes automatically when people have joined """ self.client.force_login(user=self.member) pickup_under_test = self.series.pickup_dates.first() url = '/api/pickup-dates/{}/add/'.format(pickup_under_test.id) # join pickup response = self.client.post(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) original_date = pickup_under_test.date # change series date url = '/api/pickup-date-series/{}/'.format(self.series.id) response = self.client.patch( url, {'start_date': self.series.start_date + relativedelta(hours=1)}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) # check if time of pickup is the same url = '/api/pickup-dates/{}/'.format(pickup_under_test.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(parse(response.data['date']), original_date, "time shouldn't change!") def test_invalid_rule_fails(self): url = '/api/pickup-date-series/{}/'.format(self.series.id) self.client.force_login(user=self.member) response = self.client.patch(url, {'rule': 'FREQ=WEEKLY;BYDAY='}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.data)
def setUp(self): self.series = PickupDateSeriesFactory()
class TestPickupDateSeriesChangeAPI(APITestCase, ExtractPaginationMixin): """ This is an integration test for the pickup-date-series API with pre-created series """ def setUp(self): self.now = timezone.now() self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.store = StoreFactory(group=self.group) self.series = PickupDateSeriesFactory(max_collectors=3, store=self.store) def test_change_max_collectors_for_series(self): "should change all future instances (except for individually changed ones), but not past ones" url = '/api/pickup-date-series/{}/'.format(self.series.id) self.client.force_login(user=self.member) response = self.client.patch(url, {'max_collectors': 99}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['max_collectors'], 99) url = '/api/pickup-dates/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) for _ in response.data: self.assertEqual(_['max_collectors'], 99) def test_change_series_activates_group(self): self.group.status = GroupStatus.INACTIVE.value self.group.save() url = '/api/pickup-date-series/{}/'.format(self.series.id) self.client.force_login(user=self.member) self.client.patch(url, {'max_collectors': 99}) self.group.refresh_from_db() self.assertEqual(self.group.status, GroupStatus.ACTIVE.value) def test_change_start_time(self): self.client.force_login(user=self.member) # get original times url = '/api/pickup-dates/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) original_dates = [parse(_['date']) for _ in response.data] # change times url = '/api/pickup-date-series/{}/'.format(self.series.id) new_startdate = shift_date_in_local_time( self.series.start_date, relativedelta(hours=2, minutes=20), self.group.timezone ) response = self.client.patch(url, {'start_date': new_startdate.isoformat()}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(parse(response.data['start_date']), new_startdate) # compare resulting pickups url = '/api/pickup-dates/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) for response_pickup, old_date in zip(response.data, original_dates): self.assertEqual( parse(response_pickup['date']), shift_date_in_local_time(old_date, relativedelta(hours=2, minutes=20), self.group.timezone) ) def test_change_start_date_to_future(self): self.client.force_login(user=self.member) # get original dates url = '/api/pickup-dates/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) original_dates = [parse(_['date']) for _ in response.data] # change dates url = '/api/pickup-date-series/{}/'.format(self.series.id) new_startdate = shift_date_in_local_time(self.series.start_date, relativedelta(days=5), self.group.timezone) response = self.client.patch(url, {'start_date': new_startdate.isoformat()}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(parse(response.data['start_date']), new_startdate) # compare resulting pickups url = '/api/pickup-dates/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) for response_pickup, old_date in zip_longest(response.data, original_dates): self.assertEqual( parse(response_pickup['date']), shift_date_in_local_time(old_date, relativedelta(days=5), self.group.timezone) ) def test_change_start_date_to_past(self): self.client.force_login(user=self.member) # get original dates url = '/api/pickup-dates/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) original_dates = [parse(_['date']) for _ in response.data] # change dates url = '/api/pickup-date-series/{}/'.format(self.series.id) new_startdate = shift_date_in_local_time(self.series.start_date, relativedelta(days=-5), self.group.timezone) response = self.client.patch(url, {'start_date': new_startdate.isoformat()}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(parse(response.data['start_date']), new_startdate) # compare resulting pickups url = '/api/pickup-dates/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) # shifting 5 days to the past is similar to shifting 2 days to the future for response_pickup, old_date in zip_longest(response.data, original_dates): new_date = shift_date_in_local_time(old_date, relativedelta(days=2), self.group.timezone) if new_date > self.now + relativedelta(weeks=self.store.weeks_in_advance): # date too far in future self.assertIsNone(response_pickup) else: self.assertEqual(parse(response_pickup['date']), new_date) def test_set_end_date(self): self.client.force_login(user=self.member) # change rule url = '/api/pickup-date-series/{}/'.format(self.series.id) rule = rrulestr(self.series.rule, dtstart=self.now) \ .replace(until=self.now + relativedelta(days=8)) response = self.client.patch(url, {'rule': str(rule)}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['rule'], str(rule)) # compare resulting pickups url = '/api/pickup-dates/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(len(response.data), 2, response.data) def test_set_end_date_with_users_have_joined_pickup(self): self.client.force_login(user=self.member) self.series.pickup_dates.last().add_collector(self.member) # change rule url = '/api/pickup-date-series/{}/'.format(self.series.id) rule = rrulestr(self.series.rule, dtstart=self.now) \ .replace(until=self.now) response = self.client.patch(url, { 'rule': str(rule), }) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['rule'], str(rule)) # compare resulting pickups url = '/api/pickup-dates/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(len(response.data), 1, response.data) def test_disable_pickup_series(self): "the series should get removed, empty upcoming pickups disabled, non-empty pickups kept" self.client.force_login(user=self.member) joined_pickup = self.series.pickup_dates.last() joined_pickup.add_collector(self.member) url = '/api/pickup-date-series/{}/'.format(self.series.id) response = self.client.delete(url) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT, response.data) url = '/api/pickup-dates/' response = self.get_results(url, {'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) empty_pickups = [p for p in response.data if len(p['collector_ids']) == 0] self.assertEqual(empty_pickups, []) url = '/api/pickup-dates/{}/'.format(joined_pickup.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['collector_ids'], [self.member.id]) self.assertFalse(response.data['is_disabled']) def test_change_max_collectors_to_invalid_number_fails(self): self.client.force_login(user=self.member) url = '/api/pickup-date-series/{}/'.format(self.series.id) response = self.client.patch(url, {'max_collectors': -1}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.data) def test_set_invalid_store_fails(self): original_store = self.series.store unrelated_store = StoreFactory() self.client.force_login(user=self.member) url = '/api/pickup-date-series/{}/'.format(self.series.id) response = self.client.patch(url, {'store': unrelated_store.id}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['store'], original_store.id) self.series.refresh_from_db() self.assertEqual(self.series.store.id, original_store.id) def test_set_multiple_rules_fails(self): self.client.force_login(user=self.member) url = '/api/pickup-date-series/{}/'.format(self.series.id) response = self.client.patch(url, {'rule': 'RRULE:FREQ=WEEKLY;BYDAY=MO\nRRULE:FREQ=MONTHLY'}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.data) self.assertEqual(response.data, {'rule': ['Only single recurrence rules are allowed.']}) def test_keep_changes_to_max_collectors(self): self.client.force_login(user=self.member) pickup_under_test = self.series.pickup_dates.first() url = '/api/pickup-dates/{}/'.format(pickup_under_test.id) # change setting of pickup response = self.client.patch(url, {'max_collectors': 666}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['max_collectors'], 666) # run regular update command of series self.series.update_pickups() # check if changes persist url = '/api/pickup-dates/{}/'.format(pickup_under_test.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['max_collectors'], 666) # modify series max_collectors series_url = '/api/pickup-date-series/{}/'.format(self.series.id) response = self.client.patch(series_url, {'max_collectors': 20}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) # check if changes persist url = '/api/pickup-dates/{}/'.format(pickup_under_test.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['max_collectors'], 666) def test_keep_changes_to_description(self): self.client.force_login(user=self.member) pickup_under_test = self.series.pickup_dates.first() url = '/api/pickup-dates/{}/'.format(pickup_under_test.id) # change setting of pickup response = self.client.patch(url, {'description': 'asdf'}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['description'], 'asdf') # run regular update command of series self.series.update_pickups() # check if changes persist url = '/api/pickup-dates/{}/'.format(pickup_under_test.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['description'], 'asdf') # modify series description series_url = '/api/pickup-date-series/{}/'.format(self.series.id) response = self.client.patch(series_url, {'description': 'new series description'}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) # check if changes persist url = '/api/pickup-dates/{}/'.format(pickup_under_test.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['description'], 'asdf') def test_invalid_rule_fails(self): url = '/api/pickup-date-series/{}/'.format(self.series.id) self.client.force_login(user=self.member) response = self.client.patch(url, {'rule': 'FREQ=WEEKLY;BYDAY='}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.data) def test_keeps_joined_pickups(self): # join pickups [p.add_collector(self.member) for p in self.series.pickup_dates.all()] # change series rule to add another day recurrence = rrule.rrule( freq=rrule.WEEKLY, byweekday=[ self.now.weekday(), (self.now + relativedelta(days=1)).weekday(), ], ) series_url = '/api/pickup-date-series/{}/'.format(self.series.id) self.client.force_login(user=self.member) response = self.client.patch(series_url, { 'rule': str(recurrence), }) self.assertEqual(response.status_code, status.HTTP_200_OK) self.series.refresh_from_db() response = self.client.get('/api/pickup-dates/?series={}'.format(self.series.id)) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual([parse(p['date']) for p in response.data['results']], [ shift_date_in_local_time(self.series.start_date, delta, self.group.timezone) for delta in ( relativedelta(days=0), relativedelta(days=1), relativedelta(days=7), relativedelta(days=8), relativedelta(days=14), relativedelta(days=15), relativedelta(days=21), relativedelta(days=22), ) ]) self.assertEqual( [p['collector_ids'] for p in response.data['results']], list(interleave( [[self.member.id] for _ in range(4)], [[] for _ in range(4)], )), ) def test_removes_empty_leftover_pickups_when_reducing_weeks_in_advance(self): # join one pickup joined_pickup = self.series.pickup_dates.first() joined_pickup.add_collector(self.member) # change weeks_in_advance store_url = '/api/stores/{}/'.format(self.store.id) self.client.force_login(user=self.member) response = self.client.patch(store_url, { 'weeks_in_advance': 1, }) self.assertEqual(response.status_code, status.HTTP_200_OK) response = self.get_results('/api/pickup-dates/?series={}'.format(self.series.id)) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(response.data), 1) self.assertEqual(response.data[0]['id'], joined_pickup.id) self.assertEqual(response.data[0]['collector_ids'], [self.member.id]) def test_cannot_move_pickups_in_a_series(self): self.client.force_login(user=self.member) pickup = self.series.pickup_dates.last() response = self.client.patch( '/api/pickup-dates/{}/'.format(pickup.id), {'date': pickup.date + relativedelta(weeks=7)} ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn('You can\'t move pickups', response.data['date'][0])