def test_calls_transit(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp.receive_file(42, "path/to/file")

        self.transit.receive_file.assert_called_with(42, "path/to/file")
    def test_is_receiving_file_calls_transit(self, mocker):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        self.transit.is_receiving_file = mocker.sentinel.value

        assert_that(ftp.is_receiving_file(), is_(mocker.sentinel.value))
    def test_calls_transit(self, mocker):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp.send_file(42, "test_file")

        self.transit.send_file.assert_called_with(42, "test_file")
    def test_got_code_emits_signal(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp._wormhole_delegate.wormhole_got_code("1-a-code")

        self.signals.code_received.emit.assert_called_once_with("1-a-code")
    def test_transit_message_calls_transit(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp._wormhole_delegate.wormhole_got_message(b'{"transit": "contents"}')

        self.transit.handle_transit.assert_called_with("contents")
    def test_can_send_data(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp.send_message("hello world")

        self.wormhole.send_message.assert_called_with(
            b'{"offer": {"message": "hello world"}}')
    def test_file_offer_calls_transit(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp._wormhole_delegate.wormhole_got_message(
            b'{"offer": {"file": "test"}}')

        self.transit.handle_offer.assert_called_with({"file": "test"})
    def test_can_close_the_wormhole_and_transit(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp.shutdown()

        self.wormhole.close.assert_called()
        self.transit.close.assert_called()
    def test_transit_progress_emits_signal(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp._transit_delegate.transit_progress(42, 50, 100)

        self.signals.file_transfer_progress.emit.assert_called_once_with(
            42, 50, 100)
    def test_invalid_offer_emits_respond_error(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)
        self.transit.handle_offer.side_effect = RespondError("test")

        ftp.open(None)
        ftp._wormhole_delegate.wormhole_got_message(b'{"offer": "illegal"}')

        self.signals.respond_error.emit.assert_called()
    def test_emits_signal_once_wormhole_is_closed(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp.close()
        ftp._wormhole_delegate.wormhole_closed(result="ok")

        self.signals.wormhole_closed.emit.assert_called()
    def test_message_offer_emits_message_received(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp._wormhole_delegate.wormhole_got_message(
            b'{"offer": {"message": "test"}}')

        self.signals.message_received.emit.assert_called_with("test")
    def test_transit_complete_emits_signal(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp._transit_delegate.transit_complete(42, "filename")

        self.signals.file_transfer_complete.emit.assert_called_once_with(
            42, "filename")
    def test_got_versions_emits_signals(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp._wormhole_delegate.wormhole_got_versions("versions")

        self.signals.versions_received.emit.assert_called_once_with("versions")
        self.signals.wormhole_open.emit.assert_called_once()
    def test_doesnt_send_message_if_not_connected(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)
        versions_received = self.connect(self.signals.versions_received)

        ftp.open(None)
        versions_received({"v0": {"mode": "connect"}})
        ftp.shutdown()

        self.wormhole.send_message.assert_not_called()
    def test_message_offer_sends_answer(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp._wormhole_delegate.wormhole_got_message(
            b'{"offer": {"message": "test"}}')

        self.wormhole.send_message.assert_called_with(
            b'{"answer": {"message_ack": "ok"}}')
    def test_message_ack_with_ok_emits_message_sent(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp._wormhole_delegate.wormhole_got_message(
            b'{"answer": {"message_ack": "ok"}}')

        self.signals.message_sent.emit.assert_called_with(True)
        self.signals.error.emit.assert_not_called()
    def test_sends_error_to_peer(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)
        respond_error = self.connect(self.signals.respond_error)

        ftp.open(None)
        respond_error(OfferError("Invalid Offer"), "traceback")

        self.wormhole.send_message.assert_called_with(
            b'{"error": "Invalid Offer"}')
    def test_doesnt_send_message_if_peer_connect_mode_not_supported(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)
        wormhole_open = self.connect(self.signals.wormhole_open)

        ftp.open(None)
        wormhole_open()
        ftp.shutdown()

        self.wormhole.send_message.assert_not_called()
    def test_file_ack_with_ok_calls_transit(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp._wormhole_delegate.wormhole_got_message(
            b'{"answer": {"file_ack": "ok"}}')

        self.transit.handle_file_ack.assert_called_once()
        self.signals.error.emit.assert_not_called()
    def test_wormhole_closed_after_receiving_message_ack_if_connect_mode_not_supported(
        self, ):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp._wormhole_delegate.wormhole_got_message(
            b'{"answer": {"message_ack": "ok"}}')

        self.wormhole.close.assert_called()
    def test_transit_error_emits_signal(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp._transit_delegate.transit_error(ValueError("error"), "traceback")

        self.signals.error.emit.assert_called_once()
        args = self.signals.error.emit.call_args[0]
        assert_that(args[0], is_(ValueError))
        assert_that(args[1], is_("traceback"))
    def test_wormhole_closed_after_receiving_file_if_connect_mode_not_supported(
            self):
        ftp = FileTransferProtocol(self.reactor, self.signals)
        file_transfer_complete = self.connect(
            self.signals.file_transfer_complete)

        ftp.open(None)
        file_transfer_complete(42, "filename")

        self.wormhole.close.assert_called()
    def test_invalid_json_emits_error(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp._wormhole_delegate.wormhole_got_message(b'{"invalid": {"json"}')

        self.signals.error.emit.assert_called_once()
        args = self.signals.error.emit.call_args[0]
        assert_that(args[0], is_(MessageError))
        assert_that(args[1], starts_with("Traceback"))
    def test_refused_error_closes_wormhole(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)
        respond_error = self.connect(self.signals.respond_error)

        ftp.open(None)
        respond_error(RefusedError("User Cancelled"), "traceback")

        self.wormhole.send_message.assert_called_with(
            b'{"error": "User Cancelled"}')
        self.wormhole.close.assert_called()
        self.signals.error.emit.assert_not_called()
    def test_wormhole_not_closed_after_receiving_message_if_connect_mode_supported(
        self, ):
        ftp = FileTransferProtocol(self.reactor, self.signals)
        versions_received = self.connect(self.signals.versions_received)

        ftp.open(None)
        versions_received({"v0": {"mode": "connect"}})
        ftp._wormhole_delegate.wormhole_got_message(
            b'{"offer": {"message": "test"}}')

        self.wormhole.close.assert_not_called()
    def test_file_ack_with_error_emits_error(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)

        ftp.open(None)
        ftp._wormhole_delegate.wormhole_got_message(
            b'{"answer": {"file_ack": "error"}}')

        self.signals.error.emit.assert_called_once()
        args = self.signals.error.emit.call_args[0]
        assert_that(args[0], is_(SendFileError))
        assert_that(args[1], starts_with("Traceback"))
    def test_emits_error_signals(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)
        respond_error = self.connect(self.signals.respond_error)

        ftp.open(None)
        respond_error(OfferError("Invalid Offer"), "traceback")

        self.signals.error.emit.assert_called()
        args = self.signals.error.emit.call_args[0]
        assert_that(args[0], is_(OfferError))
        assert_that(args[1], is_("traceback"))
    def test_sends_message_if_connected_and_connect_mode_supported(self):
        ftp = FileTransferProtocol(self.reactor, self.signals)
        wormhole_open = self.connect(self.signals.wormhole_open)
        versions_received = self.connect(self.signals.versions_received)

        ftp.open(None)
        wormhole_open()
        versions_received({"v0": {"mode": "connect"}})
        ftp.shutdown()

        self.wormhole.send_message.assert_called_with(
            b'{"command": "shutdown"}')
    def test_creates_a_wormhole(self, mocker):
        ftp = FileTransferProtocol(self.reactor, self.signals)
        ftp.open(None)

        self.wormhole_create.assert_called_with(
            appid="lothar.com/wormhole/text-or-file-xfer",
            relay_url="ws://relay.magic-wormhole.io:4000/v1",
            reactor=self.reactor,
            delegate=mocker.ANY,
            versions={"v0": {
                "mode": "connect"
            }},
        )