示例#1
0
    def get_by_sid(cls, sid):
        """Returns a ``Session`` instance by session id.

        :param sid:
            A session id.
        :returns:
            An existing ``Session`` entity.
        """
        data = memcache.get(sid)
        if not data:
            session = model.Key(cls, sid).get()
            if session:
                data = session.data
                memcache.set(sid, data)

        return data
示例#2
0
    def get_key(cls, user, subject, token):
        """Returns a token key.

        :param user:
            User unique ID.
        :param subject:
            The subject of the key. Examples:

            - 'auth'
            - 'signup'
        :param token:
            Randomly generated token.
        :returns:
            ``model.Key`` containing a string id in the following format:
            ``{user_id}.{subject}.{token}.``
        """
        return model.Key(cls, '%s.%s.%s' % (str(user), subject, token))
示例#3
0
    def testContext_TransactionRollback(self):
        key = model.Key('Foo', 1)

        @tasklets.tasklet
        def foo():
            ent = model.Expando(key=key, bar=1)

            @tasklets.tasklet
            def callback():
                ctx = tasklets.get_context()
                key = yield ent.put_async()
                raise model.Rollback()

            yield self.ctx.transaction(callback)

        foo().check_success()
        self.assertEqual(key.get(), None)
示例#4
0
    def create(cls, value):
        """Creates a new unique value.

        :param value:
            The value to be unique, as a string.

            The value should include the scope in which the value must be
            unique (ancestor, namespace, kind and/or property name).

            For example, for a unique property `email` from kind `User`, the
            value can be `User.email:[email protected]`. In this case `User.email`
            is the scope, and `[email protected]` is the value to be unique.
        :returns:
            True if the unique value was created, False otherwise.
        """
        entity = cls(key=model.Key(cls, value))
        txn = lambda: entity.put() if not entity.key.get() else None
        return model.transaction(txn) is not None
示例#5
0
def memoizing_fibonacci(n):
    """A memoizing recursive Fibonacci to exercise RPCs."""
    if n <= 1:
        raise tasklets.Return(n)
    key = model.Key(FibonacciMemo, str(n))
    memo = yield key.get_async(ndb_should_cache=False)
    if memo is not None:
        assert memo.arg == n
        logging.info('memo hit: %d -> %d', n, memo.value)
        raise tasklets.Return(memo.value)
    logging.info('memo fail: %d', n)
    a = yield memoizing_fibonacci(n - 1)
    b = yield memoizing_fibonacci(n - 2)
    ans = a + b
    memo = FibonacciMemo(key=key, arg=n, value=ans)
    logging.info('memo write: %d -> %d', n, memo.value)
    yield memo.put_async(ndb_should_cache=False)
    raise tasklets.Return(ans)
示例#6
0
    def testUnindexedProperty(self):
        class MyModel(model.Model):
            t = model.TextProperty()
            b = model.BlobProperty()

        ent = MyModel()
        MyModel.t._set_value(ent, u'Hello world\u1234')
        MyModel.b._set_value(ent, '\x00\xff')
        self.assertEqual(MyModel.t._get_value(ent), u'Hello world\u1234')
        self.assertEqual(MyModel.b._get_value(ent), '\x00\xff')
        pb = ent._to_pb()
        self.assertEqual(str(pb), UNINDEXED_PB)

        ent = MyModel._from_pb(pb)
        self.assertEqual(ent._get_kind(), 'MyModel')
        k = model.Key(flat=['MyModel', None])
        self.assertEqual(ent.key, k)
        self.assertEqual(MyModel.t._get_value(ent), u'Hello world\u1234')
        self.assertEqual(MyModel.b._get_value(ent), '\x00\xff')
