Skip to content

Commit

Permalink
fixed bugs in fix_timeline after hiding
Browse files Browse the repository at this point in the history
  • Loading branch information
ramusus committed Jul 18, 2014
1 parent 49c5c29 commit 9d1ac9c
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 22 deletions.
2 changes: 1 addition & 1 deletion vkontakte_groups_migration/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
VERSION = (0, 6, 3)
VERSION = (0, 6, 4)
__version__ = '.'.join(map(str, VERSION))
45 changes: 24 additions & 21 deletions vkontakte_groups_migration/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,28 +229,31 @@ def fix_memberships(self):
return

if self.next:
# delete memberships stopped in current and started from the next migration, we need to join them
GroupMembership.objects.filter(group=self.group, user_id__in=self.members_left_ids,
time_left=None, time_entered=self.next.time).delete()

# move left users to the time of the next migration
GroupMembership.objects.filter(group=self.group, user_id__in=self.members_left_ids, time_left=self.time) \
.exclude(user_id__in=self.next.members_ids) \
# всем кто вышел сейчас и есть в следующей - проставляем нужную дату выхода
# дату выхода берем из последнего лоскута и удаляем его
for prev_slice in GroupMembership.objects.filter(group=self.group, time_left=self.time).filter(user_id__in=self.next.members_ids):
next_slice = GroupMembership.objects.get(group=self.group, time_entered=self.next.time, user_id=prev_slice.user_id)
prev_slice.time_left = next_slice.time_left
next_slice.delete()
prev_slice.save()

# все кто вышел сейчас и нет в следующей - вышли в следующей
GroupMembership.objects.filter(group=self.group, time_left=self.time).exclude(user_id__in=self.next.members_ids) \
.update(time_left=self.next.time)

# these users not entered actually -> delete them
GroupMembership.objects.filter(group=self.group, user_id__in=self.members_entered_ids, time_entered=self.time) \
.exclude(user_id__in=self.next.members_ids).delete()
# все кто вошел сейчас и нет в следующей - не вошли, удаляем
GroupMembership.objects.filter(group=self.group, time_entered=self.time).exclude(user_id__in=self.next.members_ids) \
.delete()

# все кто вошел сейчас и есть в следующей - вошли в следующей
GroupMembership.objects.filter(group=self.group, time_entered=self.time).filter(user_id__in=self.next.members_ids) \
.update(time_entered=self.next.time)

# update entered_time of all entered users to the time of next migration
GroupMembership.objects.filter(group=self.group, user_id__in=self.members_entered_ids, time_entered=self.time) \
.filter(user_id__in=self.next.members_ids).update(time_entered=self.next.time)
else:
# if no next migration -> delete all current entered users
GroupMembership.objects.filter(group=self.group, user_id__in=self.members_entered_ids, time_entered=self.time).delete()

# update rest of left users -> they are not left
GroupMembership.objects.filter(group=self.group, user_id__in=self.members_left_ids, time_left=self.time).update(time_left=None)
GroupMembership.objects.filter(group=self.group, time_entered=self.time).delete()
GroupMembership.objects.filter(group=self.group, time_left=self.time).update(time_left=None)

