def test_date(self): s1 = ejson.dumps(datetime.date(2015, 1, 25)) self.assertEqual('{"$date": 1422144000000}', s1) self.assertEqual(datetime.datetime(2015, 1, 25, tzinfo=ejson.timezone.utc), ejson.loads(s1)) s2 = ejson.dumps(datetime.datetime(2015, 1, 25, 10, 30, 1, tzinfo=ejson.timezone.utc)) self.assertEqual('{"$date": 1422181801000}', s2) self.assertEqual(datetime.datetime(2015, 1, 25, 10, 30, 1, tzinfo=ejson.timezone.utc), ejson.loads(s2))
def _handle_message(self, msg, socket): if msg.tp == sockjs.MSG_OPEN: socket._ddp_session = None elif msg.tp == sockjs.MSG_MESSAGE: try: try: mbody = ejson.loads(msg.data) if type(mbody) != dict or mbody.get("msg") == None: self.logger.debug( "Discarding non-object DDP message {msg}" .format(msg=msg.data), ) socket.send(ejson.dumps({ "msg": "error", "reason": "Bad request", "offendingMessage": mbody, })) return except ValueError: self.logger.debug( "Discarding message with invalid JSON {msg}" .format(msg=msg.data), ) socket.send(json.dumps({ "msg": "error", "reason": "Bad request", })) return if mbody["msg"] == "connect": if socket._ddp_session: socket.send(json.dumps({ "msg": "error", "reason": "Already connected", "offendingMessage": mbody, })) return asyncio.async(self._handle_connect(mbody, socket), loop=self.loop) return if not socket._ddp_session: socket.send(ejson.dumps({ "msg": "error", "reason": "Must connect first", "offendingMessage": mbody, })) return socket._ddp_session.process_message(mbody) except Exception: self.logger.error( "Internal exception while processing message {msg}\n{err}" .format(msg=msg.data, err=traceback.format_exc()) )
def test_binary(self): if six.PY3: s = ejson.dumps([six.binary_type('foo', 'ascii'), 'foo']) self.assertEqual('[{"$binary": "Zm9v"}, "foo"]', s) self.assertEqual([six.binary_type('foo', 'ascii'), 'foo'], ejson.loads(s)) else: s = ejson.dumps(['foo', six.text_type('foo')]) self.assertEqual('["foo", "foo"]', s) self.assertEqual(['foo', 'foo'], ejson.loads('[{"$binary": "Zm9v"}, "foo"]'))
def send(self, data, tx_id=None): """Send `data` (raw string or EJSON payload) to WebSocket client.""" # buffer data until we get pre-requisite data if tx_id is None: tx_id = self.get_tx_id() self._tx_buffer[tx_id] = data # de-queue messages from buffer while self._tx_next_id in self._tx_buffer: # pull next message from buffer data = self._tx_buffer.pop(self._tx_next_id) if self._tx_buffer: safe_call(self.logger.debug, 'TX found %d', self._tx_next_id) # advance next message ID self._tx_next_id = next(self._tx_next_id_gen) if not isinstance(data, basestring): # ejson payload msg = data.get('msg', None) if msg in (ADDED, CHANGED, REMOVED): ids = self.remote_ids[data['collection']] meteor_id = data['id'] if msg == ADDED: if meteor_id in ids: msg = data['msg'] = CHANGED else: ids.add(meteor_id) elif msg == CHANGED: if meteor_id not in ids: # object has become visible, treat as `added`. msg = data['msg'] = ADDED ids.add(meteor_id) elif msg == REMOVED: try: ids.remove(meteor_id) except KeyError: continue # client doesn't have this, don't send. data = 'a%s' % ejson.dumps([ejson.dumps(data)]) # send message safe_call(self.logger.debug, '> %s %r', self, data) try: self.ws.send(data) except geventwebsocket.WebSocketError: self.ws.close() self._tx_buffer.clear() break num_waiting = len(self._tx_buffer) if num_waiting > 10: safe_call( self.logger.warn, 'TX received %d, waiting for %d, have %d waiting: %r.', tx_id, self._tx_next_id, num_waiting, self._tx_buffer, )
def send(self, data, tx_id=None): """Send `data` (raw string or EJSON payload) to WebSocket client.""" # buffer data until we get pre-requisite data if tx_id is None: tx_id = self.get_tx_id() self._tx_buffer[tx_id] = data # de-queue messages from buffer while self._tx_next_id in self._tx_buffer: # pull next message from buffer data = self._tx_buffer.pop(self._tx_next_id) if self._tx_buffer: safe_call(self.logger.debug, "TX found %d", self._tx_next_id) # advance next message ID self._tx_next_id = next(self._tx_next_id_gen) if not isinstance(data, basestring): # ejson payload msg = data.get("msg", None) if msg in (ADDED, CHANGED, REMOVED): ids = self.remote_ids[data["collection"]] meteor_id = data["id"] if msg == ADDED: if meteor_id in ids: msg = data["msg"] = CHANGED else: ids.add(meteor_id) elif msg == CHANGED: if meteor_id not in ids: # object has become visible, treat as `added`. msg = data["msg"] = ADDED ids.add(meteor_id) elif msg == REMOVED: try: ids.remove(meteor_id) except KeyError: continue # client doesn't have this, don't send. data = "a%s" % ejson.dumps([ejson.dumps(data)]) # send message safe_call(self.logger.debug, "> %s %r", self, data) try: self.ws.send(data) except geventwebsocket.WebSocketError: self.ws.close() self._tx_buffer.clear() break num_waiting = len(self._tx_buffer) if num_waiting > 10: safe_call( self.logger.warn, "TX received %d, waiting for %d, have %d waiting: %r.", tx_id, self._tx_next_id, num_waiting, self._tx_buffer, )
async def _handle_messages( self, websocket: websockets.protocol.WebSocketCommonProtocol, _path: str): async def send(data: object) -> None: await websocket.send(ejson.dumps(data)) async def fail(): await send({ "msg": "failed", "version": "1", }) data = ejson.loads(await websocket.recv()) if data["msg"] != "connect": return await fail() await websocket.send( ejson.dumps({ "msg": "connected", "session": str(uuid.uuid4()) })) async for message in websocket: data = ejson.loads(message) if data["msg"] == "method": assert data["method"] in self._method_handlers await send({ "id": data["id"], "msg": "result", "result": self._method_handlers[data["method"]](*data["params"]), }) continue await fail()
def ddpp_sockjs_info(environ, start_response): """Inform client that WebSocket service is available.""" start_response( '200 OK', [ ('Content-Type', 'application/json; charset=UTF-8'), ( 'Access-Control-Allow-Origin', '/'.join(environ['HTTP_REFERER'].split('/')[:3]), ), ('Access-Control-Allow-Credentials', 'true'), # ('access-control-allow-credentials', 'true'), ('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0'), ('Connection', 'keep-alive'), ('Vary', 'Origin'), ], ) yield ejson.dumps(collections.OrderedDict([ ('websocket', True), ('origins', [ '*:*', ]), ('cookie_needed', False), ('entropy', random.getrandbits(32)), ]))
async def connect(self): '''This coroutine establishes a connection to a server. It blocks until the connection is established or an exception is raised. Raises ddp_asyncio.ConnectionError if the server reports a failure (usually caused by incomplatible versions of the DDP protocol.) ''' self._websocket = await websockets.connect(self.url) msg = {'msg': 'connect', 'version': '1', 'support': ['1']} await self._websocket.send(ejson.dumps(msg)) while self._websocket.open: msg = await self._websocket.recv() msg = ejson.loads(msg) _type = msg.get('msg') if _type == 'failed': raise ConnectionError( 'The server is not compatible with version 1 of the DDP protocol.' ) elif _type == 'connected': # Ensure all Collections are in their default states for col in self._cols.values(): col._data = {} self.is_connected = True self._disconnection_event.clear() self._event_loop.create_task(self.__handler__()) return
def recvloop(self): while self.websocket.open: while len(self.callcache) > 0: self.call(*self.callcache.pop(0)) msg = yield from self.websocket.recv() if not msg: continue msg = ejson.loads(msg) if msg.get('msg') == 'connected': self.connected = True self.session = msg['session'] elif msg.get('msg') == 'ping': yield from self.websocket.send( ejson.dumps({ 'msg': 'pong', 'id': msg.get('id') })) elif msg.get('msg') == 'ready': for sub in self.subs.values(): if sub.id in msg['subs']: yield from sub.ready_cb(sub) elif msg.get('msg') == 'added': sub = self.subs.get(msg['collection']) if sub: sub.data[msg['id']] = msg['fields'] yield from sub.added_cb(sub, msg['id'], msg['fields']) elif msg.get('msg') == 'changed': sub = self.subs.get(msg['collection']) if sub: if msg.get('fields'): sub.data[msg['id']].update(msg['fields']) yield from sub.changed_cb(sub, msg['id'], msg['fields']) elif msg.get('cleared'): for key in msg['cleared']: del sub.data[key] yield from sub.changed_cb(sub, msg['id'], msg['cleared']) elif msg.get('msg') == 'removed': sub = self.subs.get(msg['collection']) if sub: del sub.data[msg['id']] yield from sub.removed_cb(sub, msg['id']) elif msg.get('msg') == 'result': c = self.calls.get(msg['id']) if c: yield from c.onfinished(msg.get('result'), msg.get('error')) self.connected = False while True: yield from self.connect() return
def get(self, request, path): """Return HTML (or other related content) for Meteor.""" if path == '/meteor_runtime_config.js': config = { 'DDP_DEFAULT_CONNECTION_URL': request.build_absolute_uri('/'), 'ROOT_URL': request.build_absolute_uri( '%s/' % self.runtime_config.get('ROOT_URL_PATH_PREFIX', ''), ), 'ROOT_URL_PATH_PREFIX': '', } # Use HTTPS instead of HTTP if SECURE_SSL_REDIRECT is set if config['DDP_DEFAULT_CONNECTION_URL'].startswith('http:') \ and settings.SECURE_SSL_REDIRECT: config['DDP_DEFAULT_CONNECTION_URL'] = 'https:%s' % ( config['DDP_DEFAULT_CONNECTION_URL'].split(':', 1)[1], ) config.update(self.runtime_config) return HttpResponse( '__meteor_runtime_config__ = %s;' % dumps(config), content_type='text/javascript', ) try: file_path, content_type = self.url_map[path] with open(file_path, 'r') as content: return HttpResponse( content.read(), content_type=content_type, ) except KeyError: print(path) return HttpResponse(self.html)
def ddpp_sockjs_info(environ, start_response): """Inform client that WebSocket service is available.""" import random import ejson start_response( '200 OK', [ ('Content-Type', 'application/json; charset=UTF-8'), ( 'Access-Control-Allow-Origin', '/'.join(environ['HTTP_REFERER'].split('/')[:3]), ), ('Access-Control-Allow-Credentials', 'true'), # ('access-control-allow-credentials', 'true'), ('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0' ), ('Connection', 'keep-alive'), ('Vary', 'Origin'), ], ) yield ejson.dumps( collections.OrderedDict([ ('websocket', True), ('origins', [ '*:*', ]), ('cookie_needed', False), ('entropy', random.getrandbits(32)), ]))
def test_serialization_with_datetime(): ejson.cleanup_registry() value = {'dt': datetime(2012, 8, 22, 3, 44, 0o5)} # Before registering ejson.dumps.when.called_with(value, sort_keys=True).should.throw( TypeError, 'datetime.datetime(2012, 8, 22, 3, 44, 5) is not JSON serializable') # After registering @ejson.register_serializer(datetime) def serialize_datetime(instance): return instance.isoformat() ejson.dumps(value, sort_keys=True).should.be.equals( '{"dt": {"__class__": "datetime.datetime", "__value__": "2012-08-22T03:44:05"}}')
def test_serialization_with_datetime(): ejson.cleanup_registry() value = {'dt': datetime(2012, 8, 22, 3, 44, 0o5)} # Before registering ejson.dumps.when.called_with(value, sort_keys=True).should.throw( TypeError, 'datetime.datetime(2012, 8, 22, 3, 44, 5) is not JSON serializable') # After registering @ejson.register_serializer(datetime) def serialize_datetime(instance): return instance.isoformat() ejson.dumps(value, sort_keys=True).should.be.equals( '{"dt": {"__class__": "datetime.datetime", "__value__": "2012-08-22T03:44:05"}}' )
def save(self, filename=None): import ejson if not os.path.exists(self.workdir): os.makedirs(self.workdir) if filename is None: filename = 'task.ejson' with open(os.path.join(self.workdir, filename), 'w') as f: f.write(ejson.dumps(self.taskDoc))
def test_escaping_string_on_dumps(): # Given that I have some data to serialize data = {'blah': '<h1>blah & bleh</h1>'} # When I try to dump it using the "escape" flag escaped = ejson.dumps(data, escape=True) # Then I see it was escaped properly escaped.should.equal('{"blah": "<h1>blah & bleh</h1>"}')
def test_log_when_debug_is_false(conf, datetime, find_event, tasks): conf.getsetting.return_value = False core.cleanup_handlers() datetime.now.return_value = 'tea time' eventlib.log('app.Event') tasks.process_task.delay.assert_called_once_with('app.Event', ejson.dumps({ '__ip_address__': '0.0.0.0', '__datetime__': 'tea time', }))
def ejson_serialize(self): """ """ message_dict = {"msg": self.msg} for arg in self._serialize_args: if arg == "error" and not self.error: continue message_dict[arg] = self.__dict__.get(arg, None) return ejson.dumps(message_dict)
def test_process_raises_the_exception_when_debugging(settings, find_event): core.cleanup_handlers() settings.DEBUG = True handler_fail = Mock() handler_fail.side_effect = ValueError('P0wned!!!') eventlib.handler('myapp.CoolEvent')(handler_fail) name, data = 'myapp.CoolEvent', ejson.dumps({'a': 1}) core.process.when.called_with(name, data).should.throw( ValueError, 'P0wned!!!')
async def unsubscribe(self, sub): '''Coroutine that unsubscribes from a publication. Raises ddp_asyncio.NotConnectedError if called while not connected to a server. ''' await self._websocket.send(ejson.dumps({ 'msg': 'unsub', 'id': sub._id }))
def test_process_raises_the_exception_when_debugging(settings, find_event): core.cleanup_handlers() settings.DEBUG = True handler_fail = Mock() handler_fail.side_effect = ValueError('P0wned!!!') eventlib.handler('myapp.CoolEvent')(handler_fail) name, data = 'myapp.CoolEvent', ejson.dumps({'a': 1}) core.process.when.called_with(name, data).should.throw(ValueError, 'P0wned!!!')
def do_sub(self, id_, name, silent, *params): """Subscribe the current thread to the specified publication.""" try: pub = self.get_pub_by_name(name) except KeyError: if not silent: raise MeteorError(404, 'Subscription not found') return sub, created = Subscription.objects.get_or_create( connection_id=this.ws.connection.pk, sub_id=id_, user_id=getattr(this, 'user_id', None), defaults={ 'publication': pub.name, 'params_ejson': ejson.dumps(params), }, ) this.subs.setdefault(sub.publication, set()).add(sub.pk) if not created: if not silent: this.send({'msg': 'ready', 'subs': [id_]}) return # re-read from DB so we can get transaction ID (xmin) sub = Subscription.objects.extra(**XMIN).get(pk=sub.pk) for col, qs in self.sub_unique_objects( sub, params, pub, xmin__lte=sub.xmin, ): sub.collections.create( model_name=model_name(qs.model), collection_name=col.name, ) if isinstance(col.model._meta.pk, AleaIdField): meteor_ids = None elif len([ field for field in col.model._meta.local_fields if ( isinstance(field, AleaIdField) ) and ( field.unique ) and ( not field.null ) ]) == 1: meteor_ids = None else: meteor_ids = get_meteor_ids( qs.model, qs.values_list('pk', flat=True), ) for obj in qs.select_related(): payload = col.obj_change_as_msg(obj, ADDED, meteor_ids) this.send(payload) if not silent: this.send({'msg': 'ready', 'subs': [id_]})
def test_process_data_clean_raise_errors(logger, find_event): core.cleanup_handlers() class MyEvent(eventlib.BaseEvent): def clean(self): raise exceptions.ValidationError('Owned!!11') data = {'name': 'Lincoln', 'answer': 42} find_event.return_value = MyEvent core.process.when.called_with('stuff', ejson.dumps(data)).should.throw( exceptions.ValidationError)
def ddpp_sockjs_info(environ, start_response): """Inform client that WebSocket service is available.""" import random import ejson start_response("200 OK", [("Content-Type", "application/json; charset=UTF-8")] + common_headers(environ)) yield ejson.dumps( collections.OrderedDict( [("websocket", True), ("origins", ["*:*"]), ("cookie_needed", False), ("entropy", random.getrandbits(32))] ) )
def test_escape_encode(self): s = ejson.dumps({ "foo": "bar", "bat": { "$escape": { "baz": "bazam" } } }, sort_keys=True) self.assertEqual('{"bat": {"$escape": {"$escape": {"baz": "bazam"}}}, "foo": "bar"}', s)
def test_log_when_debug_is_false(conf, datetime, find_event, tasks): conf.getsetting.return_value = False core.cleanup_handlers() datetime.now.return_value = 'tea time' eventlib.log('app.Event') tasks.process_task.delay.assert_called_once_with( 'app.Event', ejson.dumps({ '__ip_address__': '0.0.0.0', '__datetime__': 'tea time', }))
def recvloop(self): while self.websocket.open: while len(self.callcache) > 0: self.call(*self.callcache.pop(0)) msg = yield from self.websocket.recv() if not msg: continue msg = ejson.loads(msg) if msg.get('msg') == 'connected': self.connected = True self.session = msg['session'] elif msg.get('msg') == 'ping': yield from self.websocket.send(ejson.dumps({'msg': 'pong', 'id': msg.get('id')})) elif msg.get('msg') == 'ready': for sub in self.subs.values(): if sub.id in msg['subs']: yield from sub.ready_cb(sub) elif msg.get('msg') == 'added': sub = self.subs.get(msg['collection']) if sub: sub.data[msg['id']] = msg['fields'] yield from sub.added_cb(sub, msg['id'], msg['fields']) elif msg.get('msg') == 'changed': sub = self.subs.get(msg['collection']) if sub: if msg.get('fields'): sub.data[msg['id']].update(msg['fields']) yield from sub.changed_cb(sub, msg['id'], msg['fields']) elif msg.get('cleared'): for key in msg['cleared']: del sub.data[key] yield from sub.changed_cb(sub, msg['id'], msg['cleared']) elif msg.get('msg') == 'removed': sub = self.subs.get(msg['collection']) if sub: del sub.data[msg['id']] yield from sub.removed_cb(sub, msg['id']) elif msg.get('msg') == 'result': c = self.calls.get(msg['id']) if c: yield from c.onfinished(msg.get('result'), msg.get('error')) self.connected = False while True: yield from self.connect() return
def _broadcast(self): if conf.getsetting('UNIT_TESTING'): raise AssertionError( 'Eventlib calls must be mocked when settings.UNIT_TESTING is True') data = self.broadcast(self.data) client = redis_connection.get_connection() if client: # If not redis client, don't broadcast data['name'] = self.name data = ejson.dumps(data) client.publish("eventlib", data)
async def subscribe(self, name: str) -> asyncio.Queue: id = str(uuid.uuid4()) sub_future = asyncio.get_event_loop().create_future() self._pending_subscription_data[id] = PendingSubscriptionData( name, sub_future) await super().send( ejson.dumps({ "id": id, "msg": "sub", "name": name, })) return await sub_future
def get_user_token(user, purpose, days_valid): """Return login token info for given user.""" token = ''.join( dumps([ user.get_username(), get_auth_hash(user, purpose), ]).encode('base64').split('\n')) return { 'id': get_meteor_id(user), 'token': token, 'tokenExpires': calc_expiry_time(days_valid), }
def subscribe(self, name, *params, ready_cb = noop, added_cb = noop, changed_cb = noop, removed_cb = noop): sub = Subscription(name, ready_cb, added_cb, changed_cb, removed_cb) self.subs[name] = sub yield from self.websocket.send(ejson.dumps( {'msg': 'sub', 'id': sub.id, 'name': name, 'params': params} )) return sub
def do_sub(self, id_, name, silent, *params): """Subscribe the current thread to the specified publication.""" try: pub = self.get_pub_by_name(name) except KeyError: if not silent: raise MeteorError(404, 'Subscription not found') return sub, created = Subscription.objects.get_or_create( connection_id=this.ws.connection.pk, sub_id=id_, user_id=getattr(this, 'user_id', None), defaults={ 'publication': pub.name, 'params_ejson': ejson.dumps(params), }, ) this.subs.setdefault(sub.publication, set()).add(sub.pk) if not created: if not silent: this.send({'msg': 'ready', 'subs': [id_]}) return # re-read from DB so we can get transaction ID (xmin) sub = Subscription.objects.extra(**XMIN).get(pk=sub.pk) for col, qs in self.sub_unique_objects( sub, params, pub, xmin__lte=sub.xmin, ): sub.collections.create( model_name=model_name(qs.model), collection_name=col.name, ) if isinstance(col.model._meta.pk, AleaIdField): meteor_ids = None elif len([ field for field in col.model._meta.local_fields if (isinstance(field, AleaIdField)) and ( field.unique) and (not field.null) ]) == 1: meteor_ids = None else: meteor_ids = get_meteor_ids( qs.model, qs.values_list('pk', flat=True), ) for obj in qs.select_related(): payload = col.obj_change_as_msg(obj, ADDED, meteor_ids) this.send(payload) if not silent: this.send({'msg': 'ready', 'subs': [id_]})
async def _handle_messages(self, websocket: WebSocketServerProtocol, _path: str): async def send(data: object) -> None: await websocket.send(ejson.dumps(data)) self._subscription_task = asyncio.create_task( self._send_subscription_messages(send=send, )) async def fail(): await send({ "msg": "failed", "version": "1", }) data = ejson.loads(await websocket.recv()) if data["msg"] != "connect": return await fail() await websocket.send( ejson.dumps({ "msg": "connected", "session": str(uuid.uuid4()) })) async for message in websocket: data = ejson.loads(message) if data["msg"] == "method": assert data["method"] in self._method_handlers await send({ "id": data["id"], "msg": "result", "result": self._method_handlers[data["method"]](*data["params"]), }) continue if data["msg"] == "sub": self._subscriptions[data["name"]] = data["id"] await send({ "msg": "ready", "subs": [data["id"]], }) continue if data["msg"] == "unsub": topic = [ topic for topic, id in self._subscriptions.items() if id == data["id"] ][0] del self._subscriptions[topic] # Nothing to respond with in this case. continue await fail()
def test_process_data_clean_raise_errors(logger, find_event): core.cleanup_handlers() class MyEvent(eventlib.BaseEvent): def clean(self): raise exceptions.ValidationError('Owned!!11') data = {'name': 'Lincoln', 'answer': 42} find_event.return_value = MyEvent core.process.when.called_with( 'stuff', ejson.dumps(data) ).should.throw(exceptions.ValidationError)
def get_user_token(user, purpose, minutes_valid): """Return login token info for given user.""" token = ''.join( dumps([ user.get_username(), get_auth_hash(user, purpose), ]).encode('base64').split('\n') ) return { 'id': get_meteor_id(user), 'token': token, 'tokenExpires': calc_expiry_time(minutes_valid), }
async def invoke_method(self, method: str, params: List[Any] = []) -> Any: id = str(uuid.uuid4()) recv_future = asyncio.get_event_loop().create_future() self._invoke_method_futures[id] = recv_future await super().send( ejson.dumps({ "id": id, "msg": "method", "method": method, "params": params, })) recv = await recv_future return recv["result"]
def _broadcast(self): if conf.getsetting('UNIT_TESTING'): raise AssertionError( 'Eventlib calls must be mocked when settings.UNIT_TESTING is True' ) data = self.broadcast(self.data) client = redis_connection.get_connection() if client: # If not redis client, don't broadcast data['name'] = self.name data = ejson.dumps(data) client.publish("eventlib", data)
def test_decimal(): # Given that I have a decimal object obj = decimal.Decimal("0.14285714285714285") # When I try to serialize it serialized = ejson.dumps(obj) # Then I see the proper string description of the object serialized.should.contain('"__class__": "decimal.Decimal"') serialized.should.contain('"__value__": "0.14285714285714285"') # When I try to deserialize, I see that it also works ejson.loads(serialized).should.equal(obj)
def test_time(): # Given that I have a time object to serialize obj = datetime.time(1, 12, 50, 123) # When I serialize it serialized = ejson.dumps(obj) # Then I see that it was correctly serialized serialized.should.contain('"__class__": "datetime.time"') serialized.should.contain('"__value__": "01:12:50.000123"') # When I try to deserialize, I see that it also works ejson.loads(serialized).should.equal(obj)
def test_log(conf, find_event, process, datetime): conf.getsetting.return_value = True core.cleanup_handlers() datetime.now.return_value = 'tea time' event_cls = Mock() find_event.return_value = event_cls data = {'name': 'Event System', 'code': 42} eventlib.log('app.Event', data) find_event.assert_called_once_with('app.Event') event_cls.assert_called_once_with('app.Event', data) event_cls.return_value.validate.assert_called_once() process.assert_called_once_with('app.Event', ejson.dumps(data))
def test_time_with_timezone(): # Given that I have a time object to serialize obj = datetime.time(1, 12, 50, 123, ejson.serializers.TZInfoHelper(-120, "FNT")) # When I serialize it serialized = ejson.dumps(obj) # Then I see that it was correctly serialized serialized.should.contain('"__class__": "datetime.time"') serialized.should.contain('"__value__": "01:12:50.000123-02:00"') # When I try to deserialize, I see that it also works ejson.loads(serialized).should.equal(obj)
def test_process(find_event): core.cleanup_handlers() handler = Mock() eventlib.handler('app.Event')(handler) handler2 = Mock() eventlib.handler('app.Event')(handler2) data = {'file': '/etc/passwd', 'server': 'yipster'} core.process('app.Event', ejson.dumps(data)) handler.assert_called_once_with(data) handler2.assert_called_once_with(data)
async def invoke_method(self, method: str, params: List[Any] = []) -> Any: async with self._method_lock: id = str(uuid.uuid4()) await super().send( ejson.dumps({ "id": id, "msg": "method", "method": method, "params": params, })) recv = ejson.loads(await super().recv()) if recv["id"] != id or recv["msg"] != "result": raise websockets.exceptions.ProtocolError("Unexpected message") return recv["result"]
def get_user_token(cls, user, session_key, expiry_date, purpose): """Return login token info for given user.""" token = ''.join( dumps([ user.get_username(), session_key, cls.get_auth_hash(user, purpose), ]).encode('base64').split('\n') ) return { 'id': get_meteor_id(user), 'token': token, 'tokenExpires': expiry_date, }
def test_date(): # Given that I have an instance of the date object that must be serialized obj = datetime.date(2013, 0o3, 30) # When I serialize it serialized = ejson.dumps(obj) # Then I see the proper representation of the instance that will allow us # to deserialize it later serialized.should.contain('"__class__": "datetime.date"') serialized.should.contain('"__value__": "2013-03-30"') # When I try to load this info again, Then I see that it also works ejson.loads(serialized).should.equal(obj)
def test_process_data_clean(logger, find_event): core.cleanup_handlers() class MyEvent(eventlib.BaseEvent): def clean(self): raise exceptions.ValidationError('Owned!!11') data = {'name': 'Lincoln', 'answer': 42} find_event.return_value = MyEvent core.process('stuff', ejson.dumps(data)) logger.warning.assert_called_once_with( 'The event system just got an exception while cleaning data ' "for the event 'stuff'\n" "data: {\"answer\": 42, \"name\": \"Lincoln\"}\n" "exc: Owned!!11")
def _assert_serialize_deserialize_equals_and_is_binary( ejson_obj, json_obj, json_str, is_binary ): assert json_str == ejson.stringify(ejson_obj) assert json_str == ejson.dumps(ejson_obj) assert json_obj == ejson.to_json_value(ejson_obj) assert ejson_obj == ejson.parse(json_str) assert ejson_obj == ejson.loads(json_str) assert ejson_obj == ejson.from_json_value(json_obj) ejson_obj2 = deepcopy(ejson_obj) assert ejson.equals(ejson_obj, ejson_obj2) assert ejson.equals(ejson_obj, ejson.clone(ejson_obj)) assert is_binary == ejson.is_binary(ejson_obj)
def test_serialization_with_custom_object(): ejson.cleanup_registry() value = Person('Lincoln', 25) # Before registering ejson.dumps.when.called_with(value, sort_keys=True).should.throw( TypeError, 'Person("Lincoln", 25) is not JSON serializable') # After registering @ejson.register_serializer(Person) def serialize_person(instance): return {"name": instance.name, "age": instance.age} dumped = ejson.dumps(value, sort_keys=True) dumped.should.be.contain('"__class__": "tests.unit.test_ejson.Person"') dumped.should.be.contain('"__value__": {"age": 25, "name": "Lincoln"}')
def call(self, method, *params, callback = None, wait = True): c = MethodCall(callback) self.calls[c.id] = c yield from self.websocket.send(ejson.dumps( {'msg': 'method', 'method': method, 'params': params, 'id': c.id} )) if wait: while not c.finished: yield from asyncio.sleep(0.1) return c.result
def connect(self): c = False while not c: try: self.websocket = yield from websockets.connect(self.address) c = self.websocket.open print(c) except ConnectionRefusedError: yield from asyncio.sleep(1) msg = {'msg': 'connect', 'version': '1', 'support': ['1']} if self.session: msg['session'] = self.session yield from self.websocket.send(ejson.dumps(msg)) asyncio.async(self.recvloop()) while not self.connected: yield from asyncio.sleep(0.1)
def test_process_fails_gracefully(settings, logger, find_event): core.cleanup_handlers() settings.DEBUG = False handler_fail = Mock() handler_fail.side_effect = ValueError('P0wned!!!') eventlib.handler('myapp.CoolEvent')(handler_fail) handler = Mock() eventlib.handler('myapp.CoolEvent')(handler) data = {'a': 1} event = 'myapp.CoolEvent' core.process(event, ejson.dumps(data)) logger.warning.assert_called_once_with( 'One of the handlers for the event "myapp.CoolEvent" has ' 'failed with the following exception: P0wned!!!') handler.assert_called_once_with(data)
def ddpp_sockjs_info(environ, start_response): """Inform client that WebSocket service is available.""" import random import ejson start_response( '200 OK', [ ('Content-Type', 'application/json; charset=UTF-8'), ] + common_headers(environ), ) yield ejson.dumps(collections.OrderedDict([ ('websocket', True), ('origins', [ '*:*', ]), ('cookie_needed', False), ('entropy', random.getrandbits(32)), ]))