示例#7
0
    def testValidation(self):
        class All(model.Model):
            s = model.StringProperty()
            i = model.IntegerProperty()
            f = model.FloatProperty()
            t = model.TextProperty()
            b = model.BlobProperty()
            k = model.KeyProperty()

        BVE = datastore_errors.BadValueError
        a = All()

        a.s = None
        a.s = 'abc'
        a.s = u'def'
        a.s = '\xff'  # Not UTF-8.
        self.assertRaises(BVE, setattr, a, 's', 0)

        a.i = None
        a.i = 42
        a.i = 123L
        self.assertRaises(BVE, setattr, a, 'i', '')

        a.f = None
        a.f = 42
        a.f = 3.14
        self.assertRaises(BVE, setattr, a, 'f', '')

        a.t = None
        a.t = 'abc'
        a.t = u'def'
        a.t = '\xff'  # Not UTF-8.
        self.assertRaises(BVE, setattr, a, 't', 0)

        a.b = None
        a.b = 'abc'
        a.b = '\xff'
        self.assertRaises(BVE, setattr, a, 'b', u'')
        self.assertRaises(BVE, setattr, a, 'b', u'')

        a.k = None
        a.k = model.Key('Foo', 42)
        self.assertRaises(BVE, setattr, a, 'k', '')
示例#8
0
    def testModelRepr(self):
        class Address(model.Model):
            street = model.StringProperty()
            city = model.StringProperty()

        class Person(model.Model):
            name = model.StringProperty()
            address = model.StructuredProperty(Address)

        p = Person(name='Google',
                   address=Address(street='345 Spear', city='SF'))
        self.assertEqual(
            repr(p),
            "Person(address=Address(city='SF', street='345 Spear'), name='Google')"
        )
        p.key = model.Key(pairs=[('Person', 42)])
        self.assertEqual(
            repr(p), "Person(key=Key('Person', 42), "
            "address=Address(city='SF', street='345 Spear'), name='Google')")
示例#9
0
 def _hp_callback(self, message):
     nickname = 'Anonymous'
     if message.userid:
         nickname = yield get_nickname(message.userid)
     # Check if there's an URL.
     body = message.body
     m = re.search(r'(?i)\bhttps?://\S+[^\s.,;\]\}\)]', body)
     if not m:
         escbody = cgi.escape(body)
     else:
         url = m.group()
         pre = body[:m.start()]
         post = body[m.end():]
         title = ''
         key = model.Key(flat=[UrlSummary.GetKind(), url])
         summary = yield key.get_async()
         if not summary or summary.when < time.time() - UrlSummary.MAX_AGE:
             rpc = urlfetch.create_rpc(deadline=0.5)
             urlfetch.make_fetch_call(rpc, url, allow_truncated=True)
             t0 = time.time()
             result = yield rpc
             t1 = time.time()
             logging.warning('url=%r, status=%r, dt=%.3f', url,
                             result.status_code, t1 - t0)
             if result.status_code == 200:
                 bodytext = result.content
                 m = re.search(r'(?i)<title>([^<]+)</title>', bodytext)
                 if m:
                     title = m.group(1).strip()
                 summary = UrlSummary(key=key,
                                      url=url,
                                      title=title,
                                      when=time.time())
                 yield summary.put_async()
         hover = ''
         if summary.title:
             hover = ' title="%s"' % summary.title
         escbody = (cgi.escape(pre) + '<a%s href="%s">' %
                    (hover, cgi.escape(url)) + cgi.escape(url) + '</a>' +
                    cgi.escape(post))
     text = '%s - %s - %s<br>' % (cgi.escape(nickname),
                                  time.ctime(message.when), escbody)
     raise tasklets.Return((-message.when, text))
示例#10
0
    def testMultipleInStructuredProperty(self):
        class Address(model.Model):
            label = model.StringProperty()
            line = model.StringProperty(repeated=True)

        class Person(model.Model):
            name = model.StringProperty()
            address = model.StructuredProperty(Address)

        m = Person(name='Google',
                   address=Address(label='work',
                                   line=['345 Spear', 'San Francisco']))
        m.key = model.Key(flat=['Person', None])
        self.assertEqual(m.address.line, ['345 Spear', 'San Francisco'])
        pb = m._to_pb()
        self.assertEqual(str(pb), MULTIINSTRUCT_PB)

        m2 = Person._from_pb(pb)
        self.assertEqual(m2, m)
