def test_forwardCalls(self): cb = ContextBroker() fwdCalls = { 'getToi': 1, 'addToi': 1, 'createToi': 3, 'changeToi': 2, 'deleteToi': 1, 'register': 1, 'runQuery': 1, 'requestAttribute': 2, 'callMethod': 1, 'newId': 0, } callCollector = CallCollector() cb.pushContext(callCollector) expected = [] for call, argN in fwdCalls.items(): args = tuple(object() for i in range(argN)) retVal = getattr(cb, call)(*args) expected.append((call, args, {}, retVal)) assert callCollector.calls == expected
def test_popContext_returnValOk(self): cb = ContextBroker() ctx = object() cb.pushContext(ctx) assert cb.context is ctx assert cb.popContext() is ctx
def test_otherThread_startsEmpty(self): cb = ContextBroker() ctx = object() cb.pushContext(ctx) def getContext(): return cb.context py.test.raises(LookupError, runInThread, 1.0, getContext)
def test_effectOfPopContextOk(self): cb = ContextBroker() py.test.raises(IndexError, cb.popContext) ctx1 = object() ctx2 = object() cb.pushContext(ctx1) cb.pushContext(ctx2) assert cb.context is ctx2 assert cb.popContext() is ctx2 assert cb.context is ctx1
def test_rerun_conflicting_commit(self): toi = blm.testcommit.Test(name=['foo']) self.sync() assert self.find_one({'_id': toi.id[0]}) cctx = self.newcontext() op = commit.CallToi(toi.id[0], 'add', [['bar']]) commitId = cctx.runCommit([op], processCommits=False) ContextBroker().popContext() toi.extra = ['conflict'] self.sync() _rerunCommit = cctx.rerunCommit def rerunCommit(*args, **kw): db_toi_data = self.find_one({'_id': toi.id[0]}) assert db_toi_data.get('_terms', []) == [] return _rerunCommit(*args, **kw) cctx.rerunCommit = rerunCommit cctx.processCommits(commitId) self.sync() cctx = self.newcontext() toi, = blm.testcommit.Test._query().run() assert toi.extra == ['conflict', 'bar'] db_toi_data = self.find_one({'_id': toi.id[0]}) py.test.skip('full text index disabled for now') assert db_toi_data['_terms'] == [{ 'toid': toi.id[0], 'data': ['bar', 'conflict'] }]
def test_runAfterCommitFailing(self): py.test.xfail("post-commit hooks not supported") callbackCalled = [] def callback(tid, *args, **kw): callbackCalled.append((tid, args, kw)) raise RuntimeError('error') def callback2(tid, *args, **kw): callbackCalled.append((tid, args, kw)) class Op(commit.OperateBase): def checkPermissions(self, context): pass def operate(self, context): context.runAfterCommit(callback, 42, foo='bar') context.runAfterCommit(callback2, 43) cctx = commit.CommitContext(self.database) ContextBroker().pushContext(cctx) cctx.setMayChange(True) results = cctx.runCommit([Op()]) assert callbackCalled == [(None, (42, ), { 'foo': 'bar' }), (None, (43, ), {})]
def newcontext(self, user=None): if user is None: user = self.user ctx = commit.CommitContext(self.database, user) ctx.setMayChange(True) ContextBroker().pushContext(ctx) return ctx
def test_otherThread_pushContext(self): cb = ContextBroker() ctx = object() def check_pushContext(): cb.pushContext(ctx) assert cb.context is ctx assert cb.popContext() is ctx runInThread(1.0, check_pushContext)
def test_notifyChanges_being_called(self): result = [] def notifyChanges(commits): result.append([c._id for c in commits]) cctx = self.newcontext() cctx.id = None # cheat - pretend that this commit is unhandled commit1 = cctx.createCommit([], []) commit1.save(self.database) ContextBroker().popContext() cctx = self.newcontext() commit2 = cctx.createCommit([], []) ContextBroker().popContext() cctx.notifyChanges = notifyChanges cctx.processCommits(commit2) expected = [[commit2._id, commit1._id]] assert result == expected
def test_with_no_context(self): py.test.raises(Exception, lambda: ContextBroker().context) # sanity database = object() @context.maybe_with_context() def foo(arg): assert isinstance(ContextBroker().context, context.ReadonlyContext) assert ContextBroker().context.database is database return arg obj = object() assert foo(obj, database=database) is obj
def test_createToi(self): cctx = self.newcontext() toi = cctx.createToi(blm.testcommit.Test, cctx.newId(), {'name': ['test']}) assert toi.name == ['test'] assert toi.__class__._query(name='test').run()[0] is toi assert self.find({'_toc': 'testcommit.Test'}).count() == 0 ContextBroker().popContext() cctx.runCommit([]) assert self.find({'_toc': 'testcommit.Test'}).count() == 1
def test_canWrite_new_toi(self): user = blm.fundamental.AccessHolder() cctx = self.newcontext(user=user) toi = cctx.createToi(blm.testcommit.Test, cctx.newId(), {'name': ['test']}) self.sync() assert toi.name == ['test'] assert toi.__class__._query(name='test').run()[0] is toi assert self.find({'_toc': 'testcommit.Test'}).count() == 0 ContextBroker().popContext() cctx.runCommit([]) assert self.find({'_toc': 'testcommit.Test'}).count() == 1
def setuid(user=None): context = ContextBroker().context current = context.user context.setUser(user) try: yield finally: context.setUser(current)
def _commit(self, interested=None, _id=ObjectId(), operations=[], result=[['result'], 42], error=None): toiToDelete = blm.testcommit.Test(name=['baz']) toiToChange = blm.testcommit.Test(name=['foo']) cctx = self.newcontext() toiToCreate = blm.testcommit.Test(name=['bar']) new = DiffTOI() new.setToi(toiToCreate) changed = DiffTOI() changed.setAttrDiff(toiToChange.__class__, toiToChange.id[0], toiToChange._attrData, {'name': ['apa']}) doc = { '_id': _id, 'newTois': [new], 'changedTois': [changed], 'deletedTois': [toiToDelete.id[0]], 'operations': operations, 'addedBlobVals': {}, 'deletedBlobVals': {}, 'results': result, 'error': error, 'indexData': [], 'handled_by': cctx.id, 'user': cctx.user, 'interested': interested } commitId = mongo.insert(self.database.commits, doc) assert commitId self.sync() ContextBroker().popContext() assert self.find_one({'_id': toiToChange.id[0]})['name'] == ['foo'] assert not self.find_one({'_id': toiToCreate.id[0]}) assert self.find_one({'_id': toiToDelete.id[0]}) cctx.commit(commit.Commit.fromquery(self.database, {'_id': commitId})) self.sync() assert self.find_one({'_id': toiToChange.id[0]})['name'] == ['apa'] assert self.find_one({'_id': toiToCreate.id[0]}) assert not self.find_one({'_id': toiToDelete.id[0]}) return commitId
def test_deleteToi(self): toi = blm.testcommit.Test(name=['text']) print(toi, toi.__class__) self.sync() cctx = self.newcontext() toi, = blm.testcommit.Test._query().run() toi._delete() print(toi, toi.__class__) assert toi.__class__._query().run() == [] self.sync() assert self.find({'_toc': 'testcommit.Test'}).count() == 1 ContextBroker().popContext() cctx.runCommit([]) assert self.find({'_toc': 'testcommit.Test'}).count() == 0
def _run(self, params, state): tois = ContextBroker().runQuery(params['criteria']) result = dict([(str(t.id[0]), t._fullname) for t in tois]) update = None if result != state: state = state or {} added = dict(item for item in list(result.items()) if item not in list(state.items())) deleted = dict(item for item in list(state.items()) if item not in list(result.items())) update = { 'add' : added, 'del' : deleted, 'relevance' : None, 'error' : None } persistent = params.get('subscription') self.update(update, persistent=persistent) if persistent: self.save(params, result)
def test_changeToi(self): toi = blm.testcommit.Test(name=['test']) self.sync() cctx = self.newcontext() # New context, so we have to look it up again toi = blm.testcommit.Test._query().run()[0] toi(extra=['fOo']) assert toi.extra == ['fOo'] assert toi.__class__._query(extra='fOo').run()[0] is toi assert toi.__class__._query(extra=None).run() == [] dbtoi, = list(self.database.tois.find({'_toc': 'testcommit.Test'})) assert dbtoi.get('extra', []) == [] ContextBroker().popContext() cctx.runCommit([]) dbtoi, = list(self.database.tois.find({'_toc': 'testcommit.Test'})) assert dbtoi['extra'] == ['fOo']
def test_changeToi_with_nop_change(self): toi = blm.testcommit.Test(name=['test']) self.sync() cctx = self.newcontext() # New context, so we have to look it up again toi = blm.testcommit.Test._query(_attrList=['name']).run()[0] toi(name=['fOo']) assert toi.name == ['fOo'] assert toi.__class__._query(name='fOo').run()[0] is toi assert toi.__class__._query(name=None).run() == [] dbtoi, = list(self.database.tois.find({'_toc': 'testcommit.Test'})) assert dbtoi.get('extra', []) == [] toi(name=['test']) # Restore to original value ContextBroker().popContext() commit = cctx.runCommit([]) assert commit.state != 'failed' dbtoi, = list(self.database.tois.find({'_toc': 'testcommit.Test'})) assert dbtoi['name'] == ['test']
def __enter__(self): ContextBroker().pushContext(self) return self
def foo(): assert isinstance(ContextBroker().context, MyContext)
def foo(arg): assert isinstance(ContextBroker().context, context.ReadonlyContext) assert ContextBroker().context.database is database return arg
def teardown_method(self, method): super(TestBlobVal, self).teardown_method(method) ContextBroker().popContext()
def setup_method(self, method): super(TestBlobVal, self).setup_method(method) class FakeContext(object): database = self.database ContextBroker().pushContext(FakeContext())
def test_pushContext(self): cb = ContextBroker() ctx = object() cb.pushContext(ctx) assert cb.context is ctx
def test_popEmpty(self): cb = ContextBroker() py.test.raises(IndexError, lambda: cb.popContext())
def test_singleton(self): "Enshures that the ContextBroker is a singleton." assert ContextBroker() is ContextBroker()
def __exit__(self, exc_type, exc_val, exc_tb): assert ContextBroker().context == self ContextBroker().popContext()
class TestAttribute(object): BASIC_VALUE_TESTS = ( (Bool, (True, False, None)), (Blob, ('good float', False, None)), (Decimal, (decimal.Decimal('0.0'), 'bad decimal', DecimalValueError)), (DecimalMap, (('somekey', decimal.Decimal('1.0')), ('somekey', 'bad val'), DecimalValueError)), (DecimalMap, (('somekey', '1.0'), (None, 1), StringValueError)), (DecimalMap, (('somekey', 1), 42, TypeError)), (Float, (1.0, 'bad float', FloatValueError)), (Int, (1, 'bad int', IntValueError)), (Int, ('1', False, None)), (Int, (1, False, None)), (IntMap, (('somekey', 1), ('somekey', 'bad val'), IntValueError)), (IntMap, (('somekey', '1'), (None, 1), StringValueError)), (IntMap, (('somekey', 1), 42, TypeError)), (String, ('good string', False, None)), (String, (my_unicode('foo'), False, None)), (LimitedString, ('god limited string', False, None)), (Timespan, (1, 'bad timespan', TimespanValueError)), (TimespanMap, (('somekey', 1), ('somekey', 'bad val'), TimespanValueError)), (TimespanMap, (('somekey', '1'), (None, 1), StringValueError)), (TimespanMap, (('somekey', 1), 42, TypeError)), (Timestamp, (1, 'bad timestamp', TimestampValueError)), (TimestampMap, (('somekey', 1), ('somekey', 'bad val'), TimestampValueError)), (TimestampMap, (('somekey', '1'), (None, 1), StringValueError)), (TimestampMap, (('somekey', 1), 42, TypeError)), ) cb = ContextBroker() def setup_method(self, method): # Erase leftovers from previous tests... self.cb.contextDict.clear() self.context = FakeContext() self.cb.pushContext(self.context) def teardown_method(self, method): self.cb.contextDict.clear() def test_AttributeInherited(self): "Tests that Attribute has to be derived to be used" def spam(): class dummyAttr(Attribute()): spam raises(SyntaxError, spam) def test_ModifierInheritance(self): "Tests that attributes only can inherit Modifiers" def spam(): class foo(object): pass class bar(Int(foo())): pass raises(TypeError, spam) def test_AttributeSimple(self): "Tests a simple attribute declaration" class spam(Attribute): pass def test_ModifierValidity(self): "Tests that a modifier has to be applicable to be inherited" def spam(): class dummyRest(Restriction): pass class dummyAttr(Int()): pass class foo(dummyAttr(dummyRest())): pass raises(TypeError, spam) def test_ToiDeleted(self): class FakeToi(object): _deleted = True _fullname = 'FakeToi' id = [27] attr = Attribute._instantiate('attr') _xlatKey = 'FakeToi' toi = FakeToi() raises(ToiDeletedError, setattr, toi, 'attr', ['bar']) attr = toi.attr raises(ToiDeletedError, getattr, attr, 'value') def check_createOk(self, AttrClass): "Tests that attributes can be constructed and instantiated." class AttrDeriv(AttrClass()): pass AttrDeriv._instantiate('attr') def check_typeOk(self, attr, valueOk): "Tests that attribute instances accept a correct value." return attr.coerceValueList((valueOk,)) def _badValue_reRaise(self, attr, badVal): """ Feeds an incorrect value to the typechecking of an Attribute, extracts the underlaying type error and re-raises that error. """ try: attr.coerceValueList((badVal,)) except CapsAttributeError as e: realE = e.error.args[0][1] raise realE.__class__(realE) def check_type_notOk(self, attr, valueNotOk, error): "Tests that attribute type checks raises on incorrect values." raises(error, self._badValue_reRaise, attr, valueNotOk) def check_equals(self, AttrDeriv, value): class FakeToi(object): _deleted = False def __init__(self, **attrData): self._attrData = attrData attr1 = AttrDeriv._instantiate('attr1') attr2 = AttrDeriv._instantiate('attr2') attr3 = AttrDeriv._instantiate('attr3') toi = FakeToi(attr1=[value], attr2=[value], attr3=[value, value]) attr1.toi = attr2.toi = attr3.toi = toi assert attr1 == attr2 assert not (attr1 != attr2) assert attr1 != attr3 assert not (attr1 == attr3) def test_Attribute_basics(self): "Yields tests that perform sanity tests on Attribute's." for AttrClass, (valueOk, valueNotOk, excType) in self.BASIC_VALUE_TESTS: yield self.check_createOk, AttrClass class AttrDeriv(AttrClass()): pass attr = AttrDeriv._instantiate('attr') attr2 = AttrDeriv._instantiate('attr2') yield self.check_typeOk, attr, valueOk yield self.check_equals, AttrDeriv, valueOk if valueNotOk: yield self.check_type_notOk, attr, valueNotOk, excType def test_SingleInheritance(self): "Test that an attribute only can inherit ONE base attribute type" def spam(): class dummyAttr(Bool(), Bool()): pass raises(SyntaxError, spam) def test_Enum(self): "Tests the Enum attribute" class spam(Enum()): values = ('foo', 'bar') pass def helpValueError(self, classOb, val, err): class foo(object): ob = type.__call__(classOb(), 'bar') bar = foo() try: # if err is None: # import pdb; pdb.set_trace() bar.ob.coerceValueList(val) except AttrValueError as l: return isinstance(l.args[3].args[0][1], err) assert not err return True def test_EnumTypechecking(self): "Tests the Enum attribute value typechecking" class spam(Enum()): values = ('foo', 'bar') y = type.__call__(spam, 'spam') assert self.helpValueError(spam, ('spam',), EnumValueError) assert self.helpValueError(spam, (y.foo,), None) def test_EnumIterator(self): "Tests the Enum iterator functionality" class spam(Enum()): values = ('foo', 'bar', 'moo', 'guu') y = type.__call__(spam, 'spam') rList = [] for i in y: rList.append(i) assert rList == list(spam.values) def test_ToiRef(self): "Tests the ToiRef attribute" class FakeToc(TO): _deleted = False class spam(ToiRef()): pass toi = FakeToc(ObjectId()) ref = FakeToc(ObjectId()) toi.spam = [ref] assert toi.spam == [ref] id = ObjectId() self.context.requestAttribute = lambda toi, attr: {'spam': [id]}[attr.name] assert len(ref.spam) == 1 assert ref.spam[0].id[0] == id def test_defaultEnum(self): "Tests the enum defaults" class spam(Enum()): values = ('foo', 'bar') default = 'bar' y = type.__call__(spam, 'spam') assert y.default[0] == y.bar def test_enumSubclassWithDefault(self): class spam(Enum()): values = ('foo', 'bar') class spam2(spam()): default = 'bar' y = type.__call__(spam2, 'spam') assert y.default[0] == y.bar def test_ToiRefTypechecking(self): "Tests the ToiRef attribute value typechecking" class spam(ToiRef()): pass assert self.helpValueError(spam, ('spam',), ToiRefValueError) assert self.helpValueError(spam, (object(),), ToiRefValueError) assert self.helpValueError(spam, (42,), ToiRefValueError) assert self.helpValueError(spam, (str(ObjectId()),), ToiRefValueError) assert self.helpValueError(spam, (ObjectId(),), ToiRefValueError) assert self.helpValueError(spam, (TO(),), None) def test_ToiRefMapTypechecking(self): "Tests the ToiRef attribute value typechecking" class spam(ToiRefMap()): pass assert self.helpValueError(spam, (('foo', 'spam'),), ToiRefValueError) assert self.helpValueError(spam, (('foo', object()),), ToiRefValueError) assert self.helpValueError(spam, (('foo', 42),), ToiRefValueError) assert self.helpValueError(spam, (('foo', str(ObjectId())),), ToiRefValueError) assert self.helpValueError(spam, (('foo', ObjectId()),), ToiRefValueError) assert self.helpValueError(spam, (('foo', TO()),), None) def test_Map_get(self): class FakeToc(TO): _deleted = False class spam(IntMap()): pass toi = FakeToc(ObjectId()) self.context.requestAttribute = lambda toi, attr: {'spam': {'foo': 2}}[attr.name] assert toi.spam.get('foo') == 2 assert toi.spam.get('bar', 3) == 3 def test_Map_dictlike(self): class FakeToc(TO): _deleted = False class spam(IntMap()): pass toi = FakeToc(ObjectId()) self.context.requestAttribute = lambda toi, attr: {'spam': {'foo': 2, 'bar': 3}}[attr.name] d = {'foo': 2, 'bar': 3} assert list(toi.spam.keys()) == list(d.keys()) assert list(toi.spam.items()) == list(d.items()) assert list(toi.spam.values()) == list(d.values()) def test_Relation(self): "Tests the Relation attribute" class spam(Relation()): pass def test_validateValues(self): class FakeToc(TO): _deleted = False class spam(Int(Range(1, 10))): pass toi = FakeToc(ObjectId()) raises(AttrValueError, toi.spam.validateValues, value=[27]) def test_validateValues_MapAttr(self): class FakeToc(TO): _deleted = False class spam(IntMap(Range(1, 10))): pass toi = FakeToc(ObjectId()) raises(AttrValueError, toi.spam.validateValues, value={'1': 27}) toi.spam.validateValues(value={'1': 10}) def test_empty(self): class FakeToc(TO): class int(Int()): default = [1] class intmap(IntMap()): default = {'foo': 1} assert FakeToc.int.empty == [] assert FakeToc.intmap.empty == {} def test_on_computation(self): class FakeToc(TO): class int(Int()): def on_computation(attr, toi): return [27] toi = FakeToc() assert toi.int == [27] def test_attribute_copying(self): class FakeToc(TO): class int(Int()): pass class indirect(Int()): def on_computation(attr, toi): return toi.int toi1 = FakeToc() toi2 = FakeToc() toi1.int = [27] toi2.int = toi1.int assert toi1.int == toi2.int == [27] toi2.int = [0] # this tests that attribute unpacking in Attribute.__set__ # unpacks all levels of attributes, not just the first toi2.int = toi1.indirect assert toi2.int == [27] def test_add(self): class FakeToc(TO): class int(Int()): pass toi = FakeToc() toi.int.add(1) assert toi.int == [1] toi.int.add(1) assert toi.int == [1] toi.int.add(2) assert toi.int == [1, 2] def test_discard(self): class FakeToc(TO): class int(Int()): pass toi = FakeToc() toi.int = [1, 2] toi.int.discard(2) assert toi.int == [1] toi.int.discard(3) assert toi.int == [1]
def foo(): return ContextBroker().context
def test_startsEmpty(self): py.test.raises(LookupError, lambda: ContextBroker().context)