2009-12-29 7 views
5

Dans Go, une connexion TCP (net.Conn) est un io.ReadWriteCloser. Je voudrais tester mon code réseau en simulant une connexion TCP. Il y a deux exigences que j'ai:Simulation d'une connexion tcp dans Go

  1. les données à lire sont stockées dans une chaîne
  2. chaque fois que les données sont écrites, je voudrais qu'il soit stocké dans une sorte de tampon que je peux accéder à plus tard

Existe-t-il une structure de données pour cela, ou un moyen facile d'en créer une?

Répondre

3

Pourquoi ne pas utiliser bytes.Buffer? C'est un io.ReadWriter et a une méthode String pour obtenir les données stockées. Si vous devez faire un io.ReadWriteCloser, vous pouvez définir votre propre Type:

type CloseableBuffer struct { 
    bytes.Buffer 
} 

et définir une méthode Close:

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

EDIT: J'ai roulé cette réponse dans un paquet qui rend les choses un peu plus simple - voir ici: https://github.com/jordwest/mock-conn


Alors que la solution d'Ivan travaillera pour simp Dans les cas, gardez à l'esprit qu'une véritable connexion TCP est en fait deux tampons, ou plutôt des tuyaux. Par exemple:

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

Si vous utilisez un seul tampon que le serveur à la fois lit et écrit, vous pourriez finir avec le serveur parlant à lui-même.

Voici une solution qui vous permet de transmettre un type MockConn en tant que ReadWriteCloser au serveur. Les fonctions Read, Write et Close permettent simplement d'accéder aux fonctions de l'extrémité du serveur.

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, 
    } 
} 

Lorsque se moquant d'une connexion « serveur », il suffit de passer le MockConn en place où vous utiliseriez le net.Conn (ce implémente bien sûr l'interface ReadWriteCloser seulement, vous pouvez facilement ajouter des méthodes factices pour LocalAddr() etc si vous avez besoin soutenir l'interface complète net.Conn)

Dans vos tests, vous pouvez agir en tant que client en lisant et en écrivant aux champs ClientReader et ClientWriter au besoin:

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

Je suis un peu confus. Le code que vous avez posté ici ne semble pas correspondre à ce que vous avez mis dans github. –

2

Aucune idée si cela existait lorsque la question a été posée, mais vous voulez probablement net.Pipe() qui vous fournit deux instances net.Conn en duplex intégral qui sont liés les uns aux autres