示例#11
0
    def get_by_refresh_token(cls, user_id, token):
        """Returns a user object based on a user ID and token.

        :param user_id:
            The user_id of the requesting user.
        :param token:
            The token string to be verified.
        :returns:
            A tuple ``(User, timestamp)``, with a user object and
            the token timestamp, or ``(None, None)`` if both were not found.
        """
        token_key = cls.token_model.get_key(user_id, 'refresh', token)
        user_key = model.Key(cls, user_id)
        # Use get_multi() to save a RPC call.
        valid_token, user = model.get_multi([token_key, user_key])
        if valid_token and user:
            timestamp = int(time.mktime(valid_token.created.timetuple()))
            return user, timestamp

        return None, None
示例#12
0
    def testContext_CachePolicyDisabledLater(self):
        # If the cache is disabled after an entity is stored in the cache,
        # further get() attempts *must not* return the result stored in cache.

        self.ctx.set_cache_policy(lambda key: True)
        key1 = model.Key(flat=('Foo', 1))
        ent1 = model.Expando(key=key1)
        self.ctx.put(ent1).get_result()

        # get() uses cache
        self.assertTrue(key1 in self.ctx._cache)  # Whitebox.
        self.assertEqual(self.ctx.get(key1).get_result(), ent1)

        # get() uses cache
        self.ctx._cache[key1] = None  # Whitebox.
        self.assertEqual(self.ctx.get(key1).get_result(), None)

        # get() doesn't use cache
        self.ctx.set_cache_policy(lambda key: False)
        self.assertEqual(self.ctx.get(key1).get_result(), ent1)
示例#13
0
 def get_or_insert(self, model_class, name,
                   app=None, namespace=None, parent=None,
                   context_options=None,
                   **kwds):
   # TODO: Test the heck out of this, in all sorts of evil scenarios.
   assert isinstance(name, basestring) and name
   key = model.Key(model_class, name,
                   app=app, namespace=namespace, parent=parent)
   # TODO: Can (and should) the cache be trusted here?
   ent = yield self.get(key)
   if ent is None:
     @tasklets.tasklet
     def txn():
       ent = yield key.get_async(options=context_options)
       if ent is None:
         ent = model_class(**kwds)  # TODO: Check for forbidden keys
         ent._key = key
         yield ent.put_async(options=context_options)
       raise tasklets.Return(ent)
     ent = yield self.transaction(txn)
   raise tasklets.Return(ent)
示例#14
0
    def testMultipleStructuredProperty(self):
        class Address(model.Model):
            label = model.StringProperty()
            text = model.StringProperty()

        class Person(model.Model):
            name = model.StringProperty()
            address = model.StructuredProperty(Address, repeated=True)

        m = Person(name='Google',
                   address=[
                       Address(label='work', text='San Francisco'),
                       Address(label='home', text='Mountain View')
                   ])
        m.key = model.Key(flat=['Person', None])
        self.assertEqual(m.address[0].label, 'work')
        self.assertEqual(m.address[0].text, 'San Francisco')
        self.assertEqual(m.address[1].label, 'home')
        self.assertEqual(m.address[1].text, 'Mountain View')
        [k] = self.conn.put([m])
        m.key = k  # Connection.put() doesn't do this!
        [m2] = self.conn.get([k])
        self.assertEqual(m2, m)
