コード例 #1
0
 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}))
コード例 #2
0
 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
コード例 #3
0
 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"
     }])
コード例 #4
0
 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}"}])
コード例 #5
0
    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}])
コード例 #6
0
    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"}])
コード例 #7
0
    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")
コード例 #8
0
 def setUp(self):
     LandscapeTest.setUp(self)
     self.plugin = StubDataWatchingPlugin(1)
     self.plugin.register(self.monitor)
     self.mstore.add_schema(Message("wubble", {"wubblestuff": Int()}))
コード例 #9
0
 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'
コード例 #10
0
 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})
コード例 #11
0
 def test_type(self):
     """The C{type} should be introspectable on L{Message} objects."""
     schema = Message("foo", {})
     self.assertEqual(schema.type, "foo")
コード例 #12
0
 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"})
コード例 #13
0
 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})
コード例 #14
0
 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"})
コード例 #15
0
 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})