Golang TCP proxy— Mocking in Go

TodlyCodly
3 min readMar 3, 2023

--

Photo by Joshua J. Cotten on Unsplash

My last article was about reverse proxy in .NET, its performance and exploration of available options provided by Microsoft to handle low level TCP communication. .NET Proxy Server — performance testing .NET with K6 | by TodlyCodly | Medium

This time I wanted to explore the same topic but using Golang. While clickbait comparison “which is faster Go vs C#” is tempting, I decided to summarize important aspect of language, I encountered during work:

Almost 90% of work I did occurred prior to first real TCP connection.

Free Mocking

For my project I had to:

  • Accept connection
  • Lookup DNS
  • Create TCP connection

Without more sophisticated functionalities, reverse proxy is just accepting connection on behalf of other service, calls real one and shuffles data between client and proxied. Obviously in real life this man-in-the-middle approach is not enough.

Core functionality of project required those 3 functions from net package — net — Go Packages.

I created three types, which matched signature of functions from above:

type DialFunc func(network string, raddr string) (net.Conn, error)
type ListenFunc func(network, address string) (net.Listener, error)
type DnsLookupFunc func(host string) ([]net.IP, error)

net.Conn and net.Listener are Interfaces, net.IP is:

type IP []byte

Then I could create :

type dummyListner struct {
...
}

type dummyConn struct {
...
}

Both implemented Interfaces to satisfy Golang duck typing system.

If you think that there is a lot of code to write, well yes if you need it but most of methods looked like this:

I implemented only bare minimum, needed to make my code work. Details here progxy/tcpAdapter_test.go at master · mes1234/progxy (github.com)

This way I could generate dummy Connections and Listeners, I could use for unit testing.

Example: save content of Write operation to do assertion in unit test:

func (dc *dummyConn) Write(b []byte) (n int, err error) {
copy(dc.bufOut, b)

return len(b), nil
}

Or mock Reader

func (dc *dummyConn) Read(b []byte) (n int, err error) {
<-dc.ticker.C
for i := range b {
b[i] = dc.value
}

return len(b), nil
}

In working code all I had to do was to specify which function from net package — net — Go Packages :

Summary

Ability to easily mock anything in Golang is perfect for TDD. You are not limited to mock only interfaces, everything can be mocked.

This method does not require third party libraries.

My code for this project can be found here:

mes1234/progxy (github.com)

Thank you for reading :)

--

--

TodlyCodly
TodlyCodly

Written by TodlyCodly

C# developer, who once was Pythonista and dreams of being Golang guy.

No responses yet