示例#15
0
    def testMultipleStructuredProperty(self):
        class Address(model.Model):
            label = model.StringProperty()
            text = model.StringProperty()

        class Person(model.Model):
            name = model.StringProperty()
            address = model.StructuredProperty(Address, repeated=True)

        m = Person(name='Google',
                   address=[
                       Address(label='work', text='San Francisco'),
                       Address(label='home', text='Mountain View')
                   ])
        m.key = model.Key(flat=['Person', None])
        self.assertEqual(m.address[0].label, 'work')
        self.assertEqual(m.address[0].text, 'San Francisco')
        self.assertEqual(m.address[1].label, 'home')
        self.assertEqual(m.address[1].text, 'Mountain View')
        pb = m._to_pb()
        self.assertEqual(str(pb), MULTISTRUCT_PB)

        m2 = Person._from_pb(pb)
        self.assertEqual(m2, m)
示例#16
0
    def testRecursiveStructuredProperty(self):
        class Node(model.Model):
            name = model.StringProperty(indexed=False)

        Node.left = model.StructuredProperty(Node)
        Node.rite = model.StructuredProperty(Node)
        Node._fix_up_properties()

        class Tree(model.Model):
            root = model.StructuredProperty(Node)

        k = model.Key(flat=['Tree', None])
        tree = Tree()
        tree.key = k
        tree.root = Node(name='a',
                         left=Node(name='a1',
                                   left=Node(name='a1a'),
                                   rite=Node(name='a1b')),
                         rite=Node(name='a2', rite=Node(name='a2b')))
        pb = tree._to_pb()
        self.assertEqual(str(pb), RECURSIVE_PB)

        tree2 = Tree._from_pb(pb)
        self.assertEqual(tree2, tree)
示例#17
0
def _args_to_val(func, args, bindings):
    vals = []
    for arg in args:
        if isinstance(arg, (int, long, basestring)):
            if arg in bindings:
                val = bindings[arg]
            else:
                val = Binding(None, arg)
                bindings[arg] = val
        elif isinstance(arg, gql.Literal):
            val = arg.Get()
        else:
            assert False, 'Unexpected arg (%r)' % arg
        vals.append(val)
    if func == 'nop':
        assert len(vals) == 1
        return vals[0]
    if func == 'list':
        return vals
    if func == 'key':
        if len(vals) == 1 and isinstance(vals[0], basestring):
            return model.Key(urlsafe=vals[0])
        assert False, 'Unexpected key args (%r)' % (vals, )
    assert False, 'Unexpected func (%r)' % func
示例#18
0
 def NastyCallback(self, rpc):
     [ent] = rpc.get_result()
     key = model.Key(flat=['Expando', 1])
     newrpc = self.conn.async_get(None, [key])
示例#19
0
 def delete_by_id(cls, user_id):
     user_key = model.Key(cls, user_id)
     # Use delete_multi() to save a RPC call.
     model.delete_multi([user_key])
     return True
示例#20
0
def account_key(userid):
    return model.Key(flat=['Account', userid])
示例#21
0
 def testBasicSetup2(self):
     key = model.Key(flat=['Expando', 1])
     rpc = self.conn.async_get(None, [key])
     [ent] = rpc.get_result()
     self.assertTrue(ent is None)
示例#22
0
 def foo():
     # Foo class is declared in query_test, so let's get a unusual class name.
     key1 = model.Key(flat=('ThisModelClassDoesntExist', 1))
     ent1 = model.Expando(key=key1, foo=42, bar='hello')
     key = yield ctx.put(ent1)
     a = yield ctx.get(key1)
示例#23
0
 def create(cls, value):
     entity = cls(key=model.Key(cls, value))
     txn = lambda: entity.put() if not entity.key.get() else None
     return model.transaction(txn) is not None
