2018-11-16 13:16:36 +03:00
|
|
|
import datetime
|
2018-11-20 15:24:15 +03:00
|
|
|
import signal
|
2018-11-16 13:16:36 +03:00
|
|
|
|
2018-11-20 15:24:15 +03:00
|
|
|
import os
|
|
|
|
from multiprocessing import Process
|
|
|
|
from time import sleep
|
|
|
|
from unittest import skip, expectedFailure
|
2018-11-16 13:16:36 +03:00
|
|
|
|
2018-11-20 15:24:15 +03:00
|
|
|
import random
|
|
|
|
from django.db import connections as django_connections
|
|
|
|
from django.db.models import F
|
|
|
|
from django.test import TransactionTestCase, override_settings
|
|
|
|
|
|
|
|
from django_clickhouse import config
|
2018-11-16 13:16:36 +03:00
|
|
|
from django_clickhouse.database import connections
|
|
|
|
from django_clickhouse.migrations import migrate_app
|
|
|
|
from tests.clickhouse_models import ClickHouseTestModel, ClickHouseCollapseTestModel
|
|
|
|
from tests.models import TestModel
|
|
|
|
|
|
|
|
|
|
|
|
class SyncTest(TransactionTestCase):
|
|
|
|
def setUp(self):
|
|
|
|
self.db = connections['default']
|
|
|
|
self.db.drop_database()
|
|
|
|
self.db.db_exists = False
|
|
|
|
self.db.create_database()
|
|
|
|
migrate_app('tests', 'default')
|
2018-11-20 15:24:15 +03:00
|
|
|
ClickHouseTestModel.get_storage().flush()
|
2018-11-16 13:16:36 +03:00
|
|
|
|
|
|
|
def test_simple(self):
|
|
|
|
obj = TestModel.objects.create(value=1, created_date=datetime.date.today())
|
|
|
|
ClickHouseTestModel.sync_batch_from_storage()
|
|
|
|
|
|
|
|
synced_data = list(ClickHouseTestModel.objects_in(connections['default']))
|
|
|
|
self.assertEqual(1, len(synced_data))
|
|
|
|
self.assertEqual(obj.created_date, synced_data[0].created_date)
|
|
|
|
self.assertEqual(obj.value, synced_data[0].value)
|
|
|
|
self.assertEqual(obj.id, synced_data[0].id)
|
|
|
|
|
|
|
|
def test_collapsing_update(self):
|
|
|
|
obj = TestModel.objects.create(value=1, created_date=datetime.date.today())
|
|
|
|
obj.value = 2
|
|
|
|
obj.save()
|
|
|
|
ClickHouseCollapseTestModel.sync_batch_from_storage()
|
|
|
|
|
2018-11-20 15:24:15 +03:00
|
|
|
# sync_batch_from_storage uses FINAL, so data would be collapsed by now
|
2018-11-16 13:16:36 +03:00
|
|
|
synced_data = list(ClickHouseCollapseTestModel.objects_in(connections['default']))
|
|
|
|
self.assertEqual(1, len(synced_data))
|
|
|
|
self.assertEqual(obj.created_date, synced_data[0].created_date)
|
|
|
|
self.assertEqual(obj.value, synced_data[0].value)
|
|
|
|
self.assertEqual(obj.id, synced_data[0].id)
|
|
|
|
|
|
|
|
obj.value = 3
|
|
|
|
obj.save()
|
|
|
|
ClickHouseCollapseTestModel.sync_batch_from_storage()
|
|
|
|
|
|
|
|
synced_data = list(self.db.select('SELECT * FROM $table FINAL', model_class=ClickHouseCollapseTestModel))
|
2018-11-16 15:41:54 +03:00
|
|
|
self.assertGreaterEqual(1, len(synced_data))
|
2018-11-16 13:16:36 +03:00
|
|
|
self.assertEqual(obj.created_date, synced_data[0].created_date)
|
|
|
|
self.assertEqual(obj.value, synced_data[0].value)
|
|
|
|
self.assertEqual(obj.id, synced_data[0].id)
|
2018-11-20 15:24:15 +03:00
|
|
|
|
|
|
|
@expectedFailure
|
|
|
|
def test_collapsing_delete(self):
|
|
|
|
obj = TestModel.objects.create(value=1, created_date=datetime.date.today())
|
|
|
|
ClickHouseCollapseTestModel.sync_batch_from_storage()
|
|
|
|
obj.delete()
|
|
|
|
ClickHouseCollapseTestModel.sync_batch_from_storage()
|
|
|
|
|
|
|
|
# sync_batch_from_storage uses FINAL, so data would be collapsed by now
|
|
|
|
synced_data = list(ClickHouseCollapseTestModel.objects_in(connections['default']))
|
|
|
|
self.assertEqual(0, len(synced_data))
|
|
|
|
|
|
|
|
|
|
|
|
@skip("This doesn't work due to different threads connection problems")
|
|
|
|
class KillTest(TransactionTestCase):
|
|
|
|
TEST_TIME = 30
|
|
|
|
start = datetime.datetime.now()
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
ClickHouseTestModel.get_storage().flush()
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _create_process(count=1000, test_time=60, period=1):
|
|
|
|
for iteration in range(test_time):
|
|
|
|
TestModel.objects.using('create').bulk_create([
|
|
|
|
TestModel(created_date='2018-01-01', value=iteration * count + i) for i in range(count)])
|
|
|
|
django_connections['create'].close()
|
|
|
|
sleep(period)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _update_process(count=1000, test_time=60, period=1):
|
|
|
|
for iteration in range(test_time):
|
|
|
|
TestModel.objects.using('update').filter(id__gte=iteration * count).annotate(idmod10=F('id') % 10). \
|
|
|
|
filter(idmod10=0).update(value=-1)
|
|
|
|
django_connections['update'].close()
|
|
|
|
sleep(period)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _delete_process(count=1000, test_time=60, period=1):
|
|
|
|
for iteration in range(test_time):
|
|
|
|
TestModel.objects.using('delete').filter(id__gte=iteration * count).annotate(idmod10=F('id') % 10). \
|
|
|
|
filter(idmod10=1).delete()
|
|
|
|
django_connections['delete'].close()
|
|
|
|
sleep(period)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def _sync_process(cls, period=1):
|
|
|
|
while (datetime.datetime.now() - cls.start).total_seconds() < cls.TEST_TIME:
|
|
|
|
ClickHouseCollapseTestModel.sync_batch_from_storage()
|
|
|
|
sleep(period)
|
|
|
|
|
|
|
|
def _kill_process(self, p):
|
|
|
|
# https://stackoverflow.com/questions/47553120/kill-a-multiprocessing-pool-with-sigkill-instead-of-sigterm-i-think
|
|
|
|
os.kill(p.pid, signal.SIGKILL)
|
|
|
|
p.terminate()
|
|
|
|
|
|
|
|
def _check_data(self):
|
|
|
|
ClickHouseCollapseTestModel.sync_batch_from_storage()
|
|
|
|
|
|
|
|
ch_data = list(connections['default'].select('SELECT * FROM $table FINAL ORDER BY id',
|
|
|
|
model_class=ClickHouseCollapseTestModel))
|
|
|
|
pg_data = list(TestModel.objects.all().order_by('id'))
|
|
|
|
|
|
|
|
self.assertEqual(len(pg_data), len(ch_data))
|
|
|
|
serizlier = ClickHouseCollapseTestModel.get_django_model_serializer()
|
|
|
|
self.assertListEqual(ch_data, [serizlier.serialize(item) for item in pg_data])
|
|
|
|
|
|
|
|
def test_kills(self):
|
|
|
|
p_create = Process(target=self._create_process, kwargs={'test_time': 5})
|
|
|
|
p_update = Process(target=self._update_process, kwargs={'test_time': 5})
|
|
|
|
p_delete = Process(target=self._delete_process, kwargs={'test_time': 5})
|
|
|
|
p_sync = Process(target=self._sync_process)
|
|
|
|
|
|
|
|
self.start = datetime.datetime.now()
|
|
|
|
p_create.start()
|
|
|
|
p_update.start()
|
|
|
|
p_delete.start()
|
|
|
|
p_sync.start()
|
|
|
|
|
|
|
|
# while (datetime.datetime.now() - start).total_seconds() < self.TEST_TIME:
|
|
|
|
# self._kill_process(p_sync)
|
|
|
|
# p_sync.start()
|
|
|
|
# sleep(random.randint(0, 5))
|
|
|
|
|
|
|
|
p_create.join()
|
|
|
|
p_update.join()
|
|
|
|
p_delete.join()
|
|
|
|
p_sync.join()
|
|
|
|
|
|
|
|
# self._check_data()
|