diff options
Diffstat (limited to 'tests/units/db')
-rw-r--r-- | tests/units/db/__main__.py | 7 | ||||
-rwxr-xr-x | tests/units/db/files.py | 320 | ||||
-rwxr-xr-x | tests/units/db/index.py | 157 | ||||
-rwxr-xr-x | tests/units/db/metadata.py | 71 | ||||
-rwxr-xr-x | tests/units/db/resource.py | 312 | ||||
-rwxr-xr-x | tests/units/db/routes.py | 1628 | ||||
-rwxr-xr-x | tests/units/db/storage.py | 19 |
7 files changed, 1469 insertions, 1045 deletions
diff --git a/tests/units/db/__main__.py b/tests/units/db/__main__.py index fc91d7c..3b1b9ec 100644 --- a/tests/units/db/__main__.py +++ b/tests/units/db/__main__.py @@ -2,11 +2,12 @@ from __init__ import tests -from resource import * -from index import * -#from migrate import * +from metadata import * from storage import * +from index import * +from resource import * from routes import * +#from migrate import * if __name__ == '__main__': tests.main() diff --git a/tests/units/db/files.py b/tests/units/db/files.py new file mode 100755 index 0000000..0d806df --- /dev/null +++ b/tests/units/db/files.py @@ -0,0 +1,320 @@ + + def test_diff_WithBlobsSetByUrl(self): + URL = 'http://src.sugarlabs.org/robots.txt' + URL_content = urllib2.urlopen(URL).read() + + class Document(db.Resource): + + @db.blob_property() + def blob(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + + directory.create({'guid': '1', 'ctime': 1, 'mtime': 1}) + directory.update('1', {'blob': {'url': URL}}) + self.utime('1/1', 1) + + out_seq = Sequence() + self.assertEqual([ + {'guid': '1', 'diff': { + 'guid': {'value': '1', 'mtime': 1}, + 'ctime': {'value': 1, 'mtime': 1}, + 'mtime': {'value': 1, 'mtime': 1}, + 'blob': { + 'url': URL, + 'mtime': 1, + }, + }}, + ], + [i for i in diff(directory, [[0, None]], out_seq)]) + self.assertEqual([[1, 2]], out_seq) + + def test_merge_AvoidCalculatedBlobs(self): + + class Document(db.Resource): + + @db.blob_property() + 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 patch in diff(directory1, [[0, None]], Sequence()): + directory2.merge(**patch) + + 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(db.Resource): + + @db.blob_property() + def blob(self, value): + return value + + directory = Directory('document', Document, IndexWriter) + self.touch(('blob', 'blob-1')) + directory.merge('1', { + 'guid': {'mtime': 1, 'value': '1'}, + 'ctime': {'mtime': 2, 'value': 2}, + 'mtime': {'mtime': 3, 'value': 3}, + 'blob': {'mtime': 4, 'blob': 'blob'}, + }) + + self.assertEqual( + [(2, 3, '1')], + [(i['ctime'], i['mtime'], i['guid']) for i in directory.find()[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()) + + self.touch(('blob', 'blob-2')) + directory.merge('1', { + 'blob': {'mtime': 5, 'blob': 'blob'}, + }) + + self.assertEqual(5, doc.meta('blob')['mtime']) + self.assertEqual('blob-2', file('document/1/1/blob.blob').read()) + + + def test_DeleteOldBlobOnUpdate(self): + + class Document(db.Resource): + + @db.blob_property() + def blob(self, value): + return value + + directory = Directory(tests.tmpdir, Document, IndexWriter) + + directory.create({'guid': 'guid', 'blob': 'foo'}) + assert exists('gu/guid/blob.blob') + directory.update('guid', {'blob': {'url': 'foo'}}) + assert not exists('gu/guid/blob.blob') + + directory.update('guid', {'blob': 'foo'}) + assert exists('gu/guid/blob.blob') + directory.update('guid', {'blob': {}}) + assert not exists('gu/guid/blob.blob') + + def test_diff_Blobs(self): + + class Document(db.Resource): + + @db.blob_property() + def prop(self, value): + return value + + volume = db.Volume('db', [Document]) + cp = NodeRoutes('guid', volume) + + guid = call(cp, method='POST', document='document', content={}) + call(cp, method='PUT', document='document', guid=guid, content={'prop': 'payload'}) + self.utime('db', 0) + + patch = diff(volume, toolkit.Sequence([[1, None]])) + self.assertEqual( + {'resource': 'document'}, + next(patch)) + record = next(patch) + self.assertEqual('payload', ''.join([i for i in record.pop('blob')])) + self.assertEqual( + {'guid': guid, 'blob_size': len('payload'), 'diff': { + 'prop': { + 'digest': hashlib.sha1('payload').hexdigest(), + 'blob_size': len('payload'), + 'mime_type': 'application/octet-stream', + 'mtime': 0, + }, + }}, + record) + self.assertEqual( + {'guid': guid, 'diff': { + 'guid': {'value': guid, 'mtime': 0}, + 'author': {'mtime': 0, 'value': {}}, + 'layer': {'mtime': 0, 'value': []}, + 'tags': {'mtime': 0, 'value': []}, + 'mtime': {'value': 0, 'mtime': 0}, + 'ctime': {'value': 0, 'mtime': 0}, + }}, + next(patch)) + self.assertEqual( + {'commit': [[1, 2]]}, + next(patch)) + self.assertRaises(StopIteration, next, patch) + + def test_diff_BlobUrls(self): + url = 'http://src.sugarlabs.org/robots.txt' + blob = urllib2.urlopen(url).read() + + class Document(db.Resource): + + @db.blob_property() + def prop(self, value): + return value + + volume = db.Volume('db', [Document]) + cp = NodeRoutes('guid', volume) + + guid = call(cp, method='POST', document='document', content={}) + call(cp, method='PUT', document='document', guid=guid, content={'prop': {'url': url}}) + self.utime('db', 1) + + self.assertEqual([ + {'resource': 'document'}, + {'guid': guid, + 'diff': { + 'guid': {'value': guid, 'mtime': 1}, + 'author': {'mtime': 1, 'value': {}}, + 'layer': {'mtime': 1, 'value': []}, + 'tags': {'mtime': 1, 'value': []}, + 'mtime': {'value': 0, 'mtime': 1}, + 'ctime': {'value': 0, 'mtime': 1}, + 'prop': {'url': url, 'mtime': 1}, + }, + }, + {'commit': [[1, 2]]}, + ], + [i for i in diff(volume, toolkit.Sequence([[1, None]]))]) + + patch = diff(volume, toolkit.Sequence([[1, None]]), fetch_blobs=True) + self.assertEqual( + {'resource': 'document'}, + next(patch)) + record = next(patch) + self.assertEqual(blob, ''.join([i for i in record.pop('blob')])) + self.assertEqual( + {'guid': guid, 'blob_size': len(blob), 'diff': {'prop': {'mtime': 1}}}, + record) + self.assertEqual( + {'guid': guid, 'diff': { + 'guid': {'value': guid, 'mtime': 1}, + 'author': {'mtime': 1, 'value': {}}, + 'layer': {'mtime': 1, 'value': []}, + 'tags': {'mtime': 1, 'value': []}, + 'mtime': {'value': 0, 'mtime': 1}, + 'ctime': {'value': 0, 'mtime': 1}, + }}, + next(patch)) + self.assertEqual( + {'commit': [[1, 2]]}, + next(patch)) + self.assertRaises(StopIteration, next, patch) + + def test_diff_SkipBrokenBlobUrls(self): + + class Document(db.Resource): + + @db.blob_property() + def prop(self, value): + return value + + volume = db.Volume('db', [Document]) + cp = NodeRoutes('guid', volume) + + guid1 = call(cp, method='POST', document='document', content={}) + call(cp, method='PUT', document='document', guid=guid1, content={'prop': {'url': 'http://foo/bar'}}) + guid2 = call(cp, method='POST', document='document', content={}) + self.utime('db', 1) + + self.assertEqual([ + {'resource': 'document'}, + {'guid': guid1, + 'diff': { + 'guid': {'value': guid1, 'mtime': 1}, + 'author': {'mtime': 1, 'value': {}}, + 'layer': {'mtime': 1, 'value': []}, + 'tags': {'mtime': 1, 'value': []}, + 'mtime': {'value': 0, 'mtime': 1}, + 'ctime': {'value': 0, 'mtime': 1}, + 'prop': {'url': 'http://foo/bar', 'mtime': 1}, + }, + }, + {'guid': guid2, + 'diff': { + 'guid': {'value': guid2, 'mtime': 1}, + 'author': {'mtime': 1, 'value': {}}, + 'layer': {'mtime': 1, 'value': []}, + 'tags': {'mtime': 1, 'value': []}, + 'mtime': {'value': 0, 'mtime': 1}, + 'ctime': {'value': 0, 'mtime': 1}, + }, + }, + {'commit': [[1, 3]]}, + ], + [i for i in diff(volume, toolkit.Sequence([[1, None]]), fetch_blobs=False)]) + + self.assertEqual([ + {'resource': 'document'}, + {'guid': guid1, + 'diff': { + 'guid': {'value': guid1, 'mtime': 1}, + 'author': {'mtime': 1, 'value': {}}, + 'layer': {'mtime': 1, 'value': []}, + 'tags': {'mtime': 1, 'value': []}, + 'mtime': {'value': 0, 'mtime': 1}, + 'ctime': {'value': 0, 'mtime': 1}, + }, + }, + {'guid': guid2, + 'diff': { + 'guid': {'value': guid2, 'mtime': 1}, + 'author': {'mtime': 1, 'value': {}}, + 'layer': {'mtime': 1, 'value': []}, + 'tags': {'mtime': 1, 'value': []}, + 'mtime': {'value': 0, 'mtime': 1}, + 'ctime': {'value': 0, 'mtime': 1}, + }, + }, + {'commit': [[1, 3]]}, + ], + [i for i in diff(volume, toolkit.Sequence([[1, None]]), fetch_blobs=True)]) + + def test_merge_Blobs(self): + + class Document(db.Resource): + + @db.blob_property() + def prop(self, value): + return value + + volume = db.Volume('db', [Document]) + + merge(volume, [ + {'resource': 'document'}, + {'guid': '1', 'diff': { + 'guid': {'value': '1', 'mtime': 1.0}, + 'ctime': {'value': 2, 'mtime': 2.0}, + 'mtime': {'value': 3, 'mtime': 3.0}, + 'prop': { + 'blob': StringIO('payload'), + 'blob_size': len('payload'), + 'digest': hashlib.sha1('payload').hexdigest(), + 'mime_type': 'foo/bar', + 'mtime': 1, + }, + }}, + {'commit': [[1, 1]]}, + ]) + + assert volume['document'].exists('1') + blob = volume['document'].get('1')['prop'] + self.assertEqual(1, blob['mtime']) + self.assertEqual('foo/bar', blob['mime_type']) + self.assertEqual(hashlib.sha1('payload').hexdigest(), blob['digest']) + self.assertEqual(tests.tmpdir + '/db/document/1/1/prop.blob', blob['blob']) + self.assertEqual('payload', file(blob['blob']).read()) + diff --git a/tests/units/db/index.py b/tests/units/db/index.py index 9d996b0..cb144c6 100755 --- a/tests/units/db/index.py +++ b/tests/units/db/index.py @@ -12,23 +12,22 @@ from __init__ import tests from sugar_network import toolkit from sugar_network.db import index -from sugar_network.db.index import _fmt_prop_value -from sugar_network.db.metadata import Metadata, IndexedProperty, GUID_PREFIX, Property +from sugar_network.db.metadata import Metadata, Property, GUID_PREFIX, Boolean, Enum, List, Localized, Numeric from sugar_network.toolkit.router import ACL -from sugar_network.toolkit import coroutine +from sugar_network.toolkit import coroutine, i18n class IndexTest(tests.Test): def test_Term_AvoidCollisionsWithGuid(self): - self.assertRaises(RuntimeError, IndexedProperty, 'key', 0, 'I') - self.assertRaises(RuntimeError, IndexedProperty, 'key', 0, 'K') - self.assertRaises(RuntimeError, IndexedProperty, 'key', 1, 'I') - IndexedProperty('key', 1, 'K') - IndexedProperty('guid', 0, 'I') + self.assertRaises(RuntimeError, Property, 'key', 0, 'I') + self.assertRaises(RuntimeError, Property, 'key', 0, 'K') + self.assertRaises(RuntimeError, Property, 'key', 1, 'I') + Property('key', 1, 'K') + Property('guid', 0, 'I') def test_Create(self): - db = Index({'key': IndexedProperty('key', 1, 'K')}) + db = Index({'key': Property('key', 1, 'K')}) self.assertEqual( ([], 0), @@ -47,8 +46,8 @@ class IndexTest(tests.Test): def test_update(self): db = Index({ - 'var_1': IndexedProperty('var_1', 1, 'A'), - 'var_2': IndexedProperty('var_2', 2, 'B'), + 'var_1': Property('var_1', 1, 'A'), + 'var_2': Property('var_2', 2, 'B'), }) db.store('1', {'var_1': 'value_1', 'var_2': 'value_2'}) @@ -62,7 +61,7 @@ class IndexTest(tests.Test): db._find(reply=['var_1', 'var_2'])) def test_delete(self): - db = Index({'key': IndexedProperty('key', 1, 'K')}) + db = Index({'key': Property('key', 1, 'K')}) db.store('1', {'key': 'value'}) self.assertEqual( @@ -74,8 +73,17 @@ class IndexTest(tests.Test): ([], 0), db._find(reply=['key'])) - def test_IndexByFmt(self): - db = Index({'key': IndexedProperty('key', 1, 'K', fmt=lambda x: "foo" + x)}) + def test_IndexCalculatedValue(self): + + class Property2(Property): + + def encode(self, value): + yield "foo" + value + + def decode(self, value): + return "foo" + value + + db = Index({'key': Property2('key', 1, 'K')}) db.store('1', {'key': 'bar'}) @@ -92,15 +100,17 @@ class IndexTest(tests.Test): [], db._find(key='fake', reply=['key'])[0]) - def test_IndexByFmtGenerator(self): + def test_IndexCalculatedValues(self): - def iterate(value): - if value != 'fake': - yield 'foo' - yield 'bar' - yield value + class Property2(Property): - db = Index({'key': IndexedProperty('key', 1, 'K', fmt=iterate)}) + def encode(self, value): + if value != 'fake': + yield 'foo' + yield 'bar' + yield value + + db = Index({'key': Property2('key', 1, 'K')}) db.store('1', {'key': 'value'}) self.assertEqual( @@ -118,9 +128,9 @@ class IndexTest(tests.Test): def test_find(self): db = Index({ - 'var_1': IndexedProperty('var_1', 1, 'A', full_text=True), - 'var_2': IndexedProperty('var_2', 2, 'B', full_text=True), - 'var_3': IndexedProperty('var_3', 3, 'C', full_text=True), + 'var_1': Property('var_1', 1, 'A', full_text=True), + 'var_2': Property('var_2', 2, 'B', full_text=True), + 'var_3': Property('var_3', 3, 'C', full_text=True), }) db.store('1', {'var_1': '1', 'var_2': 'у', 'var_3': 'г'}) @@ -149,7 +159,7 @@ class IndexTest(tests.Test): def test_find_NoneFilters(self): db = Index({ - 'prop': IndexedProperty('prop', 1, 'P', full_text=True), + 'prop': Property('prop', 1, 'P', full_text=True), }) db.store('guid', {'prop': 'value'}) @@ -164,9 +174,9 @@ class IndexTest(tests.Test): [{'guid': 'guid', 'prop': 'value'}], db._find(guid=None, reply=['prop'])[0]) - def test_find_WithTypeCast(self): + def test_find_DecodeArgs(self): db = Index({ - 'var_1': IndexedProperty('var_1', 1, 'A', typecast=bool), + 'var_1': Boolean('var_1', 1, 'A'), }) db.store('1', {'var_1': True}) @@ -181,9 +191,9 @@ class IndexTest(tests.Test): def test_find_WithProps(self): db = Index({ - 'var_1': IndexedProperty('var_1', 1, 'A', full_text=True), - 'var_2': IndexedProperty('var_2', 2, 'B', full_text=True), - 'var_3': IndexedProperty('var_3', 3, 'C', full_text=True), + 'var_1': Property('var_1', 1, 'A', full_text=True), + 'var_2': Property('var_2', 2, 'B', full_text=True), + 'var_3': Property('var_3', 3, 'C', full_text=True), }) db.store('1', {'var_1': '1', 'var_2': 'у', 'var_3': 'г'}) @@ -209,9 +219,9 @@ class IndexTest(tests.Test): def test_find_WithAllBooleanProps(self): db = Index({ - 'var_1': IndexedProperty('var_1', 1, 'A', boolean=True, full_text=True), - 'var_2': IndexedProperty('var_2', 2, 'B', boolean=True, full_text=True), - 'var_3': IndexedProperty('var_3', 3, 'C', boolean=True, full_text=True), + 'var_1': Property('var_1', 1, 'A', boolean=True, full_text=True), + 'var_2': Property('var_2', 2, 'B', boolean=True, full_text=True), + 'var_3': Property('var_3', 3, 'C', boolean=True, full_text=True), }) db.store('1', {'var_1': '1', 'var_2': 'у', 'var_3': 'г'}) @@ -232,9 +242,9 @@ class IndexTest(tests.Test): def test_find_WithBooleanProps(self): db = Index({ - 'var_1': IndexedProperty('var_1', 1, 'A', boolean=True, full_text=True), - 'var_2': IndexedProperty('var_2', 2, 'B', boolean=False, full_text=True), - 'var_3': IndexedProperty('var_3', 3, 'C', boolean=True, full_text=True), + 'var_1': Property('var_1', 1, 'A', boolean=True, full_text=True), + 'var_2': Property('var_2', 2, 'B', boolean=False, full_text=True), + 'var_3': Property('var_3', 3, 'C', boolean=True, full_text=True), }) db.store('1', {'var_1': '1', 'var_2': 'у', 'var_3': 'г'}) @@ -254,7 +264,7 @@ class IndexTest(tests.Test): db._find(query='б', var_1='1', var_2='у', var_3='г', reply=['var_1'])) def test_find_ExactQuery(self): - db = Index({'key': IndexedProperty('key', 1, 'K', full_text=True)}) + db = Index({'key': Property('key', 1, 'K', full_text=True)}) db.store('1', {'key': 'фу'}) db.store('2', {'key': 'фу бар'}) @@ -280,7 +290,7 @@ class IndexTest(tests.Test): def test_find_ExactQueryTerms(self): term = 'azAZ09_' - db = Index({term: IndexedProperty(term, 1, 'T', full_text=True)}) + db = Index({term: Property(term, 1, 'T', full_text=True)}) db.store('1', {term: 'test'}) db.store('2', {term: 'test fail'}) @@ -290,7 +300,7 @@ class IndexTest(tests.Test): db._find(query='%s:=test' % term, reply=['guid'])) def test_find_ReturnPortions(self): - db = Index({'key': IndexedProperty('key', 1, 'K')}) + db = Index({'key': Property('key', 1, 'K')}) db.store('1', {'key': '1'}) db.store('2', {'key': '2'}) @@ -311,8 +321,8 @@ class IndexTest(tests.Test): def test_find_OrderBy(self): db = Index({ - 'var_1': IndexedProperty('var_1', 1, 'A'), - 'var_2': IndexedProperty('var_2', 2, 'B'), + 'var_1': Property('var_1', 1, 'A'), + 'var_2': Property('var_2', 2, 'B'), }) db.store('1', {'var_1': '1', 'var_2': '3'}) @@ -341,15 +351,15 @@ class IndexTest(tests.Test): def test_find_GroupBy(self): db = Index({ - 'var_1': IndexedProperty('var_1', 1, 'A'), - 'var_2': IndexedProperty('var_2', 2, 'B'), - 'var_3': IndexedProperty('var_3', 3, 'C'), - 'var_4': IndexedProperty('var_4', 4, 'D'), + 'var_1': Property('var_1', 1, 'A'), + 'var_2': Property('var_2', 2, 'B'), + 'var_3': Property('var_3', 3, 'C'), + 'var_4': Property('var_4', 4, 'D'), }) - db.store('1', {'var_1': '1', 'var_2': '1', 'var_3': '3', 'var_4': 0}) - db.store('2', {'var_1': '2', 'var_2': '1', 'var_3': '4', 'var_4': 0}) - db.store('3', {'var_1': '3', 'var_2': '2', 'var_3': '4', 'var_4': 0}) + db.store('1', {'var_1': '1', 'var_2': '1', 'var_3': '3', 'var_4': '0'}) + db.store('2', {'var_1': '2', 'var_2': '1', 'var_3': '4', 'var_4': '0'}) + db.store('3', {'var_1': '3', 'var_2': '2', 'var_3': '4', 'var_4': '0'}) self.assertEqual( [{'guid': '1', 'var_1': '1'}, {'guid': '3', 'var_1': '3'}], @@ -366,7 +376,7 @@ class IndexTest(tests.Test): def test_MultipleValues(self): db = Index({ - 'prop': IndexedProperty('prop', prefix='B', typecast=[1, 2], full_text=True), + 'prop': List(name='prop', prefix='B', subtype=Enum([1, 2, 3]), full_text=True), }) db.store('1', {'prop': [1, 2]}) db.store('2', {'prop': [2, 3]}) @@ -385,7 +395,7 @@ class IndexTest(tests.Test): db.close() db = Index({ - 'prop': IndexedProperty('prop', prefix='B', typecast=[], full_text=True), + 'prop': List(name='prop', prefix='B', full_text=True), }) db.store('1', {'prop': ['a', 'b']}) db.store('2', {'prop': ['b', 'c']}) @@ -448,7 +458,7 @@ class IndexTest(tests.Test): db.close() def test_find_OrderByGUIDAllTime(self): - db = Index({'prop': IndexedProperty('prop', 1, 'P')}) + db = Index({'prop': Property('prop', 1, 'P')}) db.store('3', {'prop': '1'}) db.store('2', {'prop': '1'}) @@ -469,7 +479,7 @@ class IndexTest(tests.Test): def test_find_Region(self): term = 'azAZ09_' - db = Index({term: IndexedProperty(term, 1, 'T', full_text=True)}) + db = Index({term: Property(term, 1, 'T', full_text=True)}) db.store('1', {term: 'test'}) db.store('2', {term: 'test fail'}) @@ -479,7 +489,7 @@ class IndexTest(tests.Test): db._find(query='%s:=test' % term, reply=['guid'])) def test_find_WithListProps(self): - db = Index({'prop': IndexedProperty('prop', None, 'A', full_text=True, typecast=[])}) + db = Index({'prop': List(name='prop', prefix='A', full_text=True)}) db.store('1', {'prop': ('a', )}) db.store('2', {'prop': ('a', 'aa')}) @@ -571,10 +581,10 @@ class IndexTest(tests.Test): self.assertEqual(1, len(commits)) def test_SortLocalizedProps(self): - toolkit._default_langs = ['default_lang'] + i18n._default_langs = ['default_lang'] current_lang = locale.getdefaultlocale()[0].replace('_', '-') - db = Index({'prop': IndexedProperty('prop', 1, 'A', localized=True)}) + db = Index({'prop': Localized(name='prop', slot=1, prefix='A')}) db.store('0', {'prop': {'foo': '5'}}) db.store('1', {'prop': {current_lang: '4', 'default_lang': '1', 'foo': '3'}}) @@ -598,7 +608,7 @@ class IndexTest(tests.Test): db._find(order_by='-prop')[0]) def test_SearchByLocalizedProps(self): - db = Index({'prop': IndexedProperty('prop', 1, 'A', localized=True, full_text=True)}) + db = Index({'prop': Localized(name='prop', slot=1, prefix='A', full_text=True)}) db.store('1', {'prop': {'a': 'ё'}}) db.store('2', {'prop': {'a': 'ё', 'b': 'ю'}}) @@ -635,7 +645,7 @@ class IndexTest(tests.Test): sorted(db._find(query='prop:я')[0])) def test_find_MultipleFilter(self): - db = Index({'prop': IndexedProperty('prop', 1, 'A')}) + db = Index({'prop': Property('prop', 1, 'A')}) db.store('1', {'prop': 'a'}) db.store('2', {'prop': 'b'}) @@ -677,7 +687,7 @@ class IndexTest(tests.Test): db._find(prop=['b', 'foo', 'bar'], reply=['guid'])[0]) def test_find_AndNotFilter(self): - db = Index({'prop': IndexedProperty('prop', 1, 'A')}) + db = Index({'prop': Property('prop', 1, 'A')}) db.store('1', {'prop': 'a'}) db.store('2', {'prop': 'b'}) @@ -721,24 +731,21 @@ class IndexTest(tests.Test): ]), sorted(db._find(prop=['a', 'c'], reply=['guid'], **{'!prop': 'b'})[0])) - def test_fmt_prop_value(self): - prop = Property('prop') - self.assertEqual(['0'], [i for i in _fmt_prop_value(prop, 0)]) - self.assertEqual(['1'], [i for i in _fmt_prop_value(prop, 1)]) - self.assertEqual(['0'], [i for i in _fmt_prop_value(prop, 0)]) - self.assertEqual(['1.1'], [i for i in _fmt_prop_value(prop, 1.1)]) - self.assertEqual(['0', '1'], [i for i in _fmt_prop_value(prop, [0, 1])]) - self.assertEqual(['2', '1'], [i for i in _fmt_prop_value(prop, [2, 1])]) - self.assertEqual(['probe', 'True', '0'], [i for i in _fmt_prop_value(prop, ['probe', True, 0])]) - self.assertEqual(['True'], [i for i in _fmt_prop_value(prop, True)]) - self.assertEqual(['False'], [i for i in _fmt_prop_value(prop, False)]) + def test_find_CustomEncode(self): + db = Index({'trait': Numeric('trait', 1, 'A')}) + + db.store('1', {'trait': 1}) + db.store('2', {'trait': 2}) + db.store('11', {'trait': 11}) + + self.assertEqual([{'guid': '1'}], db._find(trait='1')[0]) + self.assertEqual([{'guid': '1'}], db._find(trait=1)[0]) - prop = Property('prop', typecast=bool) - self.assertEqual(['1'], [i for i in _fmt_prop_value(prop, True)]) - self.assertEqual(['0'], [i for i in _fmt_prop_value(prop, False)]) + self.assertEqual([{'guid': '2'}], db._find(trait='2')[0]) + self.assertEqual([{'guid': '2'}], db._find(trait=2)[0]) - prop = Property('prop', fmt=lambda x: x.keys()) - self.assertEqual(['a', '2'], [i for i in _fmt_prop_value(prop, {'a': 1, 2: 'b'})]) + self.assertEqual([{'guid': '11'}], db._find(trait='11')[0]) + self.assertEqual([{'guid': '11'}], db._find(trait=11)[0]) class Index(index.IndexWriter): @@ -750,7 +757,7 @@ class Index(index.IndexWriter): metadata = Metadata(Index) metadata.update(props) - metadata['guid'] = IndexedProperty('guid', + metadata['guid'] = Property('guid', acl=ACL.CREATE | ACL.READ, slot=0, prefix=GUID_PREFIX) diff --git a/tests/units/db/metadata.py b/tests/units/db/metadata.py new file mode 100755 index 0000000..a0ba512 --- /dev/null +++ b/tests/units/db/metadata.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# sugar-lint: disable + +from __init__ import tests + +from sugar_network import db + + +class MetadataTest(tests.Test): + + def test_Typecast(self): + prop = db.Numeric() + self.assertEqual(1, prop.typecast(1)) + self.assertEqual(1, prop.typecast(1.1)) + self.assertEqual(1, prop.typecast('1')) + self.assertRaises(ValueError, prop.typecast, '1.0') + self.assertRaises(ValueError, prop.typecast, '') + self.assertRaises(TypeError, prop.typecast, None) + + prop = db.Boolean() + self.assertEqual(False, prop.typecast(0)) + self.assertEqual(True, prop.typecast(1)) + self.assertEqual(True, prop.typecast(1.1)) + self.assertEqual(True, prop.typecast('1')) + self.assertEqual(False, prop.typecast('false')) + self.assertEqual(True, prop.typecast(True)) + self.assertEqual(False, prop.typecast(False)) + self.assertEqual(False, prop.typecast('False')) + self.assertEqual(False, prop.typecast('0')) + self.assertEqual(False, prop.typecast('')) + self.assertEqual(False, prop.typecast(None)) + + prop = db.List(subtype=db.Numeric()) + self.assertEqual([1], prop.typecast(1)) + self.assertEqual([], prop.typecast(None)) + self.assertRaises(ValueError, prop.typecast, '') + self.assertEqual([], prop.typecast([])) + self.assertEqual([123], prop.typecast('123')) + self.assertRaises(ValueError, prop.typecast, 'a') + self.assertEqual([123, 4, 5], prop.typecast(['123', 4, 5.6])) + + prop = db.Enum(items=[1, 2]) + self.assertRaises(ValueError, prop.typecast, 0) + self.assertRaises(TypeError, prop.typecast, None) + self.assertRaises(ValueError, prop.typecast, '') + self.assertRaises(ValueError, prop.typecast, 'A') + self.assertRaises(ValueError, prop.typecast, '3') + self.assertEqual(1, prop.typecast(1)) + self.assertEqual(2, prop.typecast(2)) + self.assertEqual(1, prop.typecast('1')) + + prop = db.List() + self.assertEqual([], prop.typecast(None)) + self.assertEqual([''], prop.typecast('')) + self.assertEqual([''], prop.typecast([''])) + self.assertEqual([], prop.typecast([])) + self.assertEqual([0], prop.typecast(0)) + self.assertEqual([''], prop.typecast('')) + self.assertEqual(['foo'], prop.typecast('foo')) + + prop = db.List(subtype=db.Enum(['A', 'B', 'C'])) + self.assertRaises(ValueError, prop.typecast, '') + self.assertRaises(ValueError, prop.typecast, ['']) + self.assertEqual([], prop.typecast([])) + self.assertEqual(['A', 'B', 'C'], prop.typecast(['A', 'B', 'C'])) + self.assertRaises(ValueError, prop.typecast, ['a']) + self.assertRaises(ValueError, prop.typecast, ['A', 'x']) + + +if __name__ == '__main__': + tests.main() diff --git a/tests/units/db/resource.py b/tests/units/db/resource.py index d09010e..ef305ec 100755 --- a/tests/units/db/resource.py +++ b/tests/units/db/resource.py @@ -23,11 +23,16 @@ from sugar_network.db import directory as directory_ from sugar_network.db.directory import Directory from sugar_network.db.index import IndexWriter from sugar_network.toolkit.router import ACL +from sugar_network.toolkit.coroutine import this from sugar_network.toolkit import http, Sequence class ResourceTest(tests.Test): + def setUp(self, fork_num=0): + tests.Test.setUp(self, fork_num) + this.broadcast = lambda x: x + def test_ActiveProperty_Slotted(self): class Document(db.Resource): @@ -345,31 +350,31 @@ class ResourceTest(tests.Test): return value directory = Directory(tests.tmpdir, Document, IndexWriter) + guid = directory.create({'guid': '1', 'prop1': '1', 'prop2': '2'}) + doc = directory.get(guid) - self.assertRaises(http.NotFound, directory.patch, 'absent', {}) - - directory.create({'guid': '1', 'prop1': '1', 'prop2': '2'}) - self.assertEqual({}, directory.patch('1', {})) - self.assertEqual({}, directory.patch('1', {'prop1': '1', 'prop2': '2'})) - self.assertEqual({'prop1': '1_'}, directory.patch('1', {'prop1': '1_', 'prop2': '2'})) - self.assertEqual({'prop1': '1_', 'prop2': '2_'}, directory.patch('1', {'prop1': '1_', 'prop2': '2_'})) + self.assertEqual({}, doc.patch({})) + self.assertEqual({}, doc.patch({'prop1': '1', 'prop2': '2'})) + self.assertEqual({'prop1': '1_'}, doc.patch({'prop1': '1_', 'prop2': '2'})) + self.assertEqual({'prop1': '1_', 'prop2': '2_'}, doc.patch({'prop1': '1_', 'prop2': '2_'})) def test_patch_LocalizedProps(self): class Document(db.Resource): - @db.indexed_property(slot=1, localized=True) + @db.indexed_property(db.Localized, slot=1) def prop(self, value): return value directory = Directory(tests.tmpdir, Document, IndexWriter) + guid = directory.create({'guid': '1', 'prop': {'ru': 'ru'}}) + doc = directory.get(guid) - directory.create({'guid': '1', 'prop': {'ru': 'ru'}}) - self.assertEqual({}, directory.patch('1', {'prop': 'ru'})) - self.assertEqual({'prop': {'ru': 'ru_'}}, directory.patch('1', {'prop': {'ru': 'ru_'}})) - self.assertEqual({'prop': {'en': 'en'}}, directory.patch('1', {'prop': {'en': 'en'}})) - self.assertEqual({'prop': {'ru': 'ru', 'en': 'en'}}, directory.patch('1', {'prop': {'ru': 'ru', 'en': 'en'}})) - self.assertEqual({'prop': {'ru': 'ru_', 'en': 'en'}}, directory.patch('1', {'prop': {'ru': 'ru_', 'en': 'en'}})) + self.assertEqual({}, doc.patch({'prop': {'ru': 'ru'}})) + self.assertEqual({'prop': {'ru': 'ru_'}}, doc.patch({'prop': {'ru': 'ru_'}})) + self.assertEqual({'prop': {'en': 'en'}}, doc.patch({'prop': {'en': 'en'}})) + self.assertEqual({'prop': {'ru': 'ru', 'en': 'en'}}, doc.patch({'prop': {'ru': 'ru', 'en': 'en'}})) + self.assertEqual({'prop': {'ru': 'ru_', 'en': 'en'}}, doc.patch({'prop': {'ru': 'ru_', 'en': 'en'}})) def test_diff(self): @@ -379,21 +384,13 @@ class ResourceTest(tests.Test): def prop(self, value): return value - @db.blob_property() - def blob(self, value): - return value - directory = Directory(tests.tmpdir, Document, IndexWriter) - self.touch(('blob', '1')) directory.create({'guid': '1', 'prop': '1', 'ctime': 1, 'mtime': 1}) - directory.update('1', {'blob': {'blob': 'blob'}}) for i in os.listdir('1/1'): os.utime('1/1/%s' % i, (1, 1)) - self.touch(('blob', '2')) directory.create({'guid': '2', 'prop': '2', 'ctime': 2, 'mtime': 2}) - directory.update('2', {'blob': {'blob': 'blob'}}) for i in os.listdir('2/2'): os.utime('2/2/%s' % i, (2, 2)) @@ -408,22 +405,12 @@ class ResourceTest(tests.Test): 'ctime': {'value': 1, 'mtime': 1}, 'prop': {'value': '1', 'mtime': 1}, 'mtime': {'value': 1, 'mtime': 1}, - 'blob': { - 'mtime': 1, - 'blob': tests.tmpdir + '/1/1/blob.blob', - 'blob_size': 1, - }, }}, {'guid': '2', 'diff': { 'guid': {'value': '2', 'mtime': 2}, 'ctime': {'value': 2, 'mtime': 2}, 'prop': {'value': '2', 'mtime': 2}, 'mtime': {'value': 2, 'mtime': 2}, - 'blob': { - 'mtime': 2, - 'blob': tests.tmpdir + '/2/2/blob.blob', - 'blob_size': 1, - }, }}, {'guid': '3', 'diff': { 'guid': {'value': '3', 'mtime': 3}, @@ -433,7 +420,7 @@ class ResourceTest(tests.Test): }}, ], [i for i in diff(directory, [[0, None]], out_seq)]) - self.assertEqual([[1, 5]], out_seq) + self.assertEqual([[1, 3]], out_seq) out_seq = Sequence() self.assertEqual([ @@ -442,26 +429,15 @@ class ResourceTest(tests.Test): 'ctime': {'value': 2, 'mtime': 2}, 'prop': {'value': '2', 'mtime': 2}, 'mtime': {'value': 2, 'mtime': 2}, - 'blob': { - 'mtime': 2, - 'blob': tests.tmpdir + '/2/2/blob.blob', - 'blob_size': 1, - }, }}, ], - [i for i in diff(directory, [[3, 4]], out_seq)]) - self.assertEqual([[3, 4]], out_seq) - - out_seq = Sequence() - self.assertEqual([ - ], - [i for i in diff(directory, [[3, 3]], out_seq)]) - self.assertEqual([], out_seq) + [i for i in diff(directory, [[2, 2]], out_seq)]) + self.assertEqual([[2, 2]], out_seq) out_seq = Sequence() self.assertEqual([ ], - [i for i in diff(directory, [[6, 100]], out_seq)]) + [i for i in diff(directory, [[4, 100]], out_seq)]) self.assertEqual([], out_seq) directory.update('2', {'prop': '22'}) self.assertEqual([ @@ -469,8 +445,8 @@ class ResourceTest(tests.Test): 'prop': {'value': '22', 'mtime': int(os.stat('2/2/prop').st_mtime)}, }}, ], - [i for i in diff(directory, [[6, 100]], out_seq)]) - self.assertEqual([[6, 6]], out_seq) + [i for i in diff(directory, [[4, 100]], out_seq)]) + self.assertEqual([[4, 4]], out_seq) def test_diff_IgnoreCalcProps(self): @@ -535,37 +511,6 @@ class ResourceTest(tests.Test): self.assertEqual([[1, 1], [4, 4]], out_seq) - def test_diff_WithBlobsSetByUrl(self): - URL = 'http://src.sugarlabs.org/robots.txt' - URL_content = urllib2.urlopen(URL).read() - - class Document(db.Resource): - - @db.blob_property() - def blob(self, value): - return value - - directory = Directory(tests.tmpdir, Document, IndexWriter) - - directory.create({'guid': '1', 'ctime': 1, 'mtime': 1}) - directory.update('1', {'blob': {'url': URL}}) - self.utime('1/1', 1) - - out_seq = Sequence() - self.assertEqual([ - {'guid': '1', 'diff': { - 'guid': {'value': '1', 'mtime': 1}, - 'ctime': {'value': 1, 'mtime': 1}, - 'mtime': {'value': 1, 'mtime': 1}, - 'blob': { - 'url': URL, - 'mtime': 1, - }, - }}, - ], - [i for i in diff(directory, [[0, None]], out_seq)]) - self.assertEqual([[1, 2]], out_seq) - def test_diff_Filter(self): class Document(db.Resource): @@ -626,7 +571,7 @@ class ResourceTest(tests.Test): class Document(db.Resource): - @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType()) + @db.stored_property(db.Aggregated) def prop(self, value): return value @@ -768,21 +713,13 @@ class ResourceTest(tests.Test): def prop(self, value): return value - @db.blob_property() - def blob(self, value): - return value - directory1 = Directory('document1', Document, IndexWriter) directory1.create({'guid': '1', 'prop': '1', 'ctime': 1, 'mtime': 1}) - self.touch(('blob', '1')) - directory1.update('1', {'blob': {'blob': 'blob'}}) 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}) - self.touch(('blob', '2')) - directory1.update('2', {'blob': {'blob': 'blob'}}) for i in os.listdir('document1/2/2'): os.utime('document1/2/2/%s' % i, (2, 2)) @@ -808,7 +745,6 @@ class ResourceTest(tests.Test): 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')) @@ -816,7 +752,6 @@ class ResourceTest(tests.Test): 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')) @@ -824,28 +759,25 @@ class ResourceTest(tests.Test): 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(db.Resource): - @db.blob_property() - def blob(self, value): + @db.stored_property(default='') + def prop(self, value): return value directory1 = Directory('document1', Document, IndexWriter) directory2 = Directory('document2', Document, IndexWriter) directory1.create({'guid': 'guid', 'ctime': 1, 'mtime': 1}) - self.touch(('blob', '1')) - directory1.update('guid', {'blob': {'blob': 'blob'}}) + directory1.update('guid', {'prop': '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}) - self.touch(('blob', '2')) - directory2.update('guid', {'blob': {'blob': 'blob'}}) + directory2.update('guid', {'prop': '2'}) for i in os.listdir('document2/gu/guid'): os.utime('document2/gu/guid/%s' % i, (2, 2)) @@ -858,8 +790,8 @@ class ResourceTest(tests.Test): 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()) + self.assertEqual(2, doc.meta('prop')['mtime']) + self.assertEqual('2', doc.meta('prop')['value']) for patch in diff(directory1, [[0, None]], Sequence()): directory2.merge(**patch) @@ -872,8 +804,8 @@ class ResourceTest(tests.Test): 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()) + self.assertEqual(2, doc.meta('prop')['mtime']) + self.assertEqual('2', doc.meta('prop')['value']) os.utime('document1/gu/guid/mtime', (3, 3)) for patch in diff(directory1, [[0, None]], Sequence()): @@ -887,10 +819,10 @@ class ResourceTest(tests.Test): 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()) + self.assertEqual(2, doc.meta('prop')['mtime']) + self.assertEqual('2', doc.meta('prop')['value']) - os.utime('document1/gu/guid/blob', (4, 4)) + os.utime('document1/gu/guid/prop', (4, 4)) for patch in diff(directory1, [[0, None]], Sequence()): directory2.merge(**patch) @@ -902,132 +834,14 @@ class ResourceTest(tests.Test): 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(db.Resource): - - @db.indexed_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 patch in diff(directory1, [[0, None]], Sequence()): - directory2.merge(shift_seqno=False, **patch) - self.assertEqual( - [(1, 1, '1', '1')], - [(i['ctime'], i['mtime'], i['guid'], i['prop']) for i in directory2.find()[0]]) - doc = directory2.get('1') - self.assertEqual(0, doc.get('seqno')) - self.assertEqual(0, doc.meta('guid')['seqno']) - self.assertEqual(0, doc.meta('prop')['seqno']) - - directory3 = Directory('document3', Document, IndexWriter) - for patch in diff(directory1, [[0, None]], Sequence()): - directory3.merge(**patch) - self.assertEqual( - [(1, 1, '1', '1')], - [(i['ctime'], i['mtime'], i['guid'], i['prop']) for i in directory3.find()[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('1', {'prop': '2', 'ctime': 2, 'mtime': 2}) - - for patch in diff(directory1, [[0, None]], Sequence()): - directory3.merge(shift_seqno=False, **patch) - self.assertEqual( - [(2, 2, '1', '2')], - [(i['ctime'], i['mtime'], i['guid'], i['prop']) for i in directory3.find()[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('1', {'prop': '3', 'ctime': 3, 'mtime': 3}) - - for patch in diff(directory1, [[0, None]], Sequence()): - directory3.merge(**patch) - self.assertEqual( - [(3, 3, '1', '3')], - [(i['ctime'], i['mtime'], i['guid'], i['prop']) for i in directory3.find()[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(db.Resource): - - @db.blob_property() - 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 patch in diff(directory1, [[0, None]], Sequence()): - directory2.merge(**patch) - - 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(db.Resource): - - @db.blob_property() - def blob(self, value): - return value - - directory = Directory('document', Document, IndexWriter) - self.touch(('blob', 'blob-1')) - directory.merge('1', { - 'guid': {'mtime': 1, 'value': '1'}, - 'ctime': {'mtime': 2, 'value': 2}, - 'mtime': {'mtime': 3, 'value': 3}, - 'blob': {'mtime': 4, 'blob': 'blob'}, - }) - - self.assertEqual( - [(2, 3, '1')], - [(i['ctime'], i['mtime'], i['guid']) for i in directory.find()[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()) - - self.touch(('blob', 'blob-2')) - directory.merge('1', { - 'blob': {'mtime': 5, 'blob': 'blob'}, - }) - - self.assertEqual(5, doc.meta('blob')['mtime']) - self.assertEqual('blob-2', file('document/1/1/blob.blob').read()) + self.assertEqual(4, doc.meta('prop')['mtime']) + self.assertEqual('1', doc.meta('prop')['value']) def test_merge_Aggprops(self): class Document(db.Resource): - @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType()) + @db.stored_property(db.Aggregated) def prop(self, value): return value @@ -1079,6 +893,28 @@ class ResourceTest(tests.Test): }, directory.get('1')['prop']) + def test_merge_CallSetters(self): + + class Document(db.Resource): + + @db.stored_property(db.Numeric) + def prop(self, value): + return value + + @prop.setter + def prop(self, value): + return value + 1 + + directory = Directory('document', Document, IndexWriter) + + directory.merge('1', { + 'guid': {'mtime': 1, 'value': '1'}, + 'ctime': {'mtime': 1, 'value': 1}, + 'mtime': {'mtime': 1, 'value': 1}, + 'prop': {'mtime': 1, 'value': 1}, + }) + self.assertEqual(2, directory.get('1')['prop']) + def test_wipe(self): class Document(db.Resource): @@ -1088,31 +924,11 @@ class ResourceTest(tests.Test): guid = directory.create({'prop': '1'}) self.assertEqual([guid], [i.guid for i in directory.find()[0]]) directory.commit() - assert directory.mtime != 0 + assert exists('index/mtime') directory.wipe() self.assertEqual([], [i.guid for i in directory.find()[0]]) - assert directory.mtime == 0 - - def test_DeleteOldBlobOnUpdate(self): - - class Document(db.Resource): - - @db.blob_property() - def blob(self, value): - return value - - directory = Directory(tests.tmpdir, Document, IndexWriter) - - directory.create({'guid': 'guid', 'blob': 'foo'}) - assert exists('gu/guid/blob.blob') - directory.update('guid', {'blob': {'url': 'foo'}}) - assert not exists('gu/guid/blob.blob') - - directory.update('guid', {'blob': 'foo'}) - assert exists('gu/guid/blob.blob') - directory.update('guid', {'blob': {}}) - assert not exists('gu/guid/blob.blob') + assert not exists('index/mtime') def diff(directory, in_seq, out_seq, exclude_seq=None, **kwargs): diff --git a/tests/units/db/routes.py b/tests/units/db/routes.py index 5908d0f..8824ca8 100755 --- a/tests/units/db/routes.py +++ b/tests/units/db/routes.py @@ -16,10 +16,11 @@ src_root = abspath(dirname(__file__)) from __init__ import tests from sugar_network import db, toolkit -from sugar_network.db.routes import _typecast_prop_value -from sugar_network.db.metadata import Property -from sugar_network.toolkit.router import Router, Request, Response, fallbackroute, Blob, ACL -from sugar_network.toolkit import coroutine, http +from sugar_network.db import files +from sugar_network.model.user import User +from sugar_network.toolkit.router import Router, Request, Response, fallbackroute, ACL +from sugar_network.toolkit.coroutine import this +from sugar_network.toolkit import coroutine, http, i18n class RoutesTest(tests.Test): @@ -36,18 +37,19 @@ class RoutesTest(tests.Test): def wo_default(self, value): return value - @db.indexed_property(slot=1, default='not_stored_default') + @db.stored_property(default='not_stored_default') def not_stored_default(self, value): return value - self.volume = db.Volume(tests.tmpdir, [Document], lambda event: None) + volume = db.Volume(tests.tmpdir, [Document]) + router = Router(db.Routes(volume)) - self.assertRaises(RuntimeError, self.call, 'POST', ['document'], content={}) + self.assertRaises(RuntimeError, this.call, method='POST', path=['document'], content={}) - guid = self.call('POST', ['document'], content={'wo_default': 'wo_default'}) - self.assertEqual('default', self.call('GET', ['document', guid, 'w_default'])) - self.assertEqual('wo_default', self.call('GET', ['document', guid, 'wo_default'])) - self.assertEqual('not_stored_default', self.call('GET', ['document', guid, 'not_stored_default'])) + guid = this.call(method='POST', path=['document'], content={'wo_default': 'wo_default'}) + self.assertEqual('default', this.call(method='GET', path=['document', guid, 'w_default'])) + self.assertEqual('wo_default', this.call(method='GET', path=['document', guid, 'wo_default'])) + self.assertEqual('not_stored_default', this.call(method='GET', path=['document', guid, 'not_stored_default'])) def test_Populate(self): self.touch( @@ -65,10 +67,10 @@ class RoutesTest(tests.Test): class Document(db.Resource): pass - with db.Volume(tests.tmpdir, [Document], lambda event: None) as volume: - for cls in volume.values(): - for __ in cls.populate(): - pass + with db.Volume(tests.tmpdir, [Document]) as volume: + router = Router(db.Routes(volume)) + for __ in volume['document'].populate(): + pass self.assertEqual( sorted(['1', '2']), sorted([i.guid for i in volume['document'].find()[0]])) @@ -78,10 +80,10 @@ class RoutesTest(tests.Test): class Document(db.Resource): pass - with db.Volume(tests.tmpdir, [Document], lambda event: None) as volume: - for cls in volume.values(): - for __ in cls.populate(): - pass + with db.Volume(tests.tmpdir, [Document]) as volume: + router = Router(db.Routes(volume)) + for __ in volume['document'].populate(): + pass self.assertEqual( sorted(['1', '2']), sorted([i.guid for i in volume['document'].find()[0]])) @@ -94,12 +96,14 @@ class RoutesTest(tests.Test): def prop(self, value): return value - @db.indexed_property(prefix='L', localized=True, default='') + @db.indexed_property(db.Localized, prefix='L', default={}) def localized_prop(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - self.volume['testdocument'].create({'guid': 'guid'}) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + + volume['testdocument'].create({'guid': 'guid'}) self.assertEqual({ 'total': 1, @@ -107,11 +111,11 @@ class RoutesTest(tests.Test): {'guid': 'guid', 'prop': ''}, ], }, - self.call('GET', path=['testdocument'], reply=['guid', 'prop'])) + this.call(method='GET', path=['testdocument'], reply=['guid', 'prop'])) - guid_1 = self.call('POST', path=['testdocument'], content={'prop': 'value_1'}) + guid_1 = this.call(method='POST', path=['testdocument'], content={'prop': 'value_1'}) assert guid_1 - guid_2 = self.call('POST', path=['testdocument'], content={'prop': 'value_2'}) + guid_2 = this.call(method='POST', path=['testdocument'], content={'prop': 'value_2'}) assert guid_2 self.assertEqual( @@ -120,9 +124,9 @@ class RoutesTest(tests.Test): {'guid': guid_1, 'prop': 'value_1'}, {'guid': guid_2, 'prop': 'value_2'}, ]), - sorted(self.call('GET', path=['testdocument'], reply=['guid', 'prop'])['result'])) + sorted(this.call(method='GET', path=['testdocument'], reply=['guid', 'prop'])['result'])) - self.call('PUT', path=['testdocument', guid_1], content={'prop': 'value_3'}) + this.call(method='PUT', path=['testdocument', guid_1], content={'prop': 'value_3'}) self.assertEqual( sorted([ @@ -130,240 +134,397 @@ class RoutesTest(tests.Test): {'guid': guid_1, 'prop': 'value_3'}, {'guid': guid_2, 'prop': 'value_2'}, ]), - sorted(self.call('GET', path=['testdocument'], reply=['guid', 'prop'])['result'])) + sorted(this.call(method='GET', path=['testdocument'], reply=['guid', 'prop'])['result'])) - self.call('DELETE', path=['testdocument', guid_2]) + this.call(method='DELETE', path=['testdocument', guid_2]) self.assertEqual( sorted([ {'guid': 'guid', 'prop': ''}, {'guid': guid_1, 'prop': 'value_3'}, ]), - sorted(self.call('GET', path=['testdocument'], reply=['guid', 'prop'])['result'])) + sorted(this.call(method='GET', path=['testdocument'], reply=['guid', 'prop'])['result'])) - self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid_2]) + self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid_2]) self.assertEqual( {'guid': guid_1, 'prop': 'value_3'}, - self.call('GET', path=['testdocument', guid_1], reply=['guid', 'prop'])) + this.call(method='GET', path=['testdocument', guid_1], reply=['guid', 'prop'])) self.assertEqual( 'value_3', - self.call('GET', path=['testdocument', guid_1, 'prop'])) + this.call(method='GET', path=['testdocument', guid_1, 'prop'])) def test_SetBLOBs(self): class TestDocument(db.Resource): - @db.blob_property() + @db.stored_property(db.Blob) def blob(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={}) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) - self.call('PUT', path=['testdocument', guid, 'blob'], content='blob1') - self.assertEqual('blob1', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read()) + guid = this.call(method='POST', path=['testdocument'], content={}) + self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob']) - self.call('PUT', path=['testdocument', guid, 'blob'], content_stream=StringIO('blob2')) - self.assertEqual('blob2', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read()) + this.call(method='PUT', path=['testdocument', guid, 'blob'], content='blob1') + self.assertEqual('blob1', file(this.call(method='GET', path=['testdocument', guid, 'blob']).path).read()) - self.call('PUT', path=['testdocument', guid, 'blob'], content=None) - self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob']) + this.call(method='PUT', path=['testdocument', guid, 'blob'], content_stream=StringIO('blob2')) + self.assertEqual('blob2', file(this.call(method='GET', path=['testdocument', guid, 'blob']).path).read()) - def test_SetBLOBsByMeta(self): + this.call(method='PUT', path=['testdocument', guid, 'blob'], content=None) + self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob']) + + def test_CreateBLOBsWithMeta(self): class TestDocument(db.Resource): - @db.blob_property(mime_type='default') + @db.stored_property(db.Blob) def blob(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={}) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + guid = this.call(method='POST', path=['testdocument'], content={}) - self.assertRaises(RuntimeError, self.call, 'PUT', path=['testdocument', guid, 'blob'], + self.assertRaises(http.BadRequest, this.call, method='PUT', path=['testdocument', guid, 'blob'], content={}, content_type='application/json') - self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob']) + self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob']) + + self.assertRaises(http.BadRequest, this.call, method='PUT', path=['testdocument', guid, 'blob'], + content={'url': 'foo'}, content_type='application/json') + self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob']) + + this.call(method='PUT', path=['testdocument', guid, 'blob'], + content={'url': 'url', 'digest': 'digest', 'foo': 'bar'}, content_type='application/json') + self.assertEqual({ + 'mime_type': 'application/octet-stream', + 'url': 'url', + 'foo': 'bar', + }, + this.call(method='GET', path=['testdocument', guid, 'blob'])) + + def test_UpdateUrlBLOBsWithMeta(self): + + class TestDocument(db.Resource): + + @db.stored_property(db.Blob) + def blob(self, value): + return value + + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + + guid = this.call(method='POST', path=['testdocument'], content={'blob': {'digest': 'digest', 'url': 'url'}}) + self.assertEqual({ + 'mime_type': 'application/octet-stream', + 'url': 'url', + }, + this.call(method='GET', path=['testdocument', guid, 'blob'])) + + self.assertRaises(http.BadRequest, this.call, method='PUT', path=['testdocument', guid, 'blob'], + content={'digest': 'fake'}, content_type='application/json') + self.assertEqual({ + 'mime_type': 'application/octet-stream', + 'url': 'url', + }, + this.call(method='GET', path=['testdocument', guid, 'blob'])) + + this.call(method='PUT', path=['testdocument', guid, 'blob'], + content={'foo': 'bar'}, content_type='application/json') + self.assertEqual({ + 'mime_type': 'application/octet-stream', + 'url': 'url', + 'foo': 'bar', + }, + this.call(method='GET', path=['testdocument', guid, 'blob'])) + + def test_UpdateFileBLOBsWithMeta(self): + + class TestDocument(db.Resource): + + @db.stored_property(db.Blob) + def blob(self, value): + return value + + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + + guid = this.call(method='POST', path=['testdocument'], content={'blob': 'blob'}) + blob = this.call(method='GET', path=['testdocument', guid, 'blob'], environ={'HTTP_HOST': 'localhost'}) + self.assertEqual({ + 'mime_type': 'application/octet-stream', + 'size': os.stat(blob.path).st_size, + 'mtime': int(os.stat(blob.path).st_mtime), + 'url': 'http://localhost/blobs/%s' % hash('blob'), + 'digest': str(hash('blob')), + }, + blob) + self.assertEqual('blob', file(blob.path).read()) + + self.assertRaises(http.BadRequest, this.call, method='PUT', path=['testdocument', guid, 'blob'], + content={'digest': 'fake'}, content_type='application/json') + blob = this.call(method='GET', path=['testdocument', guid, 'blob'], environ={'HTTP_HOST': 'localhost'}) + self.assertEqual({ + 'mime_type': 'application/octet-stream', + 'size': os.stat(blob.path).st_size, + 'mtime': int(os.stat(blob.path).st_mtime), + 'digest': str(hash('blob')), + 'url': 'http://localhost/blobs/%s' % hash('blob'), + }, + blob) + self.assertEqual('blob', file(blob.path).read()) + + this.call(method='PUT', path=['testdocument', guid, 'blob'], + content={'foo': 'bar'}, content_type='application/json') + blob = this.call(method='GET', path=['testdocument', guid, 'blob'], environ={'HTTP_HOST': 'localhost'}) + self.assertEqual({ + 'mime_type': 'application/octet-stream', + 'size': os.stat(blob.path).st_size, + 'mtime': int(os.stat(blob.path).st_mtime), + 'digest': str(hash('blob')), + 'url': 'http://localhost/blobs/%s' % hash('blob'), + 'foo': 'bar', + }, + blob) + self.assertEqual('blob', file(blob.path).read()) + + def test_SwitchBLOBsType(self): + + class TestDocument(db.Resource): + + @db.stored_property(db.Blob) + def blob(self, value): + return value + + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) - self.call('PUT', path=['testdocument', guid, 'blob'], - content={'url': 'foo', 'bar': 'probe'}, content_type='application/json') - blob = self.call('GET', path=['testdocument', guid, 'blob']) - self.assertEqual('foo', blob['url']) + guid = this.call(method='POST', path=['testdocument'], content={'blob': 'blob'}) + this.call(method='PUT', path=['testdocument', guid, 'blob'], + content={'foo': 'bar'}, content_type='application/json') + + file_blob = this.call(method='GET', path=['testdocument', guid, 'blob'], environ={'HTTP_HOST': 'localhost'}) + self.assertEqual({ + 'mime_type': 'application/octet-stream', + 'size': os.stat(file_blob.path).st_size, + 'mtime': int(os.stat(file_blob.path).st_mtime), + 'digest': str(hash('blob')), + 'url': 'http://localhost/blobs/%s' % hash('blob'), + 'foo': 'bar', + }, file_blob) + self.assertEqual('blob', file(file_blob.path).read()) + + this.call(method='PUT', path=['testdocument', guid, 'blob'], + content={'url': 'url'}, content_type='application/json') + self.assertEqual({ + 'mime_type': 'application/octet-stream', + 'url': 'url', + 'foo': 'bar', + }, this.call(method='GET', path=['testdocument', guid, 'blob'])) + assert not exists(file_blob.path) + + this.call(method='PUT', path=['testdocument', guid, 'blob'], + content='blob', content_type='application/octet-stream', environ={'HTTP_HOST': 'localhost'}) + self.assertEqual({ + 'mime_type': 'application/octet-stream', + 'size': os.stat(file_blob.path).st_size, + 'mtime': int(os.stat(file_blob.path).st_mtime), + 'digest': str(hash('blob')), + 'url': 'http://localhost/blobs/%s' % hash('blob'), + }, this.call(method='GET', path=['testdocument', guid, 'blob'], environ={'HTTP_HOST': 'localhost'})) + self.assertEqual('blob', file(file_blob.path).read()) def test_RemoveBLOBs(self): class TestDocument(db.Resource): - @db.blob_property(mime_type='default') + @db.stored_property(db.Blob) def blob(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={'blob': 'blob'}) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + guid = this.call(method='POST', path=['testdocument'], content={'blob': 'blob'}) - self.assertEqual('blob', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read()) + self.assertEqual('blob', file(this.call(method='GET', path=['testdocument', guid, 'blob']).path).read()) - self.call('PUT', path=['testdocument', guid, 'blob']) - self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob']) + this.call(method='PUT', path=['testdocument', guid, 'blob']) + self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob']) - def test_RemoveTempBLOBFilesOnFails(self): + def test_ReuploadBLOBs(self): class TestDocument(db.Resource): - @db.blob_property(mime_type='default') + @db.stored_property(db.Blob) + def blob(self, value): + return value + + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + guid = this.call(method='POST', path=['testdocument'], content={'blob': 'blob1'}) + + blob1 = this.call(method='GET', path=['testdocument', guid, 'blob']) + self.assertEqual('blob1', file(blob1.path).read()) + + this.call(method='PUT', path=['testdocument', guid, 'blob'], content='blob2') + blob2 = this.call(method='GET', path=['testdocument', guid, 'blob']) + self.assertEqual('blob2', file(blob2.path).read()) + assert blob1.path != blob2.path + assert not exists(blob1.path) + + def test_RemoveBLOBsOnFailedSetter(self): + + class TestDocument(db.Resource): + + @db.stored_property(db.Blob) def blob(self, value): return value @blob.setter def blob(self, value): - raise RuntimeError() + if value: + raise RuntimeError() + return value + + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={}) + guid = this.call(method='POST', path=['testdocument'], content={}) + self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob']) - self.assertRaises(RuntimeError, self.call, 'PUT', path=['testdocument', guid, 'blob'], content='probe') - self.assertEqual(0, len(os.listdir('tmp'))) + self.assertRaises(RuntimeError, this.call, method='PUT', path=['testdocument', guid, 'blob'], content='probe') + self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob']) + assert not exists('blobs/%s' % hash('probe')) def test_SetBLOBsWithMimeType(self): class TestDocument(db.Resource): - @db.blob_property(mime_type='default') + @db.stored_property(db.Blob, mime_type='default') def blob(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={}) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + guid = this.call(method='POST', path=['testdocument'], content={}) - self.call('PUT', path=['testdocument', guid, 'blob'], content='blob1') - self.assertEqual('default', self.call('GET', path=['testdocument', guid, 'blob'])['mime_type']) - self.assertEqual('default', self.response.content_type) + response = Response() + this.call(response=response, + method='PUT', path=['testdocument', guid, 'blob'], content='blob1') + response = Response() + self.assertEqual('default', this.call(response=response, + method='GET', path=['testdocument', guid, 'blob'])['mime_type']) + self.assertEqual('default', response.content_type) - self.call('PUT', path=['testdocument', guid, 'blob'], content='blob1', content_type='foo') - self.assertEqual('foo', self.call('GET', path=['testdocument', guid, 'blob'])['mime_type']) - self.assertEqual('foo', self.response.content_type) + response = Response() + this.call(response=response, + method='PUT', path=['testdocument', guid, 'blob'], content='blob1', content_type='foo') + response = Response() + self.assertEqual('foo', this.call(response=response, + method='GET', path=['testdocument', guid, 'blob'])['mime_type']) + self.assertEqual('foo', response.content_type) def test_GetBLOBs(self): class TestDocument(db.Resource): - @db.blob_property() + @db.stored_property(db.Blob) def blob(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={}) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + + guid = this.call(method='POST', path=['testdocument'], content={}) blob = 'blob' - self.call('PUT', path=['testdocument', guid, 'blob'], content=blob) - - blob_path = tests.tmpdir + '/testdocument/%s/%s/blob' % (guid[:2], guid) - blob_meta = { - 'seqno': 2, - 'blob': blob_path + '.blob', - 'blob_size': len(blob), - 'digest': hashlib.sha1(blob).hexdigest(), - 'mime_type': 'application/octet-stream', - 'mtime': int(os.stat(blob_path).st_mtime), - } + this.call(method='PUT', path=['testdocument', guid, 'blob'], content=blob) + digest = str(hash(blob)) + blob_path = 'blobs/%s' % digest - self.assertEqual('blob', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read()) + self.assertEqual('blob', file(this.call(method='GET', path=['testdocument', guid, 'blob']).path).read()) self.assertEqual({ 'blob': { - 'url': 'http://localhost/testdocument/%s/blob' % guid, - 'blob_size': len(blob), - 'digest': hashlib.sha1(blob).hexdigest(), 'mime_type': u'application/octet-stream', + 'url': 'http://localhost/blobs/%s' % digest, + 'size': len(blob), + 'digest': digest, + 'mtime': int(os.stat(blob_path).st_mtime), }, }, - self.call('GET', path=['testdocument', guid], reply=['blob'], host='localhost')) + this.call(method='GET', path=['testdocument', guid], reply=['blob'], environ={'HTTP_HOST': 'localhost'})) self.assertEqual([{ 'blob': { - 'url': 'http://localhost/testdocument/%s/blob' % guid, - 'blob_size': len(blob), - 'digest': hashlib.sha1(blob).hexdigest(), 'mime_type': u'application/octet-stream', + 'url': 'http://localhost/blobs/%s' % digest, + 'size': len(blob), + 'digest': digest, + 'mtime': int(os.stat(blob_path).st_mtime), }, }], - self.call('GET', path=['testdocument'], reply=['blob'], host='localhost')['result']) + this.call(method='GET', path=['testdocument'], reply=['blob'], environ={'HTTP_HOST': 'localhost'})['result']) def test_GetBLOBsByUrls(self): class TestDocument(db.Resource): - @db.blob_property() + @db.stored_property(db.Blob) def blob(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid1 = self.call('POST', path=['testdocument'], content={}) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + guid1 = this.call(method='POST', path=['testdocument'], content={}) - self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid1, 'blob']) + self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid1, 'blob']) self.assertEqual( - {'blob': {'url': 'http://127.0.0.1/testdocument/%s/blob' % guid1}}, - self.call('GET', path=['testdocument', guid1], reply=['blob'], host='127.0.0.1')) + {'blob': {}}, + this.call(method='GET', path=['testdocument', guid1], reply=['blob'], environ={'HTTP_HOST': '127.0.0.1'})) blob = 'file' - guid2 = self.call('POST', path=['testdocument'], content={'blob': blob}) - self.assertEqual('file', file(self.call('GET', path=['testdocument', guid2, 'blob'])['blob']).read()) - self.assertEqual({ - 'blob': { - 'url': 'http://127.0.0.1/testdocument/%s/blob' % guid2, - 'blob_size': len(blob), - 'digest': hashlib.sha1(blob).hexdigest(), - 'mime_type': u'application/octet-stream', - }, - }, - self.call('GET', path=['testdocument', guid2], reply=['blob'], host='127.0.0.1')) + guid2 = this.call(method='POST', path=['testdocument'], content={'blob': blob}) + self.assertEqual( + 'http://127.0.0.1/blobs/%s' % hash(blob), + this.call(method='GET', path=['testdocument', guid2], reply=['blob'], environ={'HTTP_HOST': '127.0.0.1'})['blob']['url']) - guid3 = self.call('POST', path=['testdocument'], content={'blob': {'url': 'http://foo'}}, content_type='application/json') - self.assertEqual('http://foo', self.call('GET', path=['testdocument', guid3, 'blob'])['url']) - self.assertEqual({ - 'blob': { - 'url': 'http://foo', - }, - }, - self.call('GET', path=['testdocument', guid3], reply=['blob'], host='127.0.0.1')) + guid3 = this.call(method='POST', path=['testdocument'], content={'blob': {'url': 'http://foo', 'digest': 'digest'}}, content_type='application/json') + self.assertEqual( + 'http://foo', + this.call(method='GET', path=['testdocument', guid3, 'blob'])['url']) + self.assertEqual( + 'http://foo', + this.call(method='GET', path=['testdocument', guid3], reply=['blob'], environ={'HTTP_HOST': '127.0.0.1'})['blob']['url']) self.assertEqual( sorted([ - {'blob': { - 'url': 'http://127.0.0.1/testdocument/%s/blob' % guid1, - }}, - { 'blob': { - 'url': 'http://127.0.0.1/testdocument/%s/blob' % guid2, - 'blob_size': len(blob), - 'digest': hashlib.sha1(blob).hexdigest(), - 'mime_type': u'application/octet-stream', - }}, - { 'blob': { - 'url': 'http://foo', - }}, + None, + 'http://127.0.0.1/blobs/%s' % hash(blob), + 'http://foo', ]), - sorted(self.call('GET', path=['testdocument'], reply=['blob'], host='127.0.0.1')['result'])) + sorted([i['blob'].get('url') for i in this.call(method='GET', path=['testdocument'], reply=['blob'], + environ={'HTTP_HOST': '127.0.0.1'})['result']])) def test_CommandsGetAbsentBlobs(self): class TestDocument(db.Resource): - @db.indexed_property(slot=1, default='') - def prop(self, value): - return value - - @db.blob_property() + @db.stored_property(db.Blob) def blob(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) - guid = self.call('POST', path=['testdocument'], content={'prop': 'value'}) - self.assertEqual('value', self.call('GET', path=['testdocument', guid, 'prop'])) - self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob']) + guid = this.call(method='POST', path=['testdocument'], content={}) + self.assertRaises(http.NotFound, this.call, method='GET', path=['testdocument', guid, 'blob']) self.assertEqual( - {'blob': {'url': 'http://localhost/testdocument/%s/blob' % guid}}, - self.call('GET', path=['testdocument', guid], reply=['blob'], host='localhost')) + {'blob': {}}, + this.call(method='GET', path=['testdocument', guid], reply=['blob'], environ={'HTTP_HOST': 'localhost'})) def test_Command_ReplyForGET(self): @@ -373,44 +534,46 @@ class RoutesTest(tests.Test): def prop(self, value): return value - @db.indexed_property(prefix='L', localized=True, default='') + @db.indexed_property(db.Localized, prefix='L', default={}) def localized_prop(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={'prop': 'value'}) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + guid = this.call(method='POST', path=['testdocument'], content={'prop': 'value'}) self.assertEqual( ['guid', 'prop'], - self.call('GET', path=['testdocument', guid], reply=['guid', 'prop']).keys()) + this.call(method='GET', path=['testdocument', guid], reply=['guid', 'prop']).keys()) self.assertEqual( ['guid'], - self.call('GET', path=['testdocument'])['result'][0].keys()) + this.call(method='GET', path=['testdocument'])['result'][0].keys()) self.assertEqual( sorted(['guid', 'prop']), - sorted(self.call('GET', path=['testdocument'], reply=['prop', 'guid'])['result'][0].keys())) + sorted(this.call(method='GET', path=['testdocument'], reply=['prop', 'guid'])['result'][0].keys())) self.assertEqual( sorted(['prop']), - sorted(self.call('GET', path=['testdocument'], reply=['prop'])['result'][0].keys())) + sorted(this.call(method='GET', path=['testdocument'], reply=['prop'])['result'][0].keys())) def test_DecodeBeforeSetting(self): class TestDocument(db.Resource): - @db.indexed_property(slot=1, typecast=int) + @db.indexed_property(db.Numeric, slot=1) def prop(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) - guid = self.call('POST', path=['testdocument'], content={'prop': '-1'}) - self.assertEqual(-1, self.call('GET', path=['testdocument', guid, 'prop'])) + guid = this.call(method='POST', path=['testdocument'], content={'prop': '-1'}) + self.assertEqual(-1, this.call(method='GET', path=['testdocument', guid, 'prop'])) def test_LocalizedSet(self): - toolkit._default_langs = ['en'] + i18n._default_langs = ['en'] class TestDocument(db.Resource): @@ -418,32 +581,23 @@ class RoutesTest(tests.Test): def prop(self, value): return value - @db.indexed_property(prefix='L', localized=True, default='') + @db.indexed_property(db.Localized, prefix='L', default={}) def localized_prop(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - directory = self.volume['testdocument'] - - guid = directory.create({'localized_prop': 'value_raw'}) - self.assertEqual({'en': 'value_raw'}, directory.get(guid)['localized_prop']) - self.assertEqual( - [guid], - [i.guid for i in directory.find(localized_prop='value_raw')[0]]) - - directory.update(guid, {'localized_prop': 'value_raw2'}) - self.assertEqual({'en': 'value_raw2'}, directory.get(guid)['localized_prop']) - self.assertEqual( - [guid], - [i.guid for i in directory.find(localized_prop='value_raw2')[0]]) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + directory = volume['testdocument'] + guid = this.call(method='POST', path=['testdocument'], content={'localized_prop': 'value_ru'}, + environ={'HTTP_ACCEPT_LANGUAGE': 'ru'}) - guid = self.call('POST', path=['testdocument'], accept_language=['ru'], content={'localized_prop': 'value_ru'}) self.assertEqual({'ru': 'value_ru'}, directory.get(guid)['localized_prop']) self.assertEqual( [guid], [i.guid for i in directory.find(localized_prop='value_ru')[0]]) - self.call('PUT', path=['testdocument', guid], accept_language=['en'], content={'localized_prop': 'value_en'}) + this.call(method='PUT', path=['testdocument', guid], content={'localized_prop': 'value_en'}, + environ={'HTTP_ACCEPT_LANGUAGE': 'en'}) self.assertEqual({'ru': 'value_ru', 'en': 'value_en'}, directory.get(guid)['localized_prop']) self.assertEqual( [guid], @@ -460,14 +614,15 @@ class RoutesTest(tests.Test): def prop(self, value): return value - @db.indexed_property(prefix='L', localized=True, default='') + @db.indexed_property(db.Localized, prefix='L', default={}) def localized_prop(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - directory = self.volume['testdocument'] + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + directory = volume['testdocument'] - guid = self.call('POST', path=['testdocument'], content={ + guid = this.call(method='POST', path=['testdocument'], content={ 'localized_prop': { 'ru': 'value_ru', 'es': 'value_es', @@ -475,63 +630,78 @@ class RoutesTest(tests.Test): }, }) - toolkit._default_langs = ['en'] + i18n._default_langs = ['en'] self.assertEqual( {'localized_prop': 'value_en'}, - self.call('GET', path=['testdocument', guid], reply=['localized_prop'])) + this.call(method='GET', path=['testdocument', guid], reply=['localized_prop'])) self.assertEqual( {'localized_prop': 'value_ru'}, - self.call('GET', path=['testdocument', guid], accept_language=['ru'], reply=['localized_prop'])) + this.call(method='GET', path=['testdocument', guid], reply=['localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'ru'})) self.assertEqual( 'value_ru', - self.call('GET', path=['testdocument', guid, 'localized_prop'], accept_language=['ru', 'es'])) + this.call(method='GET', path=['testdocument', guid, 'localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'ru,es'})) self.assertEqual( [{'localized_prop': 'value_ru'}], - self.call('GET', path=['testdocument'], accept_language=['foo', 'ru', 'es'], reply=['localized_prop'])['result']) + this.call(method='GET', path=['testdocument'], reply=['localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'foo,ru,es'})['result']) self.assertEqual( {'localized_prop': 'value_ru'}, - self.call('GET', path=['testdocument', guid], accept_language=['ru-RU'], reply=['localized_prop'])) + this.call(method='GET', path=['testdocument', guid], reply=['localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'ru-RU'})) self.assertEqual( 'value_ru', - self.call('GET', path=['testdocument', guid, 'localized_prop'], accept_language=['ru-RU', 'es'])) + this.call(method='GET', path=['testdocument', guid, 'localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'ru-RU,es'})) self.assertEqual( [{'localized_prop': 'value_ru'}], - self.call('GET', path=['testdocument'], accept_language=['foo', 'ru-RU', 'es'], reply=['localized_prop'])['result']) + this.call(method='GET', path=['testdocument'], reply=['localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'ru-RU,es'})['result']) self.assertEqual( {'localized_prop': 'value_es'}, - self.call('GET', path=['testdocument', guid], accept_language=['es'], reply=['localized_prop'])) + this.call(method='GET', path=['testdocument', guid], reply=['localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'es'})) self.assertEqual( 'value_es', - self.call('GET', path=['testdocument', guid, 'localized_prop'], accept_language=['es', 'ru'])) + this.call(method='GET', path=['testdocument', guid, 'localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'es,ru'})) self.assertEqual( [{'localized_prop': 'value_es'}], - self.call('GET', path=['testdocument'], accept_language=['foo', 'es', 'ru'], reply=['localized_prop'])['result']) + this.call(method='GET', path=['testdocument'], reply=['localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'foo,es,ru'})['result']) self.assertEqual( {'localized_prop': 'value_en'}, - self.call('GET', path=['testdocument', guid], accept_language=['fr'], reply=['localized_prop'])) + this.call(method='GET', path=['testdocument', guid], reply=['localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'fr'})) self.assertEqual( 'value_en', - self.call('GET', path=['testdocument', guid, 'localized_prop'], accept_language=['fr', 'za'])) + this.call(method='GET', path=['testdocument', guid, 'localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'fr,za'})) self.assertEqual( [{'localized_prop': 'value_en'}], - self.call('GET', path=['testdocument'], accept_language=['foo', 'fr', 'za'], reply=['localized_prop'])['result']) + this.call(method='GET', path=['testdocument'], reply=['localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'foo,fr,za'})['result']) - toolkit._default_langs = ['foo'] + i18n._default_langs = ['foo'] fallback_lang = sorted(['ru', 'es', 'en'])[0] self.assertEqual( {'localized_prop': 'value_%s' % fallback_lang}, - self.call('GET', path=['testdocument', guid], accept_language=['fr'], reply=['localized_prop'])) + this.call(method='GET', path=['testdocument', guid], reply=['localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'fr'})) self.assertEqual( 'value_%s' % fallback_lang, - self.call('GET', path=['testdocument', guid, 'localized_prop'], accept_language=['fr', 'za'])) + this.call(method='GET', path=['testdocument', guid, 'localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'fr,za'})) self.assertEqual( [{'localized_prop': 'value_%s' % fallback_lang}], - self.call('GET', path=['testdocument'], accept_language=['foo', 'fr', 'za'], reply=['localized_prop'])['result']) + this.call(method='GET', path=['testdocument'], reply=['localized_prop'], + environ={'HTTP_ACCEPT_LANGUAGE': 'foo,fr,za'})['result']) def test_OpenByModuleName(self): self.touch( @@ -543,9 +713,9 @@ class RoutesTest(tests.Test): ) sys.path.insert(0, '.') - volume = db.Volume('.', ['foo.bar'], lambda event: None) - assert exists('bar/index') + volume = db.Volume('.', ['foo.bar']) volume['bar'].find() + assert exists('bar/index') volume.close() def test_Command_GetBlobSetByUrl(self): @@ -556,21 +726,25 @@ class RoutesTest(tests.Test): def prop(self, value): return value - @db.blob_property() + @db.stored_property(db.Blob) def blob(self, value): return value - @db.indexed_property(prefix='L', localized=True, default='') + @db.indexed_property(db.Localized, prefix='L', default={}) def localized_prop(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={}) - self.call('PUT', path=['testdocument', guid, 'blob'], url='http://sugarlabs.org') + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + guid = this.call(method='POST', path=['testdocument'], content={}) + this.call(method='PUT', path=['testdocument', guid, 'blob'], content={ + 'digest': 'digest', + 'url': 'http://sugarlabs.org', + }, content_type='application/json') self.assertEqual( 'http://sugarlabs.org', - self.call('GET', path=['testdocument', guid, 'blob'])['url']) + this.call(method='GET', path=['testdocument', guid, 'blob'])['url']) def test_on_create(self): @@ -580,24 +754,25 @@ class RoutesTest(tests.Test): def prop(self, value): return value - @db.indexed_property(prefix='L', localized=True, default='') + @db.indexed_property(db.Localized, prefix='L', default={}) def localized_prop(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) ts = int(time.time()) - guid = self.call('POST', path=['testdocument'], content={}) - assert self.volume['testdocument'].get(guid)['ctime'] in range(ts - 1, ts + 1) - assert self.volume['testdocument'].get(guid)['mtime'] in range(ts - 1, ts + 1) + guid = this.call(method='POST', path=['testdocument'], content={}) + assert volume['testdocument'].get(guid)['ctime'] in range(ts - 1, ts + 1) + assert volume['testdocument'].get(guid)['mtime'] in range(ts - 1, ts + 1) def test_on_create_Override(self): class Routes(db.Routes): - def on_create(self, request, props, event): + def on_create(self, request, props): props['prop'] = 'overriden' - db.Routes.on_create(self, request, props, event) + db.Routes.on_create(self, request, props) class TestDocument(db.Resource): @@ -605,17 +780,18 @@ class RoutesTest(tests.Test): def prop(self, value): return value - @db.indexed_property(prefix='L', localized=True, default='') + @db.indexed_property(db.Localized, prefix='L', default={}) def localized_prop(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(Routes(volume)) - guid = self.call('POST', ['testdocument'], content={'prop': 'foo'}, routes=Routes) - self.assertEqual('overriden', self.volume['testdocument'].get(guid)['prop']) + guid = this.call(method='POST', path=['testdocument'], content={'prop': 'foo'}, routes=Routes) + self.assertEqual('overriden', volume['testdocument'].get(guid)['prop']) - self.call('PUT', ['testdocument', guid], content={'prop': 'bar'}, routes=Routes) - self.assertEqual('bar', self.volume['testdocument'].get(guid)['prop']) + this.call(method='PUT', path=['testdocument', guid], content={'prop': 'bar'}, routes=Routes) + self.assertEqual('bar', volume['testdocument'].get(guid)['prop']) def test_on_update(self): @@ -625,26 +801,28 @@ class RoutesTest(tests.Test): def prop(self, value): return value - @db.indexed_property(prefix='L', localized=True, default='') + @db.indexed_property(db.Localized, prefix='L', default={}) def localized_prop(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={}) - prev_mtime = self.volume['testdocument'].get(guid)['mtime'] + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + + guid = this.call(method='POST', path=['testdocument'], content={}) + prev_mtime = volume['testdocument'].get(guid)['mtime'] time.sleep(1) - self.call('PUT', path=['testdocument', guid], content={'prop': 'probe'}) - assert self.volume['testdocument'].get(guid)['mtime'] - prev_mtime >= 1 + this.call(method='PUT', path=['testdocument', guid], content={'prop': 'probe'}) + assert volume['testdocument'].get(guid)['mtime'] - prev_mtime >= 1 def test_on_update_Override(self): class Routes(db.Routes): - def on_update(self, request, props, event): + def on_update(self, request, props): props['prop'] = 'overriden' - db.Routes.on_update(self, request, props, event) + db.Routes.on_update(self, request, props) class TestDocument(db.Resource): @@ -652,17 +830,18 @@ class RoutesTest(tests.Test): def prop(self, value): return value - @db.indexed_property(prefix='L', localized=True, default='') + @db.indexed_property(db.Localized, prefix='L', default={}) def localized_prop(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(Routes(volume)) - guid = self.call('POST', ['testdocument'], content={'prop': 'foo'}, routes=Routes) - self.assertEqual('foo', self.volume['testdocument'].get(guid)['prop']) + guid = this.call(method='POST', path=['testdocument'], content={'prop': 'foo'}, routes=Routes) + self.assertEqual('foo', volume['testdocument'].get(guid)['prop']) - self.call('PUT', ['testdocument', guid], content={'prop': 'bar'}, routes=Routes) - self.assertEqual('overriden', self.volume['testdocument'].get(guid)['prop']) + this.call(method='PUT', path=['testdocument', guid], content={'prop': 'bar'}, routes=Routes) + self.assertEqual('overriden', volume['testdocument'].get(guid)['prop']) def __test_DoNotPassGuidsForCreate(self): @@ -672,13 +851,15 @@ class RoutesTest(tests.Test): def prop(self, value): return value - @db.indexed_property(prefix='L', localized=True, default='') + @db.indexed_property(db.Localized, prefix='L', default={}) def localized_prop(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - self.assertRaises(http.Forbidden, self.call, 'POST', path=['testdocument'], content={'guid': 'foo'}) - guid = self.call('POST', path=['testdocument'], content={}) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + + self.assertRaises(http.Forbidden, this.call, method='POST', path=['testdocument'], content={'guid': 'foo'}) + guid = this.call(method='POST', path=['testdocument'], content={}) assert guid def test_seqno(self): @@ -689,7 +870,8 @@ class RoutesTest(tests.Test): class Document2(db.Resource): pass - volume = db.Volume(tests.tmpdir, [Document1, Document2], lambda event: None) + volume = db.Volume(tests.tmpdir, [Document1, Document2]) + router = Router(db.Routes(volume)) assert not exists('seqno') self.assertEqual(0, volume.seqno.value) @@ -706,8 +888,8 @@ class RoutesTest(tests.Test): self.assertEqual(4, volume.seqno.value) assert not exists('seqno') volume.seqno.commit() - assert exists('seqno') - volume = db.Volume(tests.tmpdir, [Document1, Document2], lambda event: None) + assert exists('db.seqno') + volume = db.Volume(tests.tmpdir, [Document1, Document2]) self.assertEqual(4, volume.seqno.value) def test_Events(self): @@ -726,7 +908,7 @@ class RoutesTest(tests.Test): def prop(self, value): pass - @db.blob_property() + @db.stored_property(db.Blob) def blob(self, value): return value @@ -739,13 +921,15 @@ class RoutesTest(tests.Test): ) events = [] - volume = db.Volume(tests.tmpdir, [Document1, Document2], lambda event: events.append(event)) + this.broadcast = lambda x: events.append(x) + volume = db.Volume(tests.tmpdir, [Document1, Document2]) + volume['document1'] + volume['document2'] coroutine.sleep(.1) mtime = int(os.stat('document1/index/mtime').st_mtime) self.assertEqual([ {'event': 'commit', 'resource': 'document1', 'mtime': mtime}, - {'event': 'populate', 'resource': 'document1', 'mtime': mtime}, ], events) del events[:] @@ -794,43 +978,45 @@ class RoutesTest(tests.Test): def prop(self, value): pass - @db.blob_property(acl=ACL.READ) + @db.stored_property(db.Blob, acl=ACL.READ) def blob(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={}) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + guid = this.call(method='POST', path=['testdocument'], content={}) - self.assertRaises(http.Forbidden, self.call, 'POST', path=['testdocument'], content={'prop': 'value'}) - self.assertRaises(http.Forbidden, self.call, 'PUT', path=['testdocument', guid], content={'prop': 'value'}) - self.assertRaises(http.Forbidden, self.call, 'PUT', path=['testdocument', guid], content={'blob': 'value'}) - self.assertRaises(http.Forbidden, self.call, 'PUT', path=['testdocument', guid, 'prop'], content='value') - self.assertRaises(http.Forbidden, self.call, 'PUT', path=['testdocument', guid, 'blob'], content='value') + self.assertRaises(http.Forbidden, this.call, method='POST', path=['testdocument'], content={'prop': 'value'}) + self.assertRaises(http.Forbidden, this.call, method='PUT', path=['testdocument', guid], content={'prop': 'value'}) + self.assertRaises(http.Forbidden, this.call, method='PUT', path=['testdocument', guid], content={'blob': 'value'}) + self.assertRaises(http.Forbidden, this.call, method='PUT', path=['testdocument', guid, 'prop'], content='value') + self.assertRaises(http.Forbidden, this.call, method='PUT', path=['testdocument', guid, 'blob'], content='value') def test_BlobsWritePermissions(self): class TestDocument(db.Resource): - @db.blob_property(acl=ACL.CREATE | ACL.WRITE) + @db.stored_property(db.Blob, acl=ACL.CREATE | ACL.WRITE) def blob1(self, value): return value - @db.blob_property(acl=ACL.CREATE) + @db.stored_property(db.Blob, acl=ACL.CREATE) def blob2(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) - guid = self.call('POST', path=['testdocument'], content={}) - self.call('PUT', path=['testdocument', guid], content={'blob1': 'value1', 'blob2': 'value2'}) - self.call('PUT', path=['testdocument', guid], content={'blob1': 'value1'}) - self.assertRaises(http.Forbidden, self.call, 'PUT', path=['testdocument', guid], content={'blob2': 'value2_'}) + guid = this.call(method='POST', path=['testdocument'], content={}) + this.call(method='PUT', path=['testdocument', guid], content={'blob1': 'value1', 'blob2': 'value2'}) + this.call(method='PUT', path=['testdocument', guid], content={'blob1': 'value1'}) + self.assertRaises(http.Forbidden, this.call, method='PUT', path=['testdocument', guid], content={'blob2': 'value2_'}) - guid = self.call('POST', path=['testdocument'], content={}) - self.call('PUT', path=['testdocument', guid, 'blob1'], content='value1') - self.call('PUT', path=['testdocument', guid, 'blob2'], content='value2') - self.call('PUT', path=['testdocument', guid, 'blob1'], content='value1_') - self.assertRaises(http.Forbidden, self.call, 'PUT', path=['testdocument', guid, 'blob2'], content='value2_') + guid = this.call(method='POST', path=['testdocument'], content={}) + this.call(method='PUT', path=['testdocument', guid, 'blob1'], content='value1') + this.call(method='PUT', path=['testdocument', guid, 'blob2'], content='value2') + this.call(method='PUT', path=['testdocument', guid, 'blob1'], content='value1_') + self.assertRaises(http.Forbidden, this.call, method='PUT', path=['testdocument', guid, 'blob2'], content='value2_') def test_properties_OverrideGet(self): @@ -844,30 +1030,32 @@ class RoutesTest(tests.Test): def prop2(self, value): return -1 - @db.blob_property() + @db.stored_property(db.Blob) def blob(self, meta): meta['blob'] = 'new-blob' return meta - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={}) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + + guid = this.call(method='POST', path=['testdocument'], content={}) self.touch(('new-blob', 'new-blob')) - self.call('PUT', path=['testdocument', guid, 'blob'], content='old-blob') + this.call(method='PUT', path=['testdocument', guid, 'blob'], content='old-blob') self.assertEqual( 'new-blob', - self.call('GET', path=['testdocument', guid, 'blob'])['blob']) + this.call(method='GET', path=['testdocument', guid, 'blob'])['blob']) self.assertEqual( '1', - self.call('GET', path=['testdocument', guid, 'prop1'])) + this.call(method='GET', path=['testdocument', guid, 'prop1'])) self.assertEqual( -1, - self.call('GET', path=['testdocument', guid, 'prop2'])) + this.call(method='GET', path=['testdocument', guid, 'prop2'])) self.assertEqual( {'prop1': '1', 'prop2': -1}, - self.call('GET', path=['testdocument', guid], reply=['prop1', 'prop2'])) + this.call(method='GET', path=['testdocument', guid], reply=['prop1', 'prop2'])) - def test_properties_OverrideSet(self): + def test_properties_OverrideSetter(self): class TestDocument(db.Resource): @@ -879,53 +1067,47 @@ class RoutesTest(tests.Test): def prop(self, value): return '_%s' % value - @db.blob_property() - def blob1(self, meta): - return meta + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + guid = this.call(method='POST', path=['testdocument'], content={}) - @blob1.setter - def blob1(self, value): - return Blob({'url': file(value['blob']).read()}) + self.assertEqual('_1', this.call(method='GET', path=['testdocument', guid, 'prop'])) - @db.blob_property() - def blob2(self, meta): - return meta + this.call(method='PUT', path=['testdocument', guid, 'prop'], content='2') + self.assertEqual('_2', this.call(method='GET', path=['testdocument', guid, 'prop'])) - @blob2.setter - def blob2(self, value): - with toolkit.NamedTemporaryFile(delete=False) as f: - f.write(' %s ' % file(value['blob']).read()) - value['blob'] = f.name - return value + this.call(method='PUT', path=['testdocument', guid], content={'prop': 3}) + self.assertEqual('_3', this.call(method='GET', path=['testdocument', guid, 'prop'])) - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={}) + def test_properties_AccessToOldValuesInSetters(self): + + class TestDocument(db.Resource): - self.assertEqual('_1', self.call('GET', path=['testdocument', guid, 'prop'])) - self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob1']) + @db.stored_property(db.Numeric) + def prop(self, value): + return value - self.call('PUT', path=['testdocument', guid, 'prop'], content='2') - self.assertEqual('_2', self.call('GET', path=['testdocument', guid, 'prop'])) - self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob1']) + @prop.setter + def prop(self, value): + return value + (self['prop'] or 0) - self.call('PUT', path=['testdocument', guid], content={'prop': 3}) - self.assertEqual('_3', self.call('GET', path=['testdocument', guid, 'prop'])) - self.assertRaises(http.NotFound, self.call, 'GET', path=['testdocument', guid, 'blob1']) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) - self.call('PUT', path=['testdocument', guid, 'blob1'], content='blob_url') - self.assertEqual('blob_url', self.call('GET', path=['testdocument', guid, 'blob1'])['url']) + guid = this.call(method='POST', path=['testdocument'], content={'prop': 1}) + self.assertEqual(1, this.call(method='GET', path=['testdocument', guid, 'prop'])) - guid = self.call('POST', path=['testdocument'], content={'blob2': 'foo'}) - self.assertEqual(' foo ', file(self.call('GET', path=['testdocument', guid, 'blob2'])['blob']).read()) + this.call(method='PUT', path=['testdocument', guid, 'prop'], content='2') + self.assertEqual(3, this.call(method='GET', path=['testdocument', guid, 'prop'])) - self.call('PUT', path=['testdocument', guid, 'blob2'], content='bar') - self.assertEqual(' bar ', file(self.call('GET', path=['testdocument', guid, 'blob2'])['blob']).read()) + this.call(method='PUT', path=['testdocument', guid], content={'prop': 3}) + self.assertEqual(6, this.call(method='GET', path=['testdocument', guid, 'prop'])) def test_properties_CallSettersAtTheEnd(self): class TestDocument(db.Resource): - @db.indexed_property(slot=1, typecast=int) + @db.indexed_property(db.Numeric, slot=1) def prop1(self, value): return value @@ -933,7 +1115,7 @@ class RoutesTest(tests.Test): def prop1(self, value): return self['prop3'] + value - @db.indexed_property(slot=2, typecast=int) + @db.indexed_property(db.Numeric, slot=2) def prop2(self, value): return value @@ -941,107 +1123,40 @@ class RoutesTest(tests.Test): def prop2(self, value): return self['prop3'] - value - @db.indexed_property(slot=3, typecast=int) + @db.indexed_property(db.Numeric, slot=3) def prop3(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={'prop1': 1, 'prop2': 2, 'prop3': 3}) - self.assertEqual(4, self.call('GET', path=['testdocument', guid, 'prop1'])) - self.assertEqual(1, self.call('GET', path=['testdocument', guid, 'prop2'])) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + + guid = this.call(method='POST', path=['testdocument'], content={'prop1': 1, 'prop2': 2, 'prop3': 3}) + self.assertEqual(4, this.call(method='GET', path=['testdocument', guid, 'prop1'])) + self.assertEqual(1, this.call(method='GET', path=['testdocument', guid, 'prop2'])) def test_properties_PopulateRequiredPropsInSetters(self): class TestDocument(db.Resource): - @db.indexed_property(slot=1, typecast=int) + @db.indexed_property(db.Numeric, slot=1) def prop1(self, value): return value @prop1.setter def prop1(self, value): - self['prop2'] = value + 1 + self.post('prop2', value + 1) return value - @db.indexed_property(slot=2, typecast=int) + @db.indexed_property(db.Numeric, slot=2) def prop2(self, value): return value - @db.blob_property() - def prop3(self, value): - return value - - @prop3.setter - def prop3(self, value): - self['prop1'] = -1 - self['prop2'] = -2 - return value - - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={'prop1': 1}) - self.assertEqual(1, self.call('GET', path=['testdocument', guid, 'prop1'])) - self.assertEqual(2, self.call('GET', path=['testdocument', guid, 'prop2'])) - - def test_properties_PopulateRequiredPropsInBlobSetter(self): - - class TestDocument(db.Resource): - - @db.blob_property() - def blob(self, value): - return value - - @blob.setter - def blob(self, value): - self['prop1'] = 1 - self['prop2'] = 2 - return value - - @db.indexed_property(slot=1, typecast=int) - def prop1(self, value): - return value - - @db.indexed_property(slot=2, typecast=int) - def prop2(self, value): - return value - - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={'blob': ''}) - self.assertEqual(1, self.call('GET', path=['testdocument', guid, 'prop1'])) - self.assertEqual(2, self.call('GET', path=['testdocument', guid, 'prop2'])) - - def __test_SubCall(self): - - class TestDocument(db.Resource): - - @db.blob_property(mime_type='application/json') - def blob(self, value): - return value - - @blob.setter - def blob(self, value): - blob = file(value['blob']).read() - if '!' not in blob: - meta = self.meta('blob') - if meta: - blob = file(meta['blob']).read() + blob - with toolkit.NamedTemporaryFile(delete=False) as f: - f.write(blob) - value['blob'] = f.name - coroutine.spawn(self.post, blob) - return value - - def post(self, value): - self.request.call('PUT', path=['testdocument', self.guid, 'blob'], content=value + '!') + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - - guid = self.call('POST', path=['testdocument'], content={'blob': '0'}) - coroutine.dispatch() - self.assertEqual('0!', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read()) - - self.call('PUT', path=['testdocument', guid, 'blob'], content='1') - coroutine.dispatch() - self.assertEqual('0!1!', file(self.call('GET', path=['testdocument', guid, 'blob'])['blob']).read()) + guid = this.call(method='POST', path=['testdocument'], content={'prop1': 1}) + self.assertEqual(1, this.call(method='GET', path=['testdocument', guid, 'prop1'])) + self.assertEqual(2, this.call(method='GET', path=['testdocument', guid, 'prop2'])) def test_Group(self): @@ -1051,15 +1166,16 @@ class RoutesTest(tests.Test): def prop(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) - self.call('POST', path=['testdocument'], content={'prop': 1}) - self.call('POST', path=['testdocument'], content={'prop': 2}) - self.call('POST', path=['testdocument'], content={'prop': 1}) + this.call(method='POST', path=['testdocument'], content={'prop': 1}) + this.call(method='POST', path=['testdocument'], content={'prop': 2}) + this.call(method='POST', path=['testdocument'], content={'prop': 1}) self.assertEqual( sorted([{'prop': 1}, {'prop': 2}]), - sorted(self.call('GET', path=['testdocument'], reply='prop', group_by='prop')['result'])) + sorted(this.call(method='GET', path=['testdocument'], reply='prop', group_by='prop')['result'])) def test_CallSetterEvenIfThereIsNoCreatePermissions(self): @@ -1073,12 +1189,13 @@ class RoutesTest(tests.Test): def prop(self, value): return value + 1 - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) - self.assertRaises(http.Forbidden, self.call, 'POST', path=['testdocument'], content={'prop': 1}) + self.assertRaises(http.Forbidden, this.call, method='POST', path=['testdocument'], content={'prop': 1}) - guid = self.call('POST', path=['testdocument'], content={}) - self.assertEqual(1, self.call('GET', path=['testdocument', guid, 'prop'])) + guid = this.call(method='POST', path=['testdocument'], content={}) + self.assertEqual(1, this.call(method='GET', path=['testdocument', guid, 'prop'])) def test_ReturnDefualtsForMissedProps(self): @@ -1088,57 +1205,34 @@ class RoutesTest(tests.Test): def prop(self, value): return value - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', path=['testdocument'], content={'prop': 'set'}) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + guid = this.call(method='POST', path=['testdocument'], content={'prop': 'set'}) self.assertEqual( [{'prop': 'set'}], - self.call('GET', path=['testdocument'], reply='prop')['result']) + this.call(method='GET', path=['testdocument'], reply='prop')['result']) self.assertEqual( {'prop': 'set'}, - self.call('GET', path=['testdocument', guid], reply='prop')) + this.call(method='GET', path=['testdocument', guid], reply='prop')) self.assertEqual( 'set', - self.call('GET', path=['testdocument', guid, 'prop'])) + this.call(method='GET', path=['testdocument', guid, 'prop'])) os.unlink('testdocument/%s/%s/prop' % (guid[:2], guid)) self.assertEqual( [{'prop': 'default'}], - self.call('GET', path=['testdocument'], reply='prop')['result']) + this.call(method='GET', path=['testdocument'], reply='prop')['result']) self.assertEqual( {'prop': 'default'}, - self.call('GET', path=['testdocument', guid], reply='prop')) + this.call(method='GET', path=['testdocument', guid], reply='prop')) self.assertEqual( 'default', - self.call('GET', path=['testdocument', guid, 'prop'])) - - def test_PopulateNonDefualtPropsInSetters(self): - - class TestDocument(db.Resource): - - @db.indexed_property(slot=1) - def prop1(self, value): - return value - - @db.indexed_property(slot=2, default='default') - def prop2(self, value): - return all - - @prop2.setter - def prop2(self, value): - if value != 'default': - self['prop1'] = value - return value - - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - - self.assertRaises(RuntimeError, self.call, 'POST', path=['testdocument'], content={}) - - guid = self.call('POST', path=['testdocument'], content={'prop2': 'value2'}) - self.assertEqual('value2', self.call('GET', path=['testdocument', guid, 'prop1'])) + this.call(method='GET', path=['testdocument', guid, 'prop'])) def test_prop_meta(self): + files.update('url', {'url': 'http://new', 'foo': 'bar', 'size': 100}) class TestDocument(db.Resource): @@ -1146,44 +1240,55 @@ class RoutesTest(tests.Test): def prop(self, value): return value - @db.blob_property() + @db.stored_property(db.Blob) def blob1(self, value): return value - @db.blob_property() + @db.stored_property(db.Blob) def blob2(self, value): return value @blob2.setter def blob2(self, value): - return {'url': 'http://new', 'foo': 'bar', 'blob_size': 100} + return 'url' - self.volume = db.Volume(tests.tmpdir, [TestDocument], lambda event: None) - guid = self.call('POST', ['testdocument'], content = {'prop': 'prop', 'blob1': 'blob', 'blob2': ''}) + volume = db.Volume(tests.tmpdir, [TestDocument]) + router = Router(db.Routes(volume)) + guid = this.call(method='POST', path=['testdocument'], content = {'prop': 'prop', 'blob1': 'blob', 'blob2': ''}) - assert self.call('HEAD', ['testdocument', guid, 'prop']) is None - meta = self.volume['testdocument'].get(guid).meta('prop') + response = Response() + assert this.call(response=response, + method='HEAD', path=['testdocument', guid, 'prop']) is None + meta = volume['testdocument'].get(guid).meta('prop') meta.pop('value') - self.assertEqual(meta, self.response.meta) - self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), self.response.last_modified) - - assert self.call('HEAD', ['testdocument', guid, 'blob1'], host='localhost') is None - meta = self.volume['testdocument'].get(guid).meta('blob1') - meta.pop('blob') - self.assertEqual(meta, self.response.meta) - self.assertEqual(len('blob'), self.response.content_length) - self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), self.response.last_modified) - - assert self.call('HEAD', ['testdocument', guid, 'blob2']) is None - meta = self.volume['testdocument'].get(guid).meta('blob2') - self.assertEqual(meta, self.response.meta) - self.assertEqual(100, self.response.content_length) - self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), self.response.last_modified) - - assert self.call('GET', ['testdocument', guid, 'blob2']) is not None - meta = self.volume['testdocument'].get(guid).meta('blob2') - self.assertEqual(meta, self.response.meta) - self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), self.response.last_modified) + self.assertEqual(meta, response.meta) + self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), response.last_modified) + + response = Response() + assert this.call(response=response, + method='HEAD', path=['testdocument', guid, 'blob1'], environ={'HTTP_HOST': 'localhost'}) is None + meta = volume['testdocument'].get(guid).meta('blob1') + meta.pop('value') + self.assertEqual(meta, response.meta) + self.assertEqual(len('blob'), response.content_length) + self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), response.last_modified) + + response = Response() + assert this.call(response=response, + method='HEAD', path=['testdocument', guid, 'blob2']) is None + meta = volume['testdocument'].get(guid).meta('blob2') + meta.pop('value') + self.assertEqual(meta, response.meta) + self.assertEqual(100, response.content_length) + self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), response.last_modified) + + response = Response() + assert this.call(response=response, + method='GET', path=['testdocument', guid, 'blob2']) is not None + meta = volume['testdocument'].get(guid).meta('blob2') + meta.pop('value') + self.assertEqual(meta, response.meta) + self.assertEqual(formatdate(meta['mtime'], localtime=False, usegmt=True), response.last_modified) def test_DefaultAuthor(self): @@ -1196,25 +1301,26 @@ class RoutesTest(tests.Test): class Document(db.Resource): pass - self.volume = db.Volume('db', [User, Document]) + volume = db.Volume(tests.tmpdir, [User, Document]) + router = Router(db.Routes(volume)) - guid = self.call('POST', ['document'], content={}, principal='user') + guid = this.call(method='POST', path=['document'], content={}, principal='user') self.assertEqual( [{'name': 'user', 'role': 2}], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual( {'user': {'role': 2, 'order': 0}}, - self.volume['document'].get(guid)['author']) + volume['document'].get(guid)['author']) - self.volume['user'].create({'guid': 'user', 'pubkey': '', 'name': 'User'}) + volume['user'].create({'guid': 'user', 'pubkey': '', 'name': 'User'}) - guid = self.call('POST', ['document'], content={}, principal='user') + guid = this.call(method='POST', path=['document'], content={}, principal='user') self.assertEqual( [{'guid': 'user', 'name': 'User', 'role': 3}], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual( {'user': {'name': 'User', 'role': 3, 'order': 0}}, - self.volume['document'].get(guid)['author']) + volume['document'].get(guid)['author']) def test_FindByAuthor(self): @@ -1227,36 +1333,37 @@ class RoutesTest(tests.Test): class Document(db.Resource): pass - self.volume = db.Volume('db', [User, Document]) + volume = db.Volume(tests.tmpdir, [User, Document]) + router = Router(db.Routes(volume)) - self.volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'UserName1'}) - self.volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User Name2'}) - self.volume['user'].create({'guid': 'user3', 'pubkey': '', 'name': 'User Name 3'}) + volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'UserName1'}) + volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User Name2'}) + volume['user'].create({'guid': 'user3', 'pubkey': '', 'name': 'User Name 3'}) - guid1 = self.call('POST', ['document'], content={}, principal='user1') - guid2 = self.call('POST', ['document'], content={}, principal='user2') - guid3 = self.call('POST', ['document'], content={}, principal='user3') + guid1 = this.call(method='POST', path=['document'], content={}, principal='user1') + guid2 = this.call(method='POST', path=['document'], content={}, principal='user2') + guid3 = this.call(method='POST', path=['document'], content={}, principal='user3') self.assertEqual(sorted([ {'guid': guid1}, ]), - self.call('GET', ['document'], author='UserName1')['result']) + this.call(method='GET', path=['document'], author='UserName1')['result']) self.assertEqual(sorted([ {'guid': guid1}, ]), - sorted(self.call('GET', ['document'], query='author:UserName')['result'])) + sorted(this.call(method='GET', path=['document'], query='author:UserName')['result'])) self.assertEqual(sorted([ {'guid': guid1}, {'guid': guid2}, {'guid': guid3}, ]), - sorted(self.call('GET', ['document'], query='author:User')['result'])) + sorted(this.call(method='GET', path=['document'], query='author:User')['result'])) self.assertEqual(sorted([ {'guid': guid2}, {'guid': guid3}, ]), - sorted(self.call('GET', ['document'], query='author:Name')['result'])) + sorted(this.call(method='GET', path=['document'], query='author:Name')['result'])) def test_PreserveAuthorsOrder(self): @@ -1269,99 +1376,77 @@ class RoutesTest(tests.Test): class Document(db.Resource): pass - self.volume = db.Volume('db', [User, Document]) + volume = db.Volume(tests.tmpdir, [User, Document]) + router = Router(db.Routes(volume)) - self.volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'}) - self.volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User2'}) - self.volume['user'].create({'guid': 'user3', 'pubkey': '', 'name': 'User3'}) + volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'}) + volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User2'}) + volume['user'].create({'guid': 'user3', 'pubkey': '', 'name': 'User3'}) - guid = self.call('POST', ['document'], content={}, principal='user1') - self.call('PUT', ['document', guid], cmd='useradd', user='user2', role=0) - self.call('PUT', ['document', guid], cmd='useradd', user='user3', role=0) + guid = this.call(method='POST', path=['document'], content={}, principal='user1') + this.call(method='PUT', path=['document', guid], cmd='useradd', user='user2', role=0) + this.call(method='PUT', path=['document', guid], cmd='useradd', user='user3', role=0) self.assertEqual([ {'guid': 'user1', 'name': 'User1', 'role': 3}, {'guid': 'user2', 'name': 'User2', 'role': 1}, {'guid': 'user3', 'name': 'User3', 'role': 1}, ], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual({ 'user1': {'name': 'User1', 'role': 3, 'order': 0}, 'user2': {'name': 'User2', 'role': 1, 'order': 1}, 'user3': {'name': 'User3', 'role': 1, 'order': 2}, }, - self.volume['document'].get(guid)['author']) + volume['document'].get(guid)['author']) - self.call('PUT', ['document', guid], cmd='userdel', user='user2', principal='user1') - self.call('PUT', ['document', guid], cmd='useradd', user='user2', role=0) + this.call(method='PUT', path=['document', guid], cmd='userdel', user='user2', principal='user1') + this.call(method='PUT', path=['document', guid], cmd='useradd', user='user2', role=0) self.assertEqual([ {'guid': 'user1', 'name': 'User1', 'role': 3}, {'guid': 'user3', 'name': 'User3', 'role': 1}, {'guid': 'user2', 'name': 'User2', 'role': 1}, ], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual({ 'user1': {'name': 'User1', 'role': 3, 'order': 0}, 'user3': {'name': 'User3', 'role': 1, 'order': 2}, 'user2': {'name': 'User2', 'role': 1, 'order': 3}, }, - self.volume['document'].get(guid)['author']) + volume['document'].get(guid)['author']) - self.call('PUT', ['document', guid], cmd='userdel', user='user2', principal='user1') - self.call('PUT', ['document', guid], cmd='useradd', user='user2', role=0) + this.call(method='PUT', path=['document', guid], cmd='userdel', user='user2', principal='user1') + this.call(method='PUT', path=['document', guid], cmd='useradd', user='user2', role=0) self.assertEqual([ {'guid': 'user1', 'name': 'User1', 'role': 3}, {'guid': 'user3', 'name': 'User3', 'role': 1}, {'guid': 'user2', 'name': 'User2', 'role': 1}, ], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual({ 'user1': {'name': 'User1', 'role': 3, 'order': 0}, 'user3': {'name': 'User3', 'role': 1, 'order': 2}, 'user2': {'name': 'User2', 'role': 1, 'order': 3}, }, - self.volume['document'].get(guid)['author']) + volume['document'].get(guid)['author']) - self.call('PUT', ['document', guid], cmd='userdel', user='user3', principal='user1') - self.call('PUT', ['document', guid], cmd='useradd', user='user3', role=0) + this.call(method='PUT', path=['document', guid], cmd='userdel', user='user3', principal='user1') + this.call(method='PUT', path=['document', guid], cmd='useradd', user='user3', role=0) self.assertEqual([ {'guid': 'user1', 'name': 'User1', 'role': 3}, {'guid': 'user2', 'name': 'User2', 'role': 1}, {'guid': 'user3', 'name': 'User3', 'role': 1}, ], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual({ 'user1': {'name': 'User1', 'role': 3, 'order': 0}, 'user2': {'name': 'User2', 'role': 1, 'order': 3}, 'user3': {'name': 'User3', 'role': 1, 'order': 4}, }, - self.volume['document'].get(guid)['author']) - - def test_CopyAthors(self): - - class User(db.Resource): - - @db.indexed_property(slot=1) - def name(self, value): - return value - - class Document(db.Resource): - pass - - self.volume = db.Volume('db', [User, Document]) - self.volume['user'].create({'guid': 'user', 'pubkey': '', 'name': 'User'}) - - guid1 = self.call('POST', ['document'], content={}, principal='user') - self.assertEqual({'user': {'name': 'User', 'role': 3, 'order': 0}}, self.volume['document'].get(guid1)['author']) - author = self.call('GET', ['document', guid1, 'author']) - self.assertEqual([{'guid': 'user', 'role': 3, 'name': 'User'}], author) - - guid2 = self.volume['document'].create({'author': author}, setters=True) - author = self.call('GET', ['document', guid1, 'author']) - self.assertEqual({'user': {'name': 'User', 'role': 3, 'order': 0}}, self.volume['document'].get(guid2)['author']) + volume['document'].get(guid)['author']) def test_AddUser(self): @@ -1374,62 +1459,63 @@ class RoutesTest(tests.Test): class Document(db.Resource): pass - self.volume = db.Volume('db', [User, Document]) + volume = db.Volume(tests.tmpdir, [User, Document]) + router = Router(db.Routes(volume)) - self.volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'}) - self.volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User2'}) + volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'}) + volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User2'}) - guid = self.call('POST', ['document'], content={}, principal='user1') + guid = this.call(method='POST', path=['document'], content={}, principal='user1') self.assertEqual([ {'guid': 'user1', 'name': 'User1', 'role': 3}, ], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual({ 'user1': {'name': 'User1', 'role': 3, 'order': 0}, }, - self.volume['document'].get(guid)['author']) + volume['document'].get(guid)['author']) - self.call('PUT', ['document', guid], cmd='useradd', user='user2', role=2) + this.call(method='PUT', path=['document', guid], cmd='useradd', user='user2', role=2) self.assertEqual([ {'guid': 'user1', 'name': 'User1', 'role': 3}, {'guid': 'user2', 'name': 'User2', 'role': 3}, ], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual({ 'user1': {'name': 'User1', 'role': 3, 'order': 0}, 'user2': {'name': 'User2', 'role': 3, 'order': 1}, }, - self.volume['document'].get(guid)['author']) + volume['document'].get(guid)['author']) - self.call('PUT', ['document', guid], cmd='useradd', user='User3', role=3) + this.call(method='PUT', path=['document', guid], cmd='useradd', user='User3', role=3) self.assertEqual([ {'guid': 'user1', 'name': 'User1', 'role': 3}, {'guid': 'user2', 'name': 'User2', 'role': 3}, {'name': 'User3', 'role': 2}, ], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual({ 'user1': {'name': 'User1', 'role': 3, 'order': 0}, 'user2': {'name': 'User2', 'role': 3, 'order': 1}, 'User3': {'role': 2, 'order': 2}, }, - self.volume['document'].get(guid)['author']) + volume['document'].get(guid)['author']) - self.call('PUT', ['document', guid], cmd='useradd', user='User4', role=4) + this.call(method='PUT', path=['document', guid], cmd='useradd', user='User4', role=4) self.assertEqual([ {'guid': 'user1', 'name': 'User1', 'role': 3}, {'guid': 'user2', 'name': 'User2', 'role': 3}, {'name': 'User3', 'role': 2}, {'name': 'User4', 'role': 0}, ], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual({ 'user1': {'name': 'User1', 'role': 3, 'order': 0}, 'user2': {'name': 'User2', 'role': 3, 'order': 1}, 'User3': {'role': 2, 'order': 2}, 'User4': {'role': 0, 'order': 3}, }, - self.volume['document'].get(guid)['author']) + volume['document'].get(guid)['author']) def test_UpdateAuthor(self): @@ -1442,46 +1528,47 @@ class RoutesTest(tests.Test): class Document(db.Resource): pass - self.volume = db.Volume('db', [User, Document]) + volume = db.Volume(tests.tmpdir, [User, Document]) + router = Router(db.Routes(volume)) - self.volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'}) - guid = self.call('POST', ['document'], content={}, principal='user1') + volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'}) + guid = this.call(method='POST', path=['document'], content={}, principal='user1') - self.call('PUT', ['document', guid], cmd='useradd', user='User2', role=0) + this.call(method='PUT', path=['document', guid], cmd='useradd', user='User2', role=0) self.assertEqual([ {'guid': 'user1', 'name': 'User1', 'role': 3}, {'name': 'User2', 'role': 0}, ], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual({ 'user1': {'name': 'User1', 'role': 3, 'order': 0}, 'User2': {'role': 0, 'order': 1}, }, - self.volume['document'].get(guid)['author']) + volume['document'].get(guid)['author']) - self.call('PUT', ['document', guid], cmd='useradd', user='user1', role=0) + this.call(method='PUT', path=['document', guid], cmd='useradd', user='user1', role=0) self.assertEqual([ {'guid': 'user1', 'name': 'User1', 'role': 1}, {'name': 'User2', 'role': 0}, ], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual({ 'user1': {'name': 'User1', 'role': 1, 'order': 0}, 'User2': {'role': 0, 'order': 1}, }, - self.volume['document'].get(guid)['author']) + volume['document'].get(guid)['author']) - self.call('PUT', ['document', guid], cmd='useradd', user='User2', role=2) + this.call(method='PUT', path=['document', guid], cmd='useradd', user='User2', role=2) self.assertEqual([ {'guid': 'user1', 'name': 'User1', 'role': 1}, {'name': 'User2', 'role': 2}, ], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual({ 'user1': {'name': 'User1', 'role': 1, 'order': 0}, 'User2': {'role': 2, 'order': 1}, }, - self.volume['document'].get(guid)['author']) + volume['document'].get(guid)['author']) def test_DelUser(self): @@ -1494,150 +1581,73 @@ class RoutesTest(tests.Test): class Document(db.Resource): pass - self.volume = db.Volume('db', [User, Document]) + volume = db.Volume(tests.tmpdir, [User, Document]) + router = Router(db.Routes(volume)) - self.volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'}) - self.volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User2'}) - guid = self.call('POST', ['document'], content={}, principal='user1') - self.call('PUT', ['document', guid], cmd='useradd', user='user2') - self.call('PUT', ['document', guid], cmd='useradd', user='User3') + volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'}) + volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User2'}) + guid = this.call(method='POST', path=['document'], content={}, principal='user1') + this.call(method='PUT', path=['document', guid], cmd='useradd', user='user2') + this.call(method='PUT', path=['document', guid], cmd='useradd', user='User3') self.assertEqual([ {'guid': 'user1', 'name': 'User1', 'role': 3}, {'guid': 'user2', 'name': 'User2', 'role': 1}, {'name': 'User3', 'role': 0}, ], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual({ 'user1': {'name': 'User1', 'role': 3, 'order': 0}, 'user2': {'name': 'User2', 'role': 1, 'order': 1}, 'User3': {'role': 0, 'order': 2}, }, - self.volume['document'].get(guid)['author']) + volume['document'].get(guid)['author']) # Do not remove yourself - self.assertRaises(RuntimeError, self.call, 'PUT', ['document', guid], cmd='userdel', user='user1', principal='user1') - self.assertRaises(RuntimeError, self.call, 'PUT', ['document', guid], cmd='userdel', user='user2', principal='user2') + self.assertRaises(RuntimeError, this.call, method='PUT', path=['document', guid], cmd='userdel', user='user1', principal='user1') + self.assertRaises(RuntimeError, this.call, method='PUT', path=['document', guid], cmd='userdel', user='user2', principal='user2') - self.call('PUT', ['document', guid], cmd='userdel', user='user1', principal='user2') + this.call(method='PUT', path=['document', guid], cmd='userdel', user='user1', principal='user2') self.assertEqual([ {'guid': 'user2', 'name': 'User2', 'role': 1}, {'name': 'User3', 'role': 0}, ], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual({ 'user2': {'name': 'User2', 'role': 1, 'order': 1}, 'User3': {'role': 0, 'order': 2}, }, - self.volume['document'].get(guid)['author']) + volume['document'].get(guid)['author']) - self.call('PUT', ['document', guid], cmd='userdel', user='User3', principal='user2') + this.call(method='PUT', path=['document', guid], cmd='userdel', user='User3', principal='user2') self.assertEqual([ {'guid': 'user2', 'name': 'User2', 'role': 1}, ], - self.call('GET', ['document', guid, 'author'])) + this.call(method='GET', path=['document', guid, 'author'])) self.assertEqual({ 'user2': {'name': 'User2', 'role': 1, 'order': 1}, }, - self.volume['document'].get(guid)['author']) - - def test_typecast_prop_value(self): - prop = Property('prop', typecast=int) - self.assertEqual(1, _typecast_prop_value(prop.typecast, 1)) - self.assertEqual(1, _typecast_prop_value(prop.typecast, 1.1)) - self.assertEqual(1, _typecast_prop_value(prop.typecast, '1')) - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, '1.0') - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, '') - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, None) - - prop = Property('prop', typecast=float) - self.assertEqual(1.0, _typecast_prop_value(prop.typecast, 1)) - self.assertEqual(1.1, _typecast_prop_value(prop.typecast, 1.1)) - self.assertEqual(1.0, _typecast_prop_value(prop.typecast, '1')) - self.assertEqual(1.1, _typecast_prop_value(prop.typecast, '1.1')) - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, '') - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, None) - - prop = Property('prop', typecast=bool) - self.assertEqual(False, _typecast_prop_value(prop.typecast, 0)) - self.assertEqual(True, _typecast_prop_value(prop.typecast, 1)) - self.assertEqual(True, _typecast_prop_value(prop.typecast, 1.1)) - self.assertEqual(True, _typecast_prop_value(prop.typecast, '1')) - self.assertEqual(True, _typecast_prop_value(prop.typecast, 'false')) - self.assertEqual(False, _typecast_prop_value(prop.typecast, '')) - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, None) - - prop = Property('prop', typecast=[int]) - self.assertEqual((1,), _typecast_prop_value(prop.typecast, 1)) - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, None) - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, '') - self.assertEqual((), _typecast_prop_value(prop.typecast, [])) - self.assertEqual((123,), _typecast_prop_value(prop.typecast, '123')) - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, 'a') - self.assertEqual((123, 4, 5), _typecast_prop_value(prop.typecast, ['123', 4, 5.6])) - - prop = Property('prop', typecast=[1, 2]) - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, 0) - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, None) - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, '') - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, 'A') - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, '3') - self.assertEqual(1, _typecast_prop_value(prop.typecast, 1)) - self.assertEqual(2, _typecast_prop_value(prop.typecast, 2)) - self.assertEqual(1, _typecast_prop_value(prop.typecast, '1')) - - prop = Property('prop', typecast=[str]) - self.assertEqual(('',), _typecast_prop_value(prop.typecast, '')) - self.assertEqual(('',), _typecast_prop_value(prop.typecast, [''])) - self.assertEqual((), _typecast_prop_value(prop.typecast, [])) - - prop = Property('prop', typecast=[]) - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, None) - self.assertEqual(('',), _typecast_prop_value(prop.typecast, '')) - self.assertEqual(('',), _typecast_prop_value(prop.typecast, [''])) - self.assertEqual((), _typecast_prop_value(prop.typecast, [])) - self.assertEqual(('0',), _typecast_prop_value(prop.typecast, 0)) - self.assertEqual(('',), _typecast_prop_value(prop.typecast, '')) - self.assertEqual(('foo',), _typecast_prop_value(prop.typecast, 'foo')) - - prop = Property('prop', typecast=[['A', 'B', 'C']]) - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, '') - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, ['']) - self.assertEqual((), _typecast_prop_value(prop.typecast, [])) - self.assertEqual(('A', 'B', 'C'), _typecast_prop_value(prop.typecast, ['A', 'B', 'C'])) - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, ['a']) - self.assertRaises(ValueError, _typecast_prop_value, prop.typecast, ['A', 'x']) - - prop = Property('prop', typecast=bool) - self.assertEqual(True, _typecast_prop_value(prop.typecast, True)) - self.assertEqual(False, _typecast_prop_value(prop.typecast, False)) - self.assertEqual(True, _typecast_prop_value(prop.typecast, 'False')) - self.assertEqual(True, _typecast_prop_value(prop.typecast, '0')) - - prop = Property('prop', typecast=[['A', 'B', 'C']]) - self.assertEqual(('A', 'B', 'C'), _typecast_prop_value(prop.typecast, ['A', 'B', 'C'])) - - prop = Property('prop', typecast=lambda x: x + 1) - self.assertEqual(1, _typecast_prop_value(prop.typecast, 0)) + volume['document'].get(guid)['author']) def test_DefaultOrder(self): class Document(db.Resource): pass - self.volume = db.Volume('db', [Document]) + volume = db.Volume(tests.tmpdir, [Document]) + router = Router(db.Routes(volume)) - self.volume['document'].create({'guid': '3', 'ctime': 3}) - self.volume['document'].create({'guid': '2', 'ctime': 2}) - self.volume['document'].create({'guid': '1', 'ctime': 1}) + volume['document'].create({'guid': '3', 'ctime': 3}) + volume['document'].create({'guid': '2', 'ctime': 2}) + volume['document'].create({'guid': '1', 'ctime': 1}) self.assertEqual([ {'guid': '1'}, {'guid': '2'}, {'guid': '3'}, ], - self.call('GET', ['document'])['result']) + this.call(method='GET', path=['document'])['result']) - def test_SetDefaultPropsOnNoneValues(self): + def test_DefaultsOnNonePostValues(self): class Document(db.Resource): @@ -1645,10 +1655,11 @@ class RoutesTest(tests.Test): def prop(self, value): return value - self.volume = db.Volume('db', [Document]) + volume = db.Volume(tests.tmpdir, [Document]) + router = Router(db.Routes(volume)) - guid = self.call('POST', ['document'], content={'prop': None}) - self.assertEqual('default', self.volume['document'].get(guid).meta('prop')['value']) + guid = this.call(method='POST', path=['document'], content={'prop': None}) + self.assertEqual('default', this.call(method='GET', path=['document', guid, 'prop'])) def test_InsertAggprops(self): @@ -1658,117 +1669,316 @@ class RoutesTest(tests.Test): def prop1(self, value): return value - @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType(), acl=ACL.WRITE) - def prop2(self, value): - return value - - @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType(), acl=ACL.INSERT) + @db.stored_property(db.Aggregated, acl=ACL.INSERT) def prop3(self, value): return value events = [] - self.volume = db.Volume('db', [Document], lambda event: events.append(event)) - guid = self.call('POST', ['document'], content={}) + volume = db.Volume(tests.tmpdir, [Document]) + router = Router(db.Routes(volume)) + this.broadcast = lambda x: events.append(x) + guid = this.call(method='POST', path=['document'], content={}) - self.assertRaises(http.NotFound, self.call, 'POST', ['document', 'foo', 'bar'], content={}) - self.assertRaises(http.NotFound, self.call, 'POST', ['document', guid, 'bar'], content={}) - self.assertRaises(http.BadRequest, self.call, 'POST', ['document', guid, 'prop1'], content={}) - self.assertRaises(http.Forbidden, self.call, 'POST', ['document', guid, 'prop2'], content={}) + self.assertRaises(http.NotFound, this.call, method='POST', path=['document', 'foo', 'bar'], content={}) + self.assertRaises(http.NotFound, this.call, method='POST', path=['document', guid, 'bar'], content={}) + self.assertRaises(http.BadRequest, this.call, method='POST', path=['document', guid, 'prop1'], content={}) del events[:] self.override(time, 'time', lambda: 0) self.override(toolkit, 'uuid', lambda: '0') - self.assertEqual('0', self.call('POST', ['document', guid, 'prop3'], content={})) + self.assertEqual('0', this.call(method='POST', path=['document', guid, 'prop3'], content=0)) self.assertEqual({ - '0': {'seqno': 2}, + '0': {'seqno': 2, 'value': 0}, }, - self.volume['document'].get(guid)['prop3']) + volume['document'].get(guid)['prop3']) self.assertEqual([ {'event': 'update', 'resource': 'document', 'guid': guid}, ], events) self.override(time, 'time', lambda: 1) - self.assertEqual('1', self.call('POST', ['document', guid, 'prop3'], content={'guid': '1', 'foo': 'bar'})) + self.override(toolkit, 'uuid', lambda: '1') + self.assertEqual('1', this.call(method='POST', path=['document', guid, 'prop3'], content={'foo': 'bar'})) self.assertEqual({ - '0': {'seqno': 2}, - '1': {'seqno': 3, 'foo': 'bar'}, + '0': {'seqno': 2, 'value': 0}, + '1': {'seqno': 3, 'value': {'foo': 'bar'}}, }, - self.volume['document'].get(guid)['prop3']) + volume['document'].get(guid)['prop3']) self.override(time, 'time', lambda: 2) self.override(toolkit, 'uuid', lambda: '2') - self.assertEqual('2', self.call('POST', ['document', guid, 'prop3'], content={'prop': 'more'})) + self.assertEqual('2', this.call(method='POST', path=['document', guid, 'prop3'], content=None)) self.assertEqual({ - '0': {'seqno': 2}, - '1': {'seqno': 3, 'foo': 'bar'}, - '2': {'seqno': 4, 'prop': 'more'}, + '0': {'seqno': 2, 'value': 0}, + '1': {'seqno': 3, 'value': {'foo': 'bar'}}, + '2': {'seqno': 4, 'value': None}, }, - self.volume['document'].get(guid)['prop3']) + volume['document'].get(guid)['prop3']) def test_RemoveAggprops(self): class Document(db.Resource): - @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType(), acl=ACL.INSERT) + @db.stored_property(db.Aggregated, acl=ACL.INSERT) def prop1(self, value): return value - @db.stored_property(typecast=db.AggregatedType, default=db.AggregatedType(), acl=ACL.INSERT | ACL.REMOVE) + @db.stored_property(db.Aggregated, acl=ACL.INSERT | ACL.REMOVE) def prop2(self, value): return value events = [] - self.volume = db.Volume('db', [Document], lambda event: events.append(event)) - guid = self.call('POST', ['document'], content={}) + volume = db.Volume(tests.tmpdir, [Document]) + router = Router(db.Routes(volume)) + this.broadcast = lambda x: events.append(x) + guid = this.call(method='POST', path=['document'], content={}) - agg_guid = self.call('POST', ['document', guid, 'prop1'], content={'probe': 'value'}) + agg_guid = this.call(method='POST', path=['document', guid, 'prop1'], content=2) del events[:] self.assertEqual( - {agg_guid: {'seqno': 2, 'probe': 'value'}}, - self.volume['document'].get(guid)['prop1']) - self.assertRaises(http.Forbidden, self.call, 'DELETE', ['document', guid, 'prop1', agg_guid]) + {agg_guid: {'seqno': 2, 'value': 2}}, + volume['document'].get(guid)['prop1']) + self.assertRaises(http.Forbidden, this.call, method='DELETE', path=['document', guid, 'prop1', agg_guid]) self.assertEqual( - {agg_guid: {'seqno': 2, 'probe': 'value'}}, - self.volume['document'].get(guid)['prop1']) + {agg_guid: {'seqno': 2, 'value': 2}}, + volume['document'].get(guid)['prop1']) self.assertEqual([], events) - agg_guid = self.call('POST', ['document', guid, 'prop2'], content={'probe': 'value'}) + agg_guid = this.call(method='POST', path=['document', guid, 'prop2'], content=3) del events[:] self.assertEqual( - {agg_guid: {'seqno': 3, 'probe': 'value'}}, - self.volume['document'].get(guid)['prop2']) - self.call('DELETE', ['document', guid, 'prop2', agg_guid]) + {agg_guid: {'seqno': 3, 'value': 3}}, + volume['document'].get(guid)['prop2']) + this.call(method='DELETE', path=['document', guid, 'prop2', agg_guid]) self.assertEqual( {agg_guid: {'seqno': 4}}, - self.volume['document'].get(guid)['prop2']) + volume['document'].get(guid)['prop2']) + self.assertEqual([ + {'event': 'update', 'resource': 'document', 'guid': guid}, + ], + events) + + def test_FailOnAbsentAggprops(self): + + class Document(db.Resource): + + @db.stored_property(db.Aggregated, acl=ACL.INSERT | ACL.REMOVE | ACL.REPLACE) + def prop(self, value): + return value + + events = [] + volume = db.Volume(tests.tmpdir, [Document]) + router = Router(db.Routes(volume)) + this.broadcast = lambda x: events.append(x) + guid = this.call(method='POST', path=['document'], content={}) + del events[:] + + self.assertRaises(http.NotFound, this.call, method='DELETE', path=['document', guid, 'prop', 'absent']) + self.assertEqual([], events) + + def test_UpdateAggprops(self): + + class Document(db.Resource): + + @db.stored_property(db.Aggregated) + def prop1(self, value): + return value + + @db.stored_property(db.Aggregated, acl=ACL.INSERT | ACL.REMOVE | ACL.REPLACE) + def prop2(self, value): + return value + + events = [] + volume = db.Volume(tests.tmpdir, [Document]) + router = Router(db.Routes(volume)) + this.broadcast = lambda x: events.append(x) + guid = this.call(method='POST', path=['document'], content={}) + + agg_guid = this.call(method='POST', path=['document', guid, 'prop1'], content=1) + del events[:] + self.assertEqual( + {agg_guid: {'seqno': 2, 'value': 1}}, + volume['document'].get(guid)['prop1']) + self.assertRaises(http.Forbidden, this.call, method='PUT', path=['document', guid, 'prop1', agg_guid], content=2) + self.assertEqual( + {agg_guid: {'seqno': 2, 'value': 1}}, + volume['document'].get(guid)['prop1']) + self.assertEqual([], events) + + agg_guid = this.call(method='POST', path=['document', guid, 'prop2'], content=2) + del events[:] + self.assertEqual( + {agg_guid: {'seqno': 3, 'value': 2}}, + volume['document'].get(guid)['prop2']) + this.call(method='PUT', path=['document', guid, 'prop2', agg_guid], content=3) + self.assertEqual( + {agg_guid: {'seqno': 4, 'value': 3}}, + volume['document'].get(guid)['prop2']) + self.assertEqual([ + {'event': 'update', 'resource': 'document', 'guid': guid}, + ], + events) + + def test_PostAbsentAggpropsOnUpdate(self): + + class Document(db.Resource): + + @db.stored_property(db.Aggregated, acl=ACL.INSERT | ACL.REMOVE | ACL.REPLACE) + def prop(self, value): + return value + + events = [] + volume = db.Volume(tests.tmpdir, [Document]) + router = Router(db.Routes(volume)) + this.broadcast = lambda x: events.append(x) + guid = this.call(method='POST', path=['document'], content={}) + del events[:] + + this.call(method='PUT', path=['document', guid, 'prop', 'absent'], content='probe') + self.assertEqual( + {'absent': {'seqno': 2, 'value': 'probe'}}, + volume['document'].get(guid)['prop']) self.assertEqual([ {'event': 'update', 'resource': 'document', 'guid': guid}, ], events) - def call(self, method=None, path=None, - accept_language=None, content=None, content_stream=None, cmd=None, - content_type=None, host=None, request=None, routes=db.Routes, principal=None, - **kwargs): - if request is None: - environ = { - 'REQUEST_METHOD': method, - 'PATH_INFO': '/'.join([''] + path), - 'HTTP_ACCEPT_LANGUAGE': ','.join(accept_language or []), - 'HTTP_HOST': host, - 'wsgi.input': content_stream, - } - if content_type: - environ['CONTENT_TYPE'] = content_type - if content_stream is not None: - environ['CONTENT_LENGTH'] = str(len(content_stream.getvalue())) - request = Request(environ, cmd=cmd, content=content) - request.update(kwargs) - request.principal = principal - router = Router(routes(self.volume)) - self.response = Response() - return router._call_route(request, self.response) + def test_OriginalAggprops(self): + + class Document(db.Resource): + + @db.stored_property(db.Aggregated, acl=ACL.INSERT | ACL.REMOVE) + def prop(self, value): + return value + + volume = db.Volume(tests.tmpdir, [User, Document]) + router = Router(db.Routes(volume)) + volume['user'].create({'guid': 'user1', 'pubkey': '', 'name': 'User1'}) + volume['user'].create({'guid': 'user2', 'pubkey': '', 'name': 'User2'}) + + guid = this.call(method='POST', path=['document'], content={}, principal=tests.UID) + assert ACL.ORIGINAL & volume['document'][guid]['author'][tests.UID]['role'] + + agg_guid1 = this.call(method='POST', path=['document', guid, 'prop'], content=1, principal=tests.UID) + assert tests.UID2 not in volume['document'][guid]['prop'][agg_guid1]['author'] + assert ACL.ORIGINAL & volume['document'][guid]['prop'][agg_guid1]['author'][tests.UID]['role'] + + agg_guid2 = this.call(method='POST', path=['document', guid, 'prop'], content=1, principal=tests.UID2) + assert tests.UID not in volume['document'][guid]['prop'][agg_guid2]['author'] + assert not (ACL.ORIGINAL & volume['document'][guid]['prop'][agg_guid2]['author'][tests.UID2]['role']) + + this.call(method='DELETE', path=['document', guid, 'prop', agg_guid2], principal=tests.UID2) + assert tests.UID not in volume['document'][guid]['prop'][agg_guid2]['author'] + assert not (ACL.ORIGINAL & volume['document'][guid]['prop'][agg_guid2]['author'][tests.UID2]['role']) + + def test_AggregatedBlobs(self): + + class Document(db.Resource): + + @db.stored_property(db.Aggregated, subtype=db.Blob()) + def blobs(self, value): + return value + + volume = db.Volume(tests.tmpdir, [Document]) + router = Router(db.Routes(volume)) + guid = this.call(method='POST', path=['document'], content={}) + + agg1 = this.call(method='POST', path=['document', guid, 'blobs'], content='blob1') + self.assertEqual({ + agg1: {'seqno': 2, 'value': str(hash('blob1'))}, + }, + volume['document'].get(guid)['blobs']) + assert files.get(str(hash('blob1'))) + + agg2 = this.call(method='POST', path=['document', guid, 'blobs'], content='blob2') + self.assertEqual({ + agg1: {'seqno': 2, 'value': str(hash('blob1'))}, + agg2: {'seqno': 3, 'value': str(hash('blob2'))}, + }, + volume['document'].get(guid)['blobs']) + assert files.get(str(hash('blob2'))) + + this.call(method='DELETE', path=['document', guid, 'blobs', agg1]) + self.assertEqual({ + agg1: {'seqno': 4}, + agg2: {'seqno': 3, 'value': str(hash('blob2'))}, + }, + volume['document'].get(guid)['blobs']) + assert files.get(str(hash('blob1'))) is None + assert files.get(str(hash('blob2'))) + + this.call(method='DELETE', path=['document', guid, 'blobs', agg2]) + self.assertEqual({ + agg1: {'seqno': 4}, + agg2: {'seqno': 5}, + }, + volume['document'].get(guid)['blobs']) + assert files.get(str(hash('blob1'))) is None + assert files.get(str(hash('blob2'))) is None + + agg3 = this.call(method='POST', path=['document', guid, 'blobs'], content='blob3') + self.assertEqual({ + agg1: {'seqno': 4}, + agg2: {'seqno': 5}, + agg3: {'seqno': 6, 'value': str(hash('blob3'))}, + }, + volume['document'].get(guid)['blobs']) + assert files.get(str(hash('blob1'))) is None + assert files.get(str(hash('blob2'))) is None + assert files.get(str(hash('blob3'))) + + def test_AggregatedSearch(self): + + class Document(db.Resource): + + @db.stored_property(db.Aggregated, prefix='A', full_text=True) + def comments(self, value): + return value + + @db.stored_property(prefix='B', full_text=False, default='') + def prop(self, value): + return value + + volume = db.Volume(tests.tmpdir, [Document]) + router = Router(db.Routes(volume)) + + guid1 = this.call(method='POST', path=['document'], content={}) + this.call(method='POST', path=['document', guid1, 'comments'], content='a') + this.call(method='POST', path=['document', guid1, 'comments'], content='b') + this.call(method='PUT', path=['document', guid1, 'prop'], content='c') + + guid2 = this.call(method='POST', path=['document'], content={}) + this.call(method='POST', path=['document', guid2, 'comments'], content='c') + this.call(method='POST', path=['document', guid2, 'comments'], content='a') + this.call(method='PUT', path=['document', guid2, 'prop'], content='b') + + guid3 = this.call(method='POST', path=['document'], content={}) + this.call(method='POST', path=['document', guid3, 'comments'], content='a c') + this.call(method='POST', path=['document', guid3, 'comments'], content='b d') + this.call(method='PUT', path=['document', guid3, 'prop'], content='e') + + self.assertEqual( + sorted([guid1, guid2, guid3]), + sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='a')['result']])) + self.assertEqual( + sorted([guid1, guid3]), + sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='b')['result']])) + self.assertEqual( + sorted([guid2, guid3]), + sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='c')['result']])) + self.assertEqual( + sorted([]), + sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='absent')['result']])) + + self.assertEqual( + sorted([guid1, guid2, guid3]), + sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='comments:a')['result']])) + self.assertEqual( + sorted([guid1, guid3]), + sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='comments:b')['result']])) + self.assertEqual( + sorted([guid2, guid3]), + sorted([i['guid'] for i in this.call(method='GET', path=['document'], query='comments:c')['result']])) if __name__ == '__main__': diff --git a/tests/units/db/storage.py b/tests/units/db/storage.py index 6eb62e5..bb61f8a 100755 --- a/tests/units/db/storage.py +++ b/tests/units/db/storage.py @@ -11,8 +11,7 @@ from os.path import exists from __init__ import tests -from sugar_network.db.metadata import Metadata, StoredProperty -from sugar_network.db.metadata import BlobProperty +from sugar_network.db.metadata import Metadata, Property from sugar_network.db.storage import Storage from sugar_network.toolkit import BUFFER_SIZE @@ -30,7 +29,7 @@ class StorageTest(tests.Test): return Storage(tests.tmpdir, metadata) def test_Record_get(self): - storage = self.storage([StoredProperty('prop')]) + storage = self.storage([Property('prop')]) self.assertEqual(None, storage.get('guid').get('prop')) self.touch(('gu/guid/prop', json.dumps({ @@ -45,7 +44,7 @@ class StorageTest(tests.Test): storage.get('guid').get('prop')) def test_Record_set(self): - storage = self.storage([StoredProperty('prop')]) + storage = self.storage([Property('prop')]) storage.get('guid').set('prop', value='value', foo='bar') self.assertEqual({ @@ -56,7 +55,7 @@ class StorageTest(tests.Test): storage.get('guid').get('prop')) def test_delete(self): - storage = self.storage([StoredProperty('prop')]) + storage = self.storage([Property('prop')]) assert not exists('ab/absent') storage.delete('absent') @@ -69,8 +68,8 @@ class StorageTest(tests.Test): def test_Record_consistent(self): storage = self.storage([ - StoredProperty('guid'), - StoredProperty('prop'), + Property('guid'), + Property('prop'), ]) record = storage.get('guid') @@ -83,7 +82,7 @@ class StorageTest(tests.Test): self.assertEqual(True, record.consistent) def test_walk(self): - storage = self.storage([StoredProperty('guid')]) + storage = self.storage([Property('guid')]) storage.get('guid1').set('guid', value=1, mtime=1) storage.get('guid2').set('guid', value=2, mtime=2) @@ -107,8 +106,8 @@ class StorageTest(tests.Test): def test_walk_SkipGuidLess(self): storage = self.storage([ - StoredProperty('guid'), - StoredProperty('prop'), + Property('guid'), + Property('prop'), ]) record = storage.get('guid1') |