示例#24
0
class ContextTests(test_utils.DatastoreTest):
    def setUp(self):
        super(ContextTests, self).setUp()
        self.set_up_eventloop()
        MyAutoBatcher.reset_log()
        self.ctx = context.Context(
            conn=model.make_connection(default_model=model.Expando),
            auto_batcher_class=MyAutoBatcher)

    def set_up_eventloop(self):
        if eventloop._EVENT_LOOP_KEY in os.environ:
            del os.environ[eventloop._EVENT_LOOP_KEY]
        self.ev = eventloop.get_event_loop()
        self.log = []

    def testContext_AutoBatcher_Get(self):
        @tasklets.tasklet
        def foo():
            key1 = model.Key(flat=['Foo', 1])
            key2 = model.Key(flat=['Foo', 2])
            key3 = model.Key(flat=['Foo', 3])
            fut1 = self.ctx.get(key1)
            fut2 = self.ctx.get(key2)
            fut3 = self.ctx.get(key3)
            ent1 = yield fut1
            ent2 = yield fut2
            ent3 = yield fut3
            raise tasklets.Return([ent1, ent2, ent3])

        ents = foo().get_result()
        self.assertEqual(ents, [None, None, None])
        self.assertEqual(len(MyAutoBatcher._log), 1)

    @tasklets.tasklet
    def create_entities(self):
        key0 = model.Key(flat=['Foo', None])
        ent1 = model.Model(key=key0)
        ent2 = model.Model(key=key0)
        ent3 = model.Model(key=key0)
        fut1 = self.ctx.put(ent1)
        fut2 = self.ctx.put(ent2)
        fut3 = self.ctx.put(ent3)
        key1 = yield fut1
        key2 = yield fut2
        key3 = yield fut3
        raise tasklets.Return([key1, key2, key3])

    def testContext_AutoBatcher_Put(self):
        keys = self.create_entities().get_result()
        self.assertEqual(len(keys), 3)
        self.assertTrue(None not in keys)
        self.assertEqual(len(MyAutoBatcher._log), 1)

    def testContext_AutoBatcher_Delete(self):
        @tasklets.tasklet
        def foo():
            key1 = model.Key(flat=['Foo', 1])
            key2 = model.Key(flat=['Foo', 2])
            key3 = model.Key(flat=['Foo', 3])
            fut1 = self.ctx.delete(key1)
            fut2 = self.ctx.delete(key2)
            fut3 = self.ctx.delete(key3)
            yield fut1
            yield fut2
            yield fut3

        foo().check_success()
        self.assertEqual(len(MyAutoBatcher._log), 1)

    def testContext_MultiRpc(self):
        # This test really tests the proper handling of MultiRpc by
        # queue_rpc() in eventloop.py.  It's easier to test from here, and
        # gives more assurance that it works.
        config = datastore_rpc.Configuration(max_get_keys=3,
                                             max_put_entities=3)
        self.ctx._conn = model.make_connection(config,
                                               default_model=model.Expando)

        @tasklets.tasklet
        def foo():
            ents = [model.Expando() for i in range(10)]
            futs = [self.ctx.put(ent) for ent in ents]
            keys = yield futs
            futs = [self.ctx.get(key) for key in keys]
            ents2 = yield futs
            self.assertEqual(ents2, ents)
            raise tasklets.Return(keys)

        keys = foo().get_result()
        print keys
        self.assertEqual(len(keys), 10)

    def testContext_Cache(self):
        @tasklets.tasklet
        def foo():
            key1 = model.Key(flat=('Foo', 1))
            ent1 = model.Expando(key=key1, foo=42, bar='hello')
            key = yield self.ctx.put(ent1)
            self.assertTrue(key1 in self.ctx._cache)  # Whitebox.
            a = yield self.ctx.get(key1)
            b = yield self.ctx.get(key1)
            self.assertTrue(a is b)
            yield self.ctx.delete(key1)
            self.assertTrue(self.ctx._cache[key] is None)  # Whitebox.
            a = yield self.ctx.get(key1)
            self.assertTrue(a is None)

        foo().check_success()

    def testContext_CachePolicy(self):
        def should_cache(key):
            return False

        @tasklets.tasklet
        def foo():
            key1 = model.Key(flat=('Foo', 1))
            ent1 = model.Expando(key=key1, foo=42, bar='hello')
            key = yield self.ctx.put(ent1)
            self.assertTrue(key1 not in self.ctx._cache)  # Whitebox.
            a = yield self.ctx.get(key1)
            b = yield self.ctx.get(key1)
            self.assertTrue(a is not b)
            yield self.ctx.delete(key1)
            self.assertTrue(key not in self.ctx._cache)  # Whitebox.
            a = yield self.ctx.get(key1)
            self.assertTrue(a is None)

        self.ctx.set_cache_policy(should_cache)
        foo().check_success()

    def testContext_CachePolicyDisabledLater(self):
        # If the cache is disabled after an entity is stored in the cache,
        # further get() attempts *must not* return the result stored in cache.

        self.ctx.set_cache_policy(lambda key: True)
        key1 = model.Key(flat=('Foo', 1))
        ent1 = model.Expando(key=key1)
        self.ctx.put(ent1).get_result()

        # get() uses cache
        self.assertTrue(key1 in self.ctx._cache)  # Whitebox.
        self.assertEqual(self.ctx.get(key1).get_result(), ent1)

        # get() uses cache
        self.ctx._cache[key1] = None  # Whitebox.
        self.assertEqual(self.ctx.get(key1).get_result(), None)

        # get() doesn't use cache
        self.ctx.set_cache_policy(lambda key: False)
        self.assertEqual(self.ctx.get(key1).get_result(), ent1)

    def testContext_Memcache(self):
        @tasklets.tasklet
        def foo():
            key1 = model.Key(flat=('Foo', 1))
            key2 = model.Key(flat=('Foo', 2))
            ent1 = model.Expando(key=key1, foo=42, bar='hello')
            ent2 = model.Expando(key=key2, foo=1, bar='world')
            k1, k2 = yield self.ctx.put(ent1), self.ctx.put(ent2)
            self.assertEqual(k1, key1)
            self.assertEqual(k2, key2)
            yield tasklets.sleep(0.01)  # Let other tasklet complete.
            keys = [k1.urlsafe(), k2.urlsafe()]
            results = memcache.get_multi(keys, key_prefix='NDB:')
            self.assertEqual(
                results, {
                    key1.urlsafe(): self.ctx._conn.adapter.entity_to_pb(ent1),
                    key2.urlsafe(): self.ctx._conn.adapter.entity_to_pb(ent2)
                })

        foo().check_success()

    def testContext_MemcachePolicy(self):
        badkeys = []

        def tracking_set_multi(*args, **kwds):
            try:
                res = save_set_multi(*args, **kwds)
                if badkeys and not res:
                    res = badkeys
                track.append((args, kwds, res, None))
                return res
            except Exception, err:
                track.append((args, kwds, None, err))
                raise

        @tasklets.tasklet
        def foo():
            k1, k2 = yield self.ctx.put(ent1), self.ctx.put(ent2)
            self.assertEqual(k1, key1)
            self.assertEqual(k2, key2)
            yield tasklets.sleep(0.01)  # Let other tasklet complete.

        key1 = model.Key('Foo', 1)
        key2 = model.Key('Foo', 2)
        ent1 = model.Expando(key=key1, foo=42, bar='hello')
        ent2 = model.Expando(key=key2, foo=1, bar='world')
        save_set_multi = memcache.set_multi
        try:
            memcache.set_multi = tracking_set_multi
            memcache.flush_all()

            track = []
            foo().check_success()
            self.assertEqual(len(track), 1)
            self.assertEqual(track[0][0], ({
                key1.urlsafe(): ent1._to_pb(),
                key2.urlsafe(): ent2._to_pb()
            }, ))
            self.assertEqual(track[0][1], {'key_prefix': 'NDB:', 'time': 0})
            memcache.flush_all()

            track = []
            self.ctx.set_memcache_policy(lambda key: False)
            foo().check_success()
            self.assertEqual(len(track), 0)
            memcache.flush_all()

            track = []
            self.ctx.set_memcache_policy(lambda key: key == key1)
            foo().check_success()
            self.assertEqual(len(track), 1)
            self.assertEqual(track[0][0], ({key1.urlsafe(): ent1._to_pb()}, ))
            self.assertEqual(track[0][1], {'key_prefix': 'NDB:', 'time': 0})
            memcache.flush_all()

            track = []
            self.ctx.set_memcache_policy(lambda key: True)
            self.ctx.set_memcache_timeout_policy(lambda key: key.id())
            foo().check_success()
            self.assertEqual(len(track), 2)
            self.assertEqual(track[0][0], ({key1.urlsafe(): ent1._to_pb()}, ))
            self.assertEqual(track[0][1], {'key_prefix': 'NDB:', 'time': 1})
            self.assertEqual(track[1][0], ({key2.urlsafe(): ent2._to_pb()}, ))
            self.assertEqual(track[1][1], {'key_prefix': 'NDB:', 'time': 2})
            memcache.flush_all()

            track = []
            badkeys = [key2.urlsafe()]
            self.ctx.set_memcache_timeout_policy(lambda key: 0)
            foo().check_success()
            self.assertEqual(len(track), 1)
            self.assertEqual(track[0][2], badkeys)
            memcache.flush_all()
        finally:
            memcache.set_multi = save_set_multi
