def test_with_unknown_fields(self): """ The L{Message} schema discards unknown fields when coercing values. """ schema = Message("foo", {}) self.assertEqual({"type": "foo"}, schema.coerce({"type": "foo", "crap": 123}))
def create_store(self): persist = Persist(filename=self.persist_filename) store = MessageStore(persist, self.temp_dir, 20) store.set_accepted_types(["empty", "data", "resynchronize"]) store.add_schema(Message("empty", {})) store.add_schema(Message("empty2", {})) store.add_schema(Message("data", {"data": Bytes()})) store.add_schema(Message("unaccepted", {"data": Bytes()})) store.add_schema(Message("resynchronize", {})) return store
def test_atomic_message_writing(self): """ If the server gets unplugged halfway through writing a file, the message should not be half-written. """ self.store.add_schema(Message("data", {"data": Int()})) self.store.add({"type": "data", "data": 1}) # We simulate it by creating a fake file which raises halfway through # writing a file. mock_open = mock.mock_open() with mock.patch("landscape.lib.fs.open", mock_open): mock_open().write.side_effect = IOError("Sorry, pal!") # This kind of ensures that raising an exception is somewhat # similar to unplugging the power -- i.e., we're not relying # on special exception-handling in the file-writing code. self.assertRaises(IOError, self.store.add, { "type": "data", "data": 2 }) mock_open.assert_called_with(mock.ANY, "wb") mock_open().write.assert_called_once_with(mock.ANY) self.assertEqual(self.store.get_pending_messages(), [{ "type": "data", "data": 1, "api": b"3.2" }])
def test_message_is_actually_coerced(self): """ The message that eventually gets sent should be the result of the coercion. """ self.store.add_schema(Message("data", {"data": Unicode()})) self.store.add({"type": "data", "data": u"\N{HIRAGANA LETTER A}".encode("utf-8"), "api": b"3.2"}) self.assertEqual(self.store.get_pending_messages(), [{"type": "data", "api": b"3.2", "data": u"\N{HIRAGANA LETTER A}"}])
def test_message_is_coerced_to_its_api_schema(self): """ A message gets coerced to the schema of the API its targeted to. """ self.store.set_server_api(b"3.3") # Add a new schema for the 'data' message type, with a slightly # different definition. self.store.add_schema(Message("data", {"data": Int()}, api=b"3.3")) # The message is coerced against the new schema. self.store.add({"type": "data", "data": 123}) self.assertEqual( self.store.get_pending_messages(), [{"type": "data", "api": b"3.3", "data": 123}])
def test_message_is_coerced_to_highest_compatible_api_schema(self): """ A message gets coerced to the schema of the highest compatible API version. """ # Add a new schema for the 'data' message type, with a slightly # different definition. self.store.set_server_api(b"3.2") self.store.add_schema(Message("data", {"data": Int()}, api=b"3.3")) # The message is coerced against the older schema. self.store.add({"type": "data", "data": b"foo"}) self.assertEqual( self.store.get_pending_messages(), [{"type": "data", "api": b"3.2", "data": b"foo"}])
def test_per_api_payloads(self): """ When sending messages to the server, the exchanger should split messages with different APIs in different payloads, and deliver them to the right API on the server. """ types = ["a", "b", "c", "d", "e", "f"] self.mstore.set_accepted_types(types) for t in types: self.mstore.add_schema(Message(t, {})) self.exchanger.exchange() # No messages queued yet. Server API should default to # the client API. payload = self.transport.payloads[-1] self.assertMessages(payload["messages"], []) self.assertEqual(payload.get("client-api"), CLIENT_API) self.assertEqual(payload.get("server-api"), b"3.2") self.assertEqual(self.transport.message_api, b"3.2") self.mstore.add({"type": "a", "api": b"1.0"}) self.mstore.add({"type": "b", "api": b"1.0"}) self.mstore.add({"type": "c", "api": b"1.1"}) self.mstore.add({"type": "d", "api": b"1.1"}) self.exchanger.exchange() payload = self.transport.payloads[-1] self.assertMessages(payload["messages"], [{"type": "a", "api": b"1.0"}, {"type": "b", "api": b"1.0"}]) self.assertEqual(payload.get("client-api"), CLIENT_API) self.assertEqual(payload.get("server-api"), b"1.0") self.assertEqual(self.transport.message_api, b"1.0") self.exchanger.exchange() payload = self.transport.payloads[-1] self.assertMessages(payload["messages"], [{"type": "c", "api": b"1.1"}, {"type": "d", "api": b"1.1"}]) self.assertEqual(payload.get("client-api"), CLIENT_API) self.assertEqual(payload.get("server-api"), b"1.1") self.assertEqual(self.transport.message_api, b"1.1")
def setUp(self): LandscapeTest.setUp(self) self.plugin = StubDataWatchingPlugin(1) self.plugin.register(self.monitor) self.mstore.add_schema(Message("wubble", {"wubblestuff": Int()}))
def setUp(self): super(MessageExchangeTest, self).setUp() self.mstore.add_schema(Message("empty", {})) self.mstore.add_schema(Message("data", {"data": Int()})) self.mstore.add_schema(Message("holdme", {})) self.identity.secure_id = 'needs-to-be-set-for-tests-to-pass'
def test_coerce(self): """The L{Message} schema should be very similar to KeyDict.""" schema = Message("foo", {"data": Int()}) self.assertEqual( schema.coerce({"type": "foo", "data": 3}), {"type": "foo", "data": 3})
def test_type(self): """The C{type} should be introspectable on L{Message} objects.""" schema = Message("foo", {}) self.assertEqual(schema.type, "foo")
def test_optional(self): """The L{Message} schema should allow additional optional keys.""" schema = Message("foo", {"data": Int()}, optional=["data"]) self.assertEqual(schema.coerce({"type": "foo"}), {"type": "foo"})
def test_api_None(self): """L{Message} schemas should accept None for C{api}.""" schema = Message("baz", {}) self.assertEqual( schema.coerce({"type": "baz", "api": None}), {"type": "baz", "api": None})
def test_api(self): """L{Message} schemas should accept C{api} keys.""" schema = Message("baz", {}) self.assertEqual( schema.coerce({"type": "baz", "api": b"whatever"}), {"type": "baz", "api": b"whatever"})
def test_timestamp(self): """L{Message} schemas should accept C{timestamp} keys.""" schema = Message("bar", {}) self.assertEqual( schema.coerce({"type": "bar", "timestamp": 0.33}), {"type": "bar", "timestamp": 0.33})