def check_memberships_count(self):
'''
Expand Down Expand Up @@ -542,11 +545,11 @@ def save(self, *args, **kwargs):

# check additionally null values of time_entered and time_left,
# because for postgres null values are acceptable in unique constraint
qs = self.__class__.objects.filter(group=self.group, user_id=self.user_id)
if not self.time_entered and qs.filter(time_entered=None).count() != 0:
raise IntegrityError("columns group_id=%s, user_id=%s, time_entered=None are not unique" % (self.group_id, self.user_id))
if not self.time_left and qs.filter(time_left=None).count() != 0:
raise IntegrityError("columns group_id=%s, user_id=%s, time_left=None are not unique" % (self.group_id, self.user_id))
# qs = self.__class__.objects.filter(group=self.group, user_id=self.user_id)
# if not self.time_entered and qs.filter(time_entered=None).count() != 0:
# raise IntegrityError("columns group_id=%s, user_id=%s, time_entered=None are not unique" % (self.group_id, self.user_id))
# if not self.time_left and qs.filter(time_left=None).count() != 0:
# raise IntegrityError("columns group_id=%s, user_id=%s, time_left=None are not unique" % (self.group_id, self.user_id))

return super(GroupMembership, self).save(*args, **kwargs)

Expand Down
56 changes: 56 additions & 0 deletions vkontakte_groups_migration/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from vkontakte_groups.factories import GroupFactory
from factories import GroupMigrationFactory, GroupMembershipFactory, GroupMembership
from datetime import datetime, timedelta
import random

GROUP_ID = 30221121

Expand Down Expand Up @@ -272,6 +273,61 @@ def test_m2m_relations(self):
update_group_users(migration.group)
self.assertListEqual(list(migration.group.users.values_list('remote_id', flat=True)), range(10, 20))


def test_deleting_bad_migration(self):

user_ids = range(1,1000)

for i in user_ids:
UserFactory(remote_id=i)

def get_random_members():
return random.sample(user_ids, random.randint(800, 850))

group1 = GroupFactory()
group2 = GroupFactory()

# normal situation
stat11 = GroupMigrationFactory(group=group1, time=datetime.now()-timedelta(10), members_ids=get_random_members())
stat11.save_final()
stat13 = GroupMigrationFactory(group=group1, time=datetime.now()-timedelta(8), members_ids=get_random_members())
stat13.save_final()
stat14 = GroupMigrationFactory(group=group1, time=datetime.now()-timedelta(7), members_ids=get_random_members())
stat14.save_final()
stat15 = GroupMigrationFactory(group=group1, time=datetime.now()-timedelta(6), members_ids=get_random_members())
stat15.save_final()

# situation with bad migration in the middle
stat21 = GroupMigrationFactory(group=group2, time=datetime.now()-timedelta(10), members_ids=stat11.members_ids)
stat21.save_final()
stat22 = GroupMigrationFactory(group=group2, time=datetime.now()-timedelta(9), members_ids=random.sample(user_ids, 200))
stat22.save_final()
stat23 = GroupMigrationFactory(group=group2, time=datetime.now()-timedelta(8), members_ids=stat13.members_ids)
stat23.save_final()
stat24 = GroupMigrationFactory(group=group2, time=datetime.now()-timedelta(7), members_ids=stat14.members_ids)
stat24.save_final()
stat25 = GroupMigrationFactory(group=group2, time=datetime.now()-timedelta(6), members_ids=stat15.members_ids)
stat25.save_final()

# hide bad migration
stat22.hide()

# no any stat22.time among memberships
self.assertEqual(group2.memberships.filter(time_entered=stat22.time).count(), 0)
self.assertEqual(group2.memberships.filter(time_left=stat22.time).count(), 0)

# check stat23.time
self.assertItemsEqual(group2.memberships.filter(time_entered=stat23.time).values_list('user_id', flat=True), set(stat23.members_ids).difference(set(stat21.members_ids)))
self.assertItemsEqual(group2.memberships.filter(time_left=stat23.time).values_list('user_id', flat=True), set(stat21.members_ids).difference(set(stat23.members_ids)))

# compare normal and bad memberships
self.assertItemsEqual(GroupMembership.objects.get_user_ids(group1), GroupMembership.objects.get_user_ids(group2))

for stat1, stat2 in [(stat11, stat21), (stat13, stat23), (stat14, stat24), (stat15, stat25)]:
self.assertItemsEqual(stat1.user_ids, stat2.user_ids)
self.assertItemsEqual(stat1.entered_user_ids, stat2.entered_user_ids)
self.assertItemsEqual(stat1.left_user_ids, stat2.left_user_ids)

def test_deleting_hiding_migration(self):

for i in range(1,7):
Expand Down

0 comments on commit 9d1ac9c

Please sign in to comment.