diff options
Diffstat (limited to 'tests/units/document/document.py')
-rwxr-xr-x | tests/units/document/document.py | 1008 |
1 files changed, 1008 insertions, 0 deletions
diff --git a/tests/units/document/document.py b/tests/units/document/document.py new file mode 100755 index 0000000..cd480eb --- /dev/null +++ b/tests/units/document/document.py @@ -0,0 +1,1008 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# sugar-lint: disable + +import os +import sys +import stat +import time +import urllib2 +import hashlib +import cPickle as pickle +from base64 import b64encode +from cStringIO import StringIO +from os.path import join, exists + +import gobject + +from __init__ import tests + +import active_document as ad +from active_document import document, storage, env, index +from active_document import directory as directory_ +from active_document.directory import Directory +from active_document.metadata import active_property, Metadata +from active_document.metadata import StoredProperty, BlobProperty +from active_document.index import IndexWriter + + +class DocumentTest(tests.Test): + + def test_ActiveProperty_Slotted(self): + + class Document(document.Document): + + @active_property(slot=1) + def slotted(self, value): + return value + + @active_property(StoredProperty) + def not_slotted(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + self.assertEqual(1, directory.metadata['slotted'].slot) + + directory.create({'slotted': 'slotted', 'not_slotted': 'not_slotted'}) + + docs, total = directory.find(0, 100, order_by='slotted') + self.assertEqual(1, total) + self.assertEqual( + [('slotted', 'not_slotted')], + [(i.slotted, i.not_slotted) for i in docs]) + + self.assertRaises(RuntimeError, directory.find, 0, 100, order_by='not_slotted') + + def test_ActiveProperty_SlottedIUnique(self): + + class Document(document.Document): + + @active_property(slot=1) + def prop_1(self, value): + return value + + @active_property(slot=1) + def prop_2(self, value): + return value + + self.assertRaises(RuntimeError, Directory, tests.tmpdir, Document, IndexWriter) + + def test_ActiveProperty_Terms(self): + + class Document(document.Document): + + @active_property(prefix='T') + def term(self, value): + return value + + @active_property(StoredProperty) + def not_term(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + self.assertEqual('T', directory.metadata['term'].prefix) + + guid = directory.create({'term': 'term', 'not_term': 'not_term'}) + + docs, total = directory.find(0, 100, term='term') + self.assertEqual(1, total) + self.assertEqual( + [('term', 'not_term')], + [(i.term, i.not_term) for i in docs]) + + self.assertEqual(0, directory.find(0, 100, query='not_term:not_term')[-1]) + self.assertEqual(1, directory.find(0, 100, query='not_term:=not_term')[-1]) + + def test_ActiveProperty_TermsUnique(self): + + class Document(document.Document): + + @active_property(prefix='P') + def prop_1(self, value): + return value + + @active_property(prefix='P') + def prop_2(self, value): + return value + + self.assertRaises(RuntimeError, Directory, tests.tmpdir, Document, IndexWriter) + + def test_ActiveProperty_FullTextSearch(self): + + class Document(document.Document): + + @active_property(full_text=False, slot=1) + def no(self, value): + return value + + @active_property(full_text=True, slot=2) + def yes(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + self.assertEqual(False, directory.metadata['no'].full_text) + self.assertEqual(True, directory.metadata['yes'].full_text) + + guid = directory.create({'no': 'foo', 'yes': 'bar'}) + + self.assertEqual(0, directory.find(0, 100, query='foo')[-1]) + self.assertEqual(1, directory.find(0, 100, query='bar')[-1]) + + def test_StoredProperty_Defaults(self): + + class Document(document.Document): + + @active_property(StoredProperty, default='default') + def w_default(self, value): + return value + + @active_property(StoredProperty) + def wo_default(self, value): + return value + + @active_property(slot=1, default='not_stored_default') + def not_stored_default(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + self.assertEqual('default', directory.metadata['w_default'].default) + self.assertEqual(None, directory.metadata['wo_default'].default) + self.assertEqual('not_stored_default', directory.metadata['not_stored_default'].default) + + guid = directory.create({'wo_default': 'wo_default'}) + + docs, total = directory.find(0, 100) + self.assertEqual(1, total) + self.assertEqual( + [('default', 'wo_default', 'not_stored_default')], + [(i.w_default, i.wo_default, i.not_stored_default) for i in docs]) + + self.assertRaises(RuntimeError, directory.create, {}) + + def test_properties_Blob(self): + + class Document(document.Document): + + @active_property(BlobProperty, mime_type='application/json') + def blob(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + + guid = directory.create({}) + blob_path = join(tests.tmpdir, guid[:2], guid, 'blob') + + self.assertEqual(ad.PropertyMeta(), directory.get(guid).blob) + + data = 'payload' + directory.set_blob(guid, 'blob', StringIO(data)) + self.assertEqual({ + 'seqno': 2, + 'mtime': os.stat(blob_path).st_mtime, + 'digest': hashlib.sha1(data).hexdigest(), + 'path': join(tests.tmpdir, guid[:2], guid, 'blob.blob'), + 'mime_type': 'application/json', + }, + directory.get(guid).meta('blob')) + self.assertEqual(data, file(blob_path + '.blob').read()) + + def test_create_FailOnExisted(self): + + class Document(document.Document): + pass + + directory = Directory(tests.tmpdir, Document, IndexWriter) + guid = directory.create(guid='guid') + assert guid == 'guid' + self.assertRaises(RuntimeError, directory.create, guid='guid') + + def test_update(self): + + class Document(document.Document): + + @active_property(slot=1) + def prop_1(self, value): + return value + + @active_property(StoredProperty) + def prop_2(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + + guid = directory.create({'prop_1': '1', 'prop_2': '2'}) + self.assertEqual( + [('1', '2')], + [(i.prop_1, i.prop_2) for i in directory.find(0, 1024)[0]]) + + directory.update(guid, {'prop_1': '3', 'prop_2': '4'}) + self.assertEqual( + [('3', '4')], + [(i.prop_1, i.prop_2) for i in directory.find(0, 1024)[0]]) + + def test_delete(self): + + class Document(document.Document): + + @active_property(prefix='P') + def prop(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + + guid_1 = directory.create({'prop': '1'}) + guid_2 = directory.create({'prop': '2'}) + guid_3 = directory.create({'prop': '3'}) + + self.assertEqual( + ['1', '2', '3'], + [i.prop for i in directory.find(0, 1024)[0]]) + + directory.delete(guid_2) + self.assertEqual( + ['1', '3'], + [i.prop for i in directory.find(0, 1024)[0]]) + + directory.delete(guid_3) + self.assertEqual( + ['1'], + [i.prop for i in directory.find(0, 1024)[0]]) + + directory.delete(guid_1) + self.assertEqual( + [], + [i.prop for i in directory.find(0, 1024)[0]]) + + def test_populate(self): + + class Document(document.Document): + + @active_property(slot=1) + def prop(self, value): + return value + + self.touch( + ('1/1/guid', '{"value": "1"}'), + ('1/1/ctime', '{"value": 1}'), + ('1/1/mtime', '{"value": 1}'), + ('1/1/prop', '{"value": "prop-1"}'), + ('1/1/seqno', '{"value": 0}'), + + ('2/2/guid', '{"value": "2"}'), + ('2/2/ctime', '{"value": 2}'), + ('2/2/mtime', '{"value": 2}'), + ('2/2/prop', '{"value": "prop-2"}'), + ('2/2/seqno', '{"value": 0}'), + ) + + directory = Directory(tests.tmpdir, Document, IndexWriter) + + self.assertEqual(0, directory._index.mtime) + for i in directory.populate(): + pass + self.assertNotEqual(0, directory._index.mtime) + + doc = directory.get('1') + self.assertEqual(1, doc['ctime']) + self.assertEqual(1, doc['mtime']) + self.assertEqual('prop-1', doc['prop']) + + doc = directory.get('2') + self.assertEqual(2, doc['ctime']) + self.assertEqual(2, doc['mtime']) + self.assertEqual('prop-2', doc['prop']) + + self.assertEqual( + [ + (1, 1, 'prop-1'), + (2, 2, 'prop-2'), + ], + [(i.ctime, i.mtime, i.prop) for i in directory.find(0, 10)[0]]) + + def test_populate_IgnoreBadDocuments(self): + + class Document(document.Document): + + @active_property(slot=1) + def prop(self, value): + return value + + self.touch( + ('1/1/guid', '{"value": "1"}'), + ('1/1/ctime', '{"value": 1}'), + ('1/1/mtime', '{"value": 1}'), + ('1/1/prop', '{"value": "prop-1"}'), + ('1/1/seqno', '{"value": 0}'), + + ('2/2/guid', '{"value": "2"}'), + ('2/2/ctime', ''), + ('2/2/mtime', '{"value": 2}'), + ('2/2/prop', '{"value": "prop-2"}'), + ('2/2/seqno', '{"value": 0}'), + + ('3/3/guid', ''), + ('3/3/ctime', ''), + ('3/3/mtime', ''), + ('3/3/prop', ''), + ('3/3/seqno', ''), + ) + + directory = Directory(tests.tmpdir, Document, IndexWriter) + + populated = 0 + for i in directory.populate(): + populated += 1 + self.assertEqual(2, populated) + self.assertEqual( + sorted(['1', '2']), + sorted([i.guid for i in directory.find(0, 10)[0]])) + assert exists('1/1/guid') + assert exists('2/2/guid') + assert not exists('3/3/guid') + + def test_create_with_guid(self): + + class Document(document.Document): + + @active_property(slot=1) + def prop(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + + guid = directory.create(guid='guid', prop='foo') + self.assertEqual( + [('guid', 'foo')], + [(i.guid, i.prop) for i in directory.find(0, 1024)[0]]) + + directory.update(guid, {'prop': 'probe'}) + self.assertEqual( + [('guid', 'probe')], + [(i.guid, i.prop) for i in directory.find(0, 1024)[0]]) + + def test_seqno(self): + + class Document(document.Document): + + @active_property(slot=1, default='') + def prop(self, value): + return value + + @active_property(BlobProperty) + def blob(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + + guid_1 = directory.create({}) + seqno = directory.get(guid_1).get('seqno') + self.assertEqual(1, seqno) + self.assertEqual( + pickle.load(file('%s/%s/guid' % (guid_1[:2], guid_1)))['seqno'], + seqno) + self.assertEqual( + pickle.load(file('%s/%s/prop' % (guid_1[:2], guid_1)))['seqno'], + seqno) + + guid_2 = directory.create({}) + seqno = directory.get(guid_2).get('seqno') + self.assertEqual(2, seqno) + self.assertEqual( + pickle.load(file('%s/%s/guid' % (guid_2[:2], guid_2)))['seqno'], + seqno) + self.assertEqual( + pickle.load(file('%s/%s/prop' % (guid_2[:2], guid_2)))['seqno'], + seqno) + + directory.set_blob(guid_1, 'blob', StringIO('blob')) + seqno = directory.get(guid_1).get('seqno') + self.assertEqual(3, seqno) + self.assertEqual( + pickle.load(file('%s/%s/guid' % (guid_1[:2], guid_1)))['seqno'], + 1) + self.assertEqual( + pickle.load(file('%s/%s/prop' % (guid_1[:2], guid_1)))['seqno'], + 1) + self.assertEqual( + pickle.load(file('%s/%s/blob' % (guid_1[:2], guid_1)))['seqno'], + seqno) + + directory.update(guid_1, {'prop': 'new'}) + seqno = directory.get(guid_1).get('seqno') + self.assertEqual(4, seqno) + self.assertEqual( + pickle.load(file('%s/%s/guid' % (guid_1[:2], guid_1)))['seqno'], + 1) + self.assertEqual( + pickle.load(file('%s/%s/prop' % (guid_1[:2], guid_1)))['seqno'], + seqno) + self.assertEqual( + pickle.load(file('%s/%s/blob' % (guid_1[:2], guid_1)))['seqno'], + 3) + + def test_diff(self): + + class Document(document.Document): + + @active_property(slot=1) + def prop(self, value): + return value + + @active_property(BlobProperty) + def blob(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + + directory.create(guid='1', prop='1', ctime=1, mtime=1) + directory.set_blob('1', 'blob', StringIO('1')) + for i in os.listdir('1/1'): + os.utime('1/1/%s' % i, (1, 1)) + + directory.create(guid='2', prop='2', ctime=2, mtime=2) + directory.set_blob('2', 'blob', StringIO('2')) + for i in os.listdir('2/2'): + os.utime('2/2/%s' % i, (2, 2)) + + directory.create(guid='3', prop='3', ctime=3, mtime=3) + for i in os.listdir('3/3'): + os.utime('3/3/%s' % i, (3, 3)) + + out_seq = env.Sequence() + self.assertEqual([ + ('1', { + 'guid': {'value': '1', 'mtime': 1}, + 'ctime': {'value': 1, 'mtime': 1}, + 'prop': {'value': '1', 'mtime': 1}, + 'mtime': {'value': 1, 'mtime': 1}, + 'blob': {'mtime': 1, 'digest': hashlib.sha1('1').hexdigest(), 'mime_type': 'application/octet-stream', 'path': tests.tmpdir + '/1/1/blob.blob'}, + }), + ('2', { + 'guid': {'value': '2', 'mtime': 2}, + 'ctime': {'value': 2, 'mtime': 2}, + 'prop': {'value': '2', 'mtime': 2}, + 'mtime': {'value': 2, 'mtime': 2}, + 'blob': {'mtime': 2, 'digest': hashlib.sha1('2').hexdigest(), 'mime_type': 'application/octet-stream', 'path': tests.tmpdir + '/2/2/blob.blob'}, + }), + ('3', { + 'guid': {'value': '3', 'mtime': 3}, + 'ctime': {'value': 3, 'mtime': 3}, + 'prop': {'value': '3', 'mtime': 3}, + 'mtime': {'value': 3, 'mtime': 3}, + }), + ], + [i for i in directory.diff(env.Sequence([[0, None]]), out_seq)]) + self.assertEqual([[1, 5]], out_seq) + + out_seq = env.Sequence() + self.assertEqual([ + ('2', { + 'guid': {'value': '2', 'mtime': 2}, + 'ctime': {'value': 2, 'mtime': 2}, + 'prop': {'value': '2', 'mtime': 2}, + 'mtime': {'value': 2, 'mtime': 2}, + 'blob': {'mtime': 2, 'digest': hashlib.sha1('2').hexdigest(), 'mime_type': 'application/octet-stream', 'path': tests.tmpdir + '/2/2/blob.blob'}, + }), + ], + [i for i in directory.diff(env.Sequence([[3, 4]]), out_seq)]) + self.assertEqual([[3, 4]], out_seq) + + out_seq = env.Sequence() + self.assertEqual([ + ], + [i for i in directory.diff(env.Sequence([[3, 3]]), out_seq)]) + self.assertEqual([], out_seq) + + out_seq = env.Sequence() + self.assertEqual([ + ], + [i for i in directory.diff(env.Sequence([[6, 100]]), out_seq)]) + self.assertEqual([], out_seq) + directory.update(guid='2', prop='22') + self.assertEqual([ + ('2', { + 'prop': {'value': '22', 'mtime': os.stat('2/2/prop').st_mtime}, + }), + ], + [i for i in directory.diff(env.Sequence([[6, 100]]), out_seq)]) + self.assertEqual([[6, 6]], out_seq) + + def test_diff_Partial(self): + + class Document(document.Document): + + @active_property(slot=1) + def prop(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + directory.create(guid='1', prop='1', ctime=1, mtime=1) + for i in os.listdir('1/1'): + os.utime('1/1/%s' % i, (1, 1)) + directory.create(guid='2', prop='2', ctime=2, mtime=2) + for i in os.listdir('2/2'): + os.utime('2/2/%s' % i, (2, 2)) + + out_seq = env.Sequence() + for guid, diff in directory.diff(env.Sequence([[0, None]]), out_seq): + self.assertEqual('1', guid) + break + self.assertEqual([], out_seq) + + out_seq = env.Sequence() + for guid, diff in directory.diff(env.Sequence([[0, None]]), out_seq): + if guid == '2': + break + self.assertEqual([[1, 1]], out_seq) + + out_seq = env.Sequence() + for guid, diff in directory.diff(env.Sequence([[0, None]]), out_seq): + pass + self.assertEqual([[1, 2]], out_seq) + + def test_diff_WithBlobsSetByUrl(self): + + class Document(document.Document): + + @active_property(BlobProperty) + def blob(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + + directory.create(guid='1', ctime=1, mtime=1) + directory.set_blob('1', 'blob', url='http://sugarlabs.org') + for i in os.listdir('1/1'): + os.utime('1/1/%s' % i, (1, 1)) + + out_seq = env.Sequence() + self.assertEqual([ + ('1', { + 'guid': {'value': '1', 'mtime': 1}, + 'ctime': {'value': 1, 'mtime': 1}, + 'mtime': {'value': 1, 'mtime': 1}, + 'blob': {'mtime': 1, 'mime_type': 'application/octet-stream', 'url': 'http://sugarlabs.org'}, + }), + ], + [i for i in directory.diff(env.Sequence([[0, None]]), out_seq)]) + self.assertEqual([[1, 2]], out_seq) + + def test_diff_Filter(self): + + class Document(document.Document): + + @active_property(prefix='P') + def prop(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + + directory.create(guid='1', ctime=1, mtime=1, prop='1') + directory.create(guid='2', ctime=2, mtime=2, prop='2') + for i in os.listdir('2/2'): + os.utime('2/2/%s' % i, (2, 2)) + + out_seq = env.Sequence() + self.assertEqual([ + ('2', { + 'guid': {'value': '2', 'mtime': 2}, + 'ctime': {'value': 2, 'mtime': 2}, + 'mtime': {'value': 2, 'mtime': 2}, + 'prop': {'value': '2', 'mtime': 2}, + }), + ], + [i for i in directory.diff(env.Sequence([[0, None]]), out_seq, prop='2')]) + self.assertEqual([[2, 2]], out_seq) + + def test_diff_GroupBy(self): + + class Document(document.Document): + + @active_property(slot=1, prefix='P') + def prop(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + + directory.create(guid='1', ctime=1, mtime=1, prop='0') + for i in os.listdir('1/1'): + os.utime('1/1/%s' % i, (1, 1)) + directory.create(guid='2', ctime=2, mtime=2, prop='0') + for i in os.listdir('2/2'): + os.utime('2/2/%s' % i, (2, 2)) + + out_seq = env.Sequence() + self.assertEqual([ + ('2', { + 'guid': {'value': '2', 'mtime': 2}, + 'ctime': {'value': 2, 'mtime': 2}, + 'mtime': {'value': 2, 'mtime': 2}, + 'prop': {'value': '0', 'mtime': 2}, + }), + ], + [i for i in directory.diff(env.Sequence([[0, None]]), out_seq, group_by='prop')]) + self.assertEqual([[2, 2]], out_seq) + + def test_merge_New(self): + + class Document(document.Document): + + @active_property(slot=1) + def prop(self, value): + return value + + @active_property(BlobProperty) + def blob(self, value): + return value + + directory1 = Directory('document1', Document, IndexWriter) + + directory1.create(guid='1', prop='1', ctime=1, mtime=1) + directory1.set_blob('1', 'blob', StringIO('1')) + for i in os.listdir('document1/1/1'): + os.utime('document1/1/1/%s' % i, (1, 1)) + + directory1.create(guid='2', prop='2', ctime=2, mtime=2) + directory1.set_blob('2', 'blob', StringIO('2')) + for i in os.listdir('document1/2/2'): + os.utime('document1/2/2/%s' % i, (2, 2)) + + directory1.create(guid='3', prop='3', ctime=3, mtime=3) + for i in os.listdir('document1/3/3'): + os.utime('document1/3/3/%s' % i, (3, 3)) + + directory2 = Directory('document2', Document, IndexWriter) + for guid, diff in directory1.diff(env.Sequence([[0, None]]), env.Sequence()): + directory2.merge(guid, diff) + + self.assertEqual( + sorted([ + (1, '1', 1, '1'), + (2, '2', 2, '2'), + (3, '3', 3, '3'), + ]), + sorted([(i['ctime'], i['prop'], i['mtime'], i['guid']) for i in directory2.find(0, 1024)[0]])) + + doc = directory2.get('1') + self.assertEqual(1, doc.get('seqno')) + self.assertEqual(1, doc.meta('guid')['mtime']) + self.assertEqual(1, doc.meta('ctime')['mtime']) + self.assertEqual(1, doc.meta('prop')['mtime']) + self.assertEqual(1, doc.meta('mtime')['mtime']) + self.assertEqual(1, doc.meta('blob')['mtime']) + + doc = directory2.get('2') + self.assertEqual(2, doc.get('seqno')) + self.assertEqual(2, doc.meta('guid')['mtime']) + self.assertEqual(2, doc.meta('ctime')['mtime']) + self.assertEqual(2, doc.meta('prop')['mtime']) + self.assertEqual(2, doc.meta('mtime')['mtime']) + self.assertEqual(2, doc.meta('blob')['mtime']) + + doc = directory2.get('3') + self.assertEqual(3, doc.get('seqno')) + self.assertEqual(3, doc.meta('guid')['mtime']) + self.assertEqual(3, doc.meta('ctime')['mtime']) + self.assertEqual(3, doc.meta('prop')['mtime']) + self.assertEqual(3, doc.meta('mtime')['mtime']) + self.assertEqual(None, doc.meta('blob')) + + def test_merge_Update(self): + + class Document(document.Document): + + @active_property(BlobProperty) + def blob(self, value): + return value + + directory1 = Directory('document1', Document, IndexWriter) + directory2 = Directory('document2', Document, IndexWriter) + + directory1.create(guid='guid', ctime=1, mtime=1) + directory1.set_blob('guid', 'blob', StringIO('1')) + for i in os.listdir('document1/gu/guid'): + os.utime('document1/gu/guid/%s' % i, (1, 1)) + + directory2.create(guid='guid', ctime=2, mtime=2) + directory2.set_blob('guid', 'blob', StringIO('2')) + for i in os.listdir('document2/gu/guid'): + os.utime('document2/gu/guid/%s' % i, (2, 2)) + + self.assertEqual( + [(2, 2, 'guid')], + [(i['ctime'], i['mtime'], i['guid']) for i in directory2.find(0, 1024)[0]]) + doc = directory2.get('guid') + self.assertEqual(2, doc.get('seqno')) + self.assertEqual(2, doc.meta('guid')['mtime']) + self.assertEqual(2, doc.meta('ctime')['mtime']) + self.assertEqual(2, doc.meta('mtime')['mtime']) + self.assertEqual(2, doc.meta('blob')['mtime']) + self.assertEqual('2', file('document2/gu/guid/blob.blob').read()) + + for guid, diff in directory1.diff(env.Sequence([[0, None]]), env.Sequence()): + directory2.merge(guid, diff) + + self.assertEqual( + [(2, 2, 'guid')], + [(i['ctime'], i['mtime'], i['guid']) for i in directory2.find(0, 1024)[0]]) + doc = directory2.get('guid') + self.assertEqual(2, doc.get('seqno')) + self.assertEqual(2, doc.meta('guid')['mtime']) + self.assertEqual(2, doc.meta('ctime')['mtime']) + self.assertEqual(2, doc.meta('mtime')['mtime']) + self.assertEqual(2, doc.meta('blob')['mtime']) + self.assertEqual('2', file('document2/gu/guid/blob.blob').read()) + + os.utime('document1/gu/guid/mtime', (3, 3)) + for guid, diff in directory1.diff(env.Sequence([[0, None]]), env.Sequence()): + directory2.merge(guid, diff) + + self.assertEqual( + [(2, 1, 'guid')], + [(i['ctime'], i['mtime'], i['guid']) for i in directory2.find(0, 1024)[0]]) + doc = directory2.get('guid') + self.assertEqual(3, doc.get('seqno')) + self.assertEqual(2, doc.meta('guid')['mtime']) + self.assertEqual(2, doc.meta('ctime')['mtime']) + self.assertEqual(3, doc.meta('mtime')['mtime']) + self.assertEqual(2, doc.meta('blob')['mtime']) + self.assertEqual('2', file('document2/gu/guid/blob.blob').read()) + + os.utime('document1/gu/guid/blob', (4, 4)) + for guid, diff in directory1.diff(env.Sequence([[0, None]]), env.Sequence()): + directory2.merge(guid, diff) + + self.assertEqual( + [(2, 1, 'guid')], + [(i['ctime'], i['mtime'], i['guid']) for i in directory2.find(0, 1024)[0]]) + doc = directory2.get('guid') + self.assertEqual(4, doc.get('seqno')) + self.assertEqual(2, doc.meta('guid')['mtime']) + self.assertEqual(2, doc.meta('ctime')['mtime']) + self.assertEqual(3, doc.meta('mtime')['mtime']) + self.assertEqual(4, doc.meta('blob')['mtime']) + self.assertEqual('1', file('document2/gu/guid/blob.blob').read()) + + def test_merge_SeqnoLessMode(self): + + class Document(document.Document): + + @active_property(slot=1) + def prop(self, value): + return value + + directory1 = Directory('document1', Document, IndexWriter) + directory1.create(guid='1', prop='1', ctime=1, mtime=1) + + directory2 = Directory('document2', Document, IndexWriter) + for guid, diff in directory1.diff(env.Sequence([[0, None]]), env.Sequence()): + directory2.merge(guid, diff, increment_seqno=False) + self.assertEqual( + [(1, 1, '1', '1')], + [(i['ctime'], i['mtime'], i['guid'], i['prop']) for i in directory2.find(0, 1024)[0]]) + doc = directory2.get('1') + self.assertEqual(None, doc.get('seqno')) + self.assertEqual(0, doc.meta('guid')['seqno']) + self.assertEqual(0, doc.meta('prop')['seqno']) + + directory3 = Directory('document3', Document, IndexWriter) + for guid, diff in directory1.diff(env.Sequence([[0, None]]), env.Sequence()): + directory3.merge(guid, diff=diff) + self.assertEqual( + [(1, 1, '1', '1')], + [(i['ctime'], i['mtime'], i['guid'], i['prop']) for i in directory3.find(0, 1024)[0]]) + doc = directory3.get('1') + self.assertEqual(1, doc.get('seqno')) + self.assertEqual(1, doc.meta('guid')['seqno']) + self.assertEqual(1, doc.meta('prop')['seqno']) + + directory1.update(guid='1', prop='2', ctime=2, mtime=2) + + for guid, diff in directory1.diff(env.Sequence([[0, None]]), env.Sequence()): + directory3.merge(guid, diff, increment_seqno=False) + self.assertEqual( + [(2, 2, '1', '2')], + [(i['ctime'], i['mtime'], i['guid'], i['prop']) for i in directory3.find(0, 1024)[0]]) + doc = directory3.get('1') + self.assertEqual(1, doc.get('seqno')) + self.assertEqual(1, doc.meta('guid')['seqno']) + self.assertEqual(1, doc.meta('prop')['seqno']) + + time.sleep(1) + directory1.update(guid='1', prop='3', ctime=3, mtime=3) + + for guid, diff in directory1.diff(env.Sequence([[0, None]]), env.Sequence()): + directory3.merge(guid, diff) + self.assertEqual( + [(3, 3, '1', '3')], + [(i['ctime'], i['mtime'], i['guid'], i['prop']) for i in directory3.find(0, 1024)[0]]) + doc = directory3.get('1') + self.assertEqual(2, doc.get('seqno')) + self.assertEqual(1, doc.meta('guid')['seqno']) + self.assertEqual(2, doc.meta('prop')['seqno']) + + def test_merge_AvoidCalculatedBlobs(self): + + class Document(document.Document): + + @active_property(BlobProperty) + def blob(self, value): + return {'url': 'http://foo/bar', 'mime_type': 'image/png'} + + directory1 = Directory('document1', Document, IndexWriter) + directory1.create(guid='guid', ctime=1, mtime=1) + for i in os.listdir('document1/gu/guid'): + os.utime('document1/gu/guid/%s' % i, (1, 1)) + + directory2 = Directory('document2', Document, IndexWriter) + for guid, diff in directory1.diff(env.Sequence([[0, None]]), env.Sequence()): + directory2.merge(guid, diff) + + doc = directory2.get('guid') + self.assertEqual(1, doc.get('seqno')) + self.assertEqual(1, doc.meta('guid')['mtime']) + assert not exists('document2/gu/guid/blob') + + def test_merge_Blobs(self): + + class Document(document.Document): + + @active_property(BlobProperty) + def blob(self, value): + return value + + directory = Directory('document', Document, IndexWriter) + self.touch(('file', 'blob-1')) + directory.merge('1', { + 'guid': {'mtime': 1, 'value': '1'}, + 'ctime': {'mtime': 2, 'value': 2}, + 'mtime': {'mtime': 3, 'value': 3}, + 'blob': {'mtime': 4, 'path': 'file'}, + }) + + self.assertEqual( + [(2, 3, '1')], + [(i['ctime'], i['mtime'], i['guid']) for i in directory.find(0, 1024)[0]]) + + doc = directory.get('1') + self.assertEqual(1, doc.get('seqno')) + self.assertEqual(1, doc.meta('guid')['mtime']) + self.assertEqual(2, doc.meta('ctime')['mtime']) + self.assertEqual(3, doc.meta('mtime')['mtime']) + self.assertEqual(4, doc.meta('blob')['mtime']) + self.assertEqual('blob-1', file('document/1/1/blob.blob').read()) + + directory.merge('1', { + 'blob': {'mtime': 5, 'content': b64encode('blob-2')}, + }) + + self.assertEqual(5, doc.meta('blob')['mtime']) + self.assertEqual('blob-2', file('document/1/1/blob.blob').read()) + + def test_MalformedGUIDs(self): + + class Document(document.Document): + pass + + directory = Directory(tests.tmpdir, Document, IndexWriter) + + self.assertRaises(RuntimeError, directory.create, {'guid': 'foo/bar'}) + self.assertRaises(RuntimeError, directory.create, {'guid': 'foo bar'}) + self.assertRaises(RuntimeError, directory.create, {'guid': 'foo#bar'}) + assert directory.create({'guid': 'foo-bar.1-2'}) + + def __test_Integers(self): + db = Index({ + 'prop': ActiveProperty('prop', 1, 'A', typecast=int, full_text=True), + }) + + db.store('1', {'prop': 9}, True) + db.store('2', {'prop': 89}, True) + db.store('3', {'prop': 777}, True) + + self.assertEqual( + [ + {'guid': '1', 'prop': 9}, + {'guid': '2', 'prop': 89}, + {'guid': '3', 'prop': 777}, + ], + db._find(order_by='prop')[0]) + + self.assertEqual( + [ + {'guid': '1', 'prop': 9}, + {'guid': '2', 'prop': 89}, + ], + db._find(query='prop:0..100', order_by='prop')[0]) + + self.assertEqual( + [ + {'guid': '1', 'prop': 9}, + ], + db._find(query='prop:9', order_by='prop')[0]) + + self.assertEqual( + [ + {'guid': '2', 'prop': 89}, + ], + db._find(query='prop:=89', order_by='prop')[0]) + + def __test_Floats(self): + db = Index({ + 'prop': ActiveProperty('prop', 1, 'A', typecast=float, full_text=True), + }) + + db.store('1', {'prop': 9.1}, True) + db.store('2', {'prop': 89.2}, True) + db.store('3', {'prop': 777.3}, True) + + self.assertEqual( + [ + {'guid': '1', 'prop': 9.1}, + {'guid': '2', 'prop': 89.2}, + {'guid': '3', 'prop': 777.3}, + ], + db._find(order_by='prop')[0]) + + self.assertEqual( + [ + {'guid': '1', 'prop': 9.1}, + {'guid': '2', 'prop': 89.2}, + ], + db._find(query='prop:0..100', order_by='prop')[0]) + + self.assertEqual( + [ + {'guid': '1', 'prop': 9.1}, + ], + db._find(query='prop:9.1', order_by='prop')[0]) + + self.assertEqual( + [ + {'guid': '2', 'prop': 89.2}, + ], + db._find(query='prop:=89.2', order_by='prop')[0]) + + def __test_Booleans(self): + db = Index({ + 'prop': ActiveProperty('prop', 1, 'A', typecast=bool, full_text=True), + }) + + db.store('1', {'prop': True}, True) + db.store('2', {'prop': False}, True) + + self.assertEqual( + [ + {'guid': '2', 'prop': False}, + {'guid': '1', 'prop': True}, + ], + db._find(order_by='prop')[0]) + + self.assertEqual( + [ + {'guid': '2', 'prop': False}, + {'guid': '1', 'prop': True}, + ], + db._find(query='prop:0..100', order_by='prop')[0]) + + self.assertEqual( + [ + {'guid': '1', 'prop': True}, + ], + db._find(query='prop:1..1', order_by='prop')[0]) + + self.assertEqual( + [ + {'guid': '2', 'prop': False}, + ], + db._find(query='prop:0', order_by='prop')[0]) + + self.assertEqual( + [ + {'guid': '1', 'prop': True}, + ], + db._find(query='prop:=1', order_by='prop')[0]) + + +if __name__ == '__main__': + tests.main() |