def echo_server(port=12345, pcon=NewLinerConn):
    """makes Echo server"""
    print("Making echo server")
    def echo_handler(request):
        print("echo server: "+request.body)
        request.write(request.body)

    server = PServer(echo_handler, pcon)
    server.listen(port)
    server.start()
    IOLoop.instance().start()
 def setUp(self):
     AsyncTestCase.setUp(self)
     self.response_callback = SpyMethod()
     self.server = PServer(self.response_callback, NetStringConn, io_loop = self.io_loop)
     self.server.handle_stream = SpyMethod()
     self.port = get_unused_port()
     self.server.listen(self.port)
class TestPServer1(AsyncTestCase):
    def setUp(self):
        AsyncTestCase.setUp(self)
        self.response_callback = SpyMethod()
        self.server = PServer(self.response_callback, NetStringConn, io_loop = self.io_loop)
        self.server.handle_stream = SpyMethod()
        self.port = get_unused_port()
        self.server.listen(self.port)

    def check_and_stop(self):
        assert self.io_loop._running
        assert self.server._started
        self.server.stop()
        self.io_loop.add_callback(self.stop)

    def test_start_stop_server(self):
        self.server.start()
        assert self.port in [s[1] for s in self.server.sockets_names()]
        self.io_loop.add_timeout(time.time()+.2, self.check_and_stop)
        self.wait(timeout=1)


    def check_handle_request(self):
        assert self.server.handle_stream.num_calls == 1

        # assert_that_method(self.server.handle_stream).was_called()
        # self.io_loop.add_callback(assert_that_method(self.server.handle_stream).was_called)

    def test_connection_sync(self):
        self.server.start()

        def connect():
            # following raises exception, if connection was'nt made
            sock = socket.create_connection(("127.0.0.1", self.port), .2)
            assert sock
            #assert_that_method(self.server.handle_stream).was_never_called()
            assert self.server.handle_stream.num_calls == 0
            sock.send(b'request\n')
            self.io_loop.add_callback(self.check_handle_request)
            self.io_loop.add_callback(self.stop)

        self.io_loop.add_callback(connect)
        self.wait(timeout=1)
    def setUp(self):
        AsyncTestCase.setUp(self)
        self.response_callback = echo_handler
        self.server = PServer(self.response_callback, NetStringConn, io_loop = self.io_loop)
        #self.server = proxy_spy(self.server)
        self.port = get_unused_port()
        self.server.listen(self.port)

        conn_info = socket.getaddrinfo('127.0.0.1', self.port, socket.AF_UNSPEC, socket.SOCK_STREAM)
        af, socktype, proto, conname, saddress = conn_info[0]
        # print(conn_info)
        # print(socket.AF_INET, socket.SOCK_STREAM)
        self.server_address = saddress
        self.sock = socket.socket(af, socktype, 6)                 # In the examples from net, the protocol version is 0
        self.stream = iostream.IOStream(self.sock, self.io_loop)   # client must have the same event loop, otherwise it will create new one
        self.server.start()