示例#25
0
 def foo():
     key = model.Key(flat=('Foo', 1))
     lo_hi = yield self.ctx.allocate_ids(key, size=10)
     self.assertEqual(lo_hi, (1, 10))
     lo_hi = yield self.ctx.allocate_ids(key, max=20)
     self.assertEqual(lo_hi, (11, 20))
示例#26
0
 def testBasicSetup1(self):
     ent = model.Expando()
     ent.foo = 'bar'
     rpc = self.conn.async_put(None, [ent])
     [key] = rpc.get_result()
     self.assertEqual(key, model.Key(flat=['Expando', 1]))
示例#27
0
    def testIdAndParent(self):
        p = model.Key('ParentModel', 'foo')

        # key name
        m = model.Model(id='bar')
        m2 = model.Model._from_pb(m._to_pb())
        self.assertEqual(m2.key, model.Key('Model', 'bar'))

        # key name + parent
        m = model.Model(id='bar', parent=p)
        m2 = model.Model._from_pb(m._to_pb())
        self.assertEqual(m2.key, model.Key('ParentModel', 'foo', 'Model',
                                           'bar'))

        # key id
        m = model.Model(id=42)
        m2 = model.Model._from_pb(m._to_pb())
        self.assertEqual(m2.key, model.Key('Model', 42))

        # key id + parent
        m = model.Model(id=42, parent=p)
        m2 = model.Model._from_pb(m._to_pb())
        self.assertEqual(m2.key, model.Key('ParentModel', 'foo', 'Model', 42))

        # parent
        m = model.Model(parent=p)
        m2 = model.Model._from_pb(m._to_pb())
        self.assertEqual(m2.key, model.Key('ParentModel', 'foo', 'Model',
                                           None))

        # not key -- invalid
        self.assertRaises(datastore_errors.BadValueError,
                          model.Model,
                          key='foo')

        # wrong key kind -- invalid
        k = model.Key('OtherModel', 'bar')
        self.assertRaises(model.KindError, model.Model, key=k)

        # incomplete parent -- invalid
        p2 = model.Key('ParentModel', None)
        self.assertRaises(datastore_errors.BadArgumentError,
                          model.Model,
                          parent=p2)
        self.assertRaises(datastore_errors.BadArgumentError,
                          model.Model,
                          id='bar',
                          parent=p2)

        # key + id -- invalid
        k = model.Key('Model', 'bar')
        self.assertRaises(datastore_errors.BadArgumentError,
                          model.Model,
                          key=k,
                          id='bar')

        # key + parent -- invalid
        k = model.Key('Model', 'bar', parent=p)
        self.assertRaises(datastore_errors.BadArgumentError,
                          model.Model,
                          key=k,
                          parent=p)

        # key + id + parent -- invalid
        self.assertRaises(datastore_errors.BadArgumentError,
                          model.Model,
                          key=k,
                          id='bar',
                          parent=p)
