2009-12-29 30 views
5

En Go, una conexión TCP (net.Conn) es un io.ReadWriteCloser. Me gustaría probar mi código de red simulando una conexión TCP. Hay dos requisitos que tengo:Simular una conexión tcp en Go

  1. los datos que leer se almacena en una cadena
  2. cada vez que los datos se escriben, me gustaría que se almacena en algún tipo de tampón que puedo acceder más tarde

¿Hay una estructura de datos para esto, o una manera fácil de hacer una?

Respuesta

3

¿Por qué no usar bytes.Buffer? Es un io.ReadWriter y tiene un método String para obtener los datos almacenados. Si usted necesita para que sea un io.ReadWriteCloser, se podría definir es el propietario Tipo:

type CloseableBuffer struct { 
    bytes.Buffer 
} 

y definir un método Close:

func (b *CloseableBuffer) Close() error { 
    return nil 
} 
5

EDITAR: He rodado esta respuesta en un paquete que hace las cosas un poco más simple - ver aquí: https://github.com/jordwest/mock-conn


mientras que la solución de Ivan funcionará para siend En los casos, tenga en cuenta que una conexión TCP real es en realidad dos búferes, o más bien tuberías. Por ejemplo:

Server | Client 
---------+--------- 
    reads <=== writes 
writes ===> reads 

Si utiliza una única memoria intermedia que tanto el servidor lee y escribe en, usted podría terminar con el servidor de hablar a sí mismo.

Aquí hay una solución que le permite pasar un tipo MockConn como ReadWriteCloser al servidor. Las funciones Read, Write y Close simplemente realizan un proxy a través de las funciones en el extremo de las canalizaciones del servidor.

type MockConn struct { 
    ServerReader *io.PipeReader 
    ServerWriter *io.PipeWriter 

    ClientReader *io.PipeReader 
    ClientWriter *io.PipeWriter 
} 

func (c MockConn) Close() error { 
    if err := c.ServerWriter.Close(); err != nil { 
     return err 
    } 
    if err := c.ServerReader.Close(); err != nil { 
     return err 
    } 
    return nil 
} 

func (c MockConn) Read(data []byte) (n int, err error) { return c.ServerReader.Read(data) } 
func (c MockConn) Write(data []byte) (n int, err error) { return c.ServerWriter.Write(data) } 

func NewMockConn() MockConn { 
    serverRead, clientWrite := io.Pipe() 
    clientRead, serverWrite := io.Pipe() 

    return MockConn{ 
     ServerReader: serverRead, 
     ServerWriter: serverWrite, 
     ClientReader: clientRead, 
     ClientWriter: clientWrite, 
    } 
} 

Cuando burlarse de una conexión de 'servidor', sólo tiene que pasar el MockConn en el lugar de donde se usaría el net.Conn (esto obviamente implementa la interfaz ReadWriteCloser solamente, usted podría agregar fácilmente métodos ficticias para LocalAddr() etc si es necesario apoyar la interfaz completa net.Conn)

En sus pruebas que puede actuar como el cliente mediante la lectura y la escritura en los ClientReader y ClientWriter campos según sea necesario:

func TestTalkToServer(t *testing.T) { 
    /* 
    * Assumes that NewMockConn has already been called and 
    * the server is waiting for incoming data 
    */ 

    // Send a message to the server 
    fmt.Fprintf(mockConn.ClientWriter, "Hello from client!\n") 

    // Wait for the response from the server 
    rd := bufio.NewReader(mockConn.ClientReader) 
    line, err := rd.ReadString('\n') 

    if line != "Hello from server!" { 
     t.Errorf("Server response not as expected: %s\n", line) 
    } 
} 
+0

Estoy algo confundido. El código que publicaste aquí no parece coincidir con lo que pusiste en github. –

2

No tengo idea de si esto existió cuando se formuló la pregunta, pero es probable que desee net.Pipe() que le proporciona dos instancias de dúplex completo net.Conn que están vinculadas entre sí

Cuestiones relacionadas