class TestPServer2(AsyncTestCase):
    def setUp(self):
        AsyncTestCase.setUp(self)
        self.response_callback = echo_handler
        self.server = PServer(self.response_callback, NetStringConn, io_loop = self.io_loop)
        #self.server = proxy_spy(self.server)
        self.port = get_unused_port()
        self.server.listen(self.port)

        conn_info = socket.getaddrinfo('127.0.0.1', self.port, socket.AF_UNSPEC, socket.SOCK_STREAM)
        af, socktype, proto, conname, saddress = conn_info[0]
        # print(conn_info)
        # print(socket.AF_INET, socket.SOCK_STREAM)
        self.server_address = saddress
        self.sock = socket.socket(af, socktype, 6)                 # In the examples from net, the protocol version is 0
        self.stream = iostream.IOStream(self.sock, self.io_loop)   # client must have the same event loop, otherwise it will create new one
        self.server.start()


    def test_connection_stream(self):
        """test próby połączenia trzech klientów: jeden z tego samego wątku, drugi z nowego.
        Pierwszy jest z tego samego wątku. Przy połączeniu uwstawia walidator <connected>.
        Drugi z nowego wątku zamyka przy połączeniu zatrzymuje główną pętlę i server.
        Trzeci jest z nowego procesu. Musi mieć nowego event loopa, który musi osobno wystartować (główny event loop startuje wraz z funkcją self.wati).
           Przy połączeniu event loop procesu zostaje zamknięty i proces się kończy.
           Gdyby się nie połączył, test się nie skończy"""
        connected_t = TEvent()

        def connect(io_loop, f_stop=None):
            if not f_stop:
                f_stop = io_loop.stop
            sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
            stream2 = iostream.IOStream(sock2, io_loop)
            stream2.connect(self.server_address, f_stop)
            if io_loop != self.io_loop:                       # we get other event loop
                logger.debug("Mam nowy  event loop. Startuje go")
                io_loop.start()


        self.stream.connect(self.server_address, connected_t.set)
        p=Process(target = connect, args=(self.get_new_ioloop(), ))  # proces musi operować na innym event loopie!
        p.start()
        t=Thread(target = connect, args=(self.io_loop, self.stop))   # wątek może mieć ten sam eventloop
        t.start()

        self.wait(timeout=1)
        assert connected_t.is_set()
        assert t.is_alive() is False
        p.join(0.1)
        if p.is_alive():
            p.terminate()
            self.fail("Process doesn't terminate normally - client doesn't connect to server")

    def test_req_resp(self):

        def client_work():
            num_writes = 1
            client.stop_cond = lambda obj: len(obj.resp)==num_writes
            #client.next_random()
            for i in range(num_writes):
                #self.io_loop.add_callback(lambda: client.write(str(random.random())))
                client.next_random()

        client = EchoClient(self.stream, self)
        self.stream.connect(self.server_address, client_work)

        self.wait(timeout=1)
        assert client.req == client.resp


    def raw_req_resp_session(self, length, callback):
        """make req resp session with NetString server.
        when session is finished, call callback
        """
        out = []
        def send(i):
            """Send some data in NetString format"""
            data = 'w'+str(i+1)                       # some test data
            data = "{}:{},".format(len(data), data) # constructing NetString
            logger.debug("send "+data)
            self.stream.write(data, on_write)

        def on_read(data):
            out.append(data)
            logger.debug("out: {}".format(data))
            i = len(out)
            if i == length:
                callback()
            else:
                send(i)

        def on_write():
            self.stream.read_bytes(5, on_read)

        send(0)

    def test_req_resp2(self):
        self.stream.connect(self.server_address,
                            lambda: self.raw_req_resp_session(1, self.stop))

        self.wait(timeout=1)


    def test_req_resp3(self):
        self.stream.connect(self.server_address,
                            lambda: self.raw_req_resp_session(4, self.stop))

        self.wait(timeout=1)

    def test_req_resp_noseq(self):
        """test if reads /writes where reads do not follow approprite writes don't succeed"""

        def work():
            self.stream.write("2:d1,")
            with pytest.raises(IOError):
                self.stream.write("2:d1,")
            self.io_loop.add_callback(self.stop)

        self.io_loop.add_callback(work)

        self.wait(timeout=1)


    def socket_raw_req_resp(self, d_in, d_out):
        time.sleep(.1)
        sock = socket.create_connection(self.server_address, .2)
        for d in d_out:
            logger.info("sending: "+ d)
            sock.send(d)
            r = sock.recv(8)
            try:
                r += sock.recv(8)  # net string are written sended in two phases, and depends on cache can be sent in two phases as well.
            except: pass
            logger.info("received: "+ r)
            d_in.append(r)
        self.stop()


    def test_req_resp_socket(self):
        d_out = ["2:d1,", "2:d2,"]
        d_in  = []
        t = Thread(target=self.socket_raw_req_resp,  args=(d_in, d_out))
        self.io_loop.add_callback(t.start)

        self.wait(timeout=1.2)
        assert d_in == d_out