示例#28
0
def subverting_aries_fix():
    # Variation by Guido van Rossum.
    def setup_context():
        ctx = tasklets.get_context()
        ctx.set_datastore_policy(True)
        ctx.set_memcache_policy(True)
        ctx.set_cache_policy(False)
        return ctx

    key = model.Key(CrashTestDummyModel, 1)
    mkey = tasklets.get_context()._memcache_prefix + key.urlsafe()

    ent1 = CrashTestDummyModel(key=key, name=u'Brad Roberts')
    ent2 = CrashTestDummyModel(key=key, name=u'Ellen Reid')

    ctx = setup_context()
    # Store an original version of the entity
    # NOTE: Do not wish to store this one value in memcache, turning it off
    ent1.put(use_memcache=False)

    a_lock1 = threading.Lock()
    a_lock2 = threading.Lock()
    a_lock3 = threading.Lock()

    class A(threading.Thread):
        def run(self):
            ctx = setup_context()
            fut = ent2.put_async()

            # Get to the point that the lock is written to memcache
            wait_on_batcher(ctx._memcache_set_batcher)

            # Wait for B to cause a race condition
            a_lock2.acquire()
            a_lock1.acquire()
            wait_on_batcher(ctx._put_batcher)
            a_lock2.release()
            a_lock1.release()

            # Wait for C to read from memcache
            a_lock3.acquire()
            fut.check_success()
            a_lock3.release()

    class C(threading.Thread):
        def run(self):
            setup_context()
            result = key.get()
            assert result == ent2, result
            eventloop.run()

    logging.info('A: write lock to memcache')
    a = A()
    a_lock1.acquire()
    a_lock3.acquire()
    a.start()
    while memcache.get(mkey) != context._LOCKED:
        time.sleep(0.1)  # Wait for the memcache lock to be set

    logging.info('M: evict the lock')
    memcache.flush_all()
    assert memcache.get(mkey) is None, 'lock was not evicted'

    logging.info("B: read from memcache (it's a miss)")
    b = key.get_async()
    wait_on_batcher(ctx._memcache_get_batcher)

    logging.info('B: write lock to memcache')
    wait_on_batcher(ctx._memcache_set_batcher)

    logging.info("B: read the lock back (it's a success)")
    wait_on_batcher(ctx._memcache_get_batcher)

    logging.info('B: read from datastore')
    wait_on_batcher(ctx._get_batcher)

    logging.info('A: write to datastore')
    a_lock1.release()
    a_lock2.acquire()
    a_lock2.release()

    logging.info('B: write to memcache (writes a stale value)')
    b.get_result()
    eventloop.run()  # Puts to memcache are still stuck in the eventloop

    logging.info('C: read from memcache (sees a stale value)')
    c = C()
    c.start()
    c.join()

    logging.info('A: delete from memcache (deletes the stale value!)')
    a_lock3.release()
    a.join()

    pb3 = memcache.get(mkey)
    assert pb3 is not context._LOCKED, 'Received _LOCKED value'
    if pb3 is not None:
        ent3 = ctx._conn.adapter.pb_to_entity(pb3)
        assert ent3 == ent2, 'stale value in memcache; %r != %r' % (ent3, ent2)

    # Finally check the high-level API.
    ent4 = key.get()
    assert ent4 == ent2
示例#29
0
 def foo():
     key1 = model.Key(flat=('Foo', 1))
     ent1 = model.Expando(key=key1, foo=42, bar='hello')
     key = yield ctx.put(ent1)
     a = yield ctx.get(key1)
示例#30
0
 def foo():
   parent = model.Key(flat=('Foo', 1))
   ent = yield self.ctx.get_or_insert(Mod, 'a', parent=parent, data='hello')
   assert isinstance(ent, Mod)
   ent2 = yield self.ctx.get_or_insert(Mod, 'a', parent=parent, data='hello')
   assert ent2 == ent