Author Archives: bullgare
Debugging go app in Jetbrains Goland on m1
First download a proper version of GoLand here — select .dmg (MacOS Apple Silicon) here (direct link — https://www.jetbrains.com/go/download/download-thanks.html?type=eap&platform=macM1&build=211.6556.11&code=GO). Then make sure you are using arm version of go (go version go1.16.2 darwin/arm64). If not, download and install arm version of golang (like «go1.16.2.darwin-arm64.pkg») from the list here — https://golang.org/dl/. Now it should work. With …
Run Steam on MacBook with m1 chip (apple silicon)
You need to install Crossover. Then you need to install Steam there. Good video explaining the process of installing Steam on Apple Silicon chips: https://www.youtube.com/watch?v=3TdCV7fn2CA Here is the list of supported games — https://applesilicongames.com/
Embedding assets to go binary in go 1.16
That’s how you can use it:
1 2 3 4 5 6 7 8 9 10 |
package server import "embed" // content holds our static web server content. //go:embed image/* template/* //go:embed html/index.html var content embed.FS data, _ := f.ReadFile("html/index.html") print(string(data)) |
Or embedding one file directly into a variable:
1 2 3 4 5 |
import _ "embed" //go:embed hello.txt var s string print(s) |
More details — https://golang.org/pkg/embed/
mmock for mocking microservices
It is a very easy to set up though pretty powerful tool with support for delays and handling query params. It also has a console for checking all the requests and corresponding responses matched. Here it is https://github.com/jmartin82/mmock. Below I describe a way to use it with docker-compose for local development.
Forward multiple kubernetes pods for local development
kubefwd is a great tool that can forward a lot of pods at once to your local machine. The only downside for me is that it touches your local /etc/hosts. That’s how I use it:
1 |
sudo KUBECONFIG=<path to your k8s config> kubefwd svc -l "app in (first-api, second-api, third-service)" |
It does not have huge documentation, but it is written in golang, and you can check how the source …
XDebug inside a docker container
That’s how you can debug your php app running in a docker container.
Force ipv4 for golang http client
Sometimes you want to prevent your http client from using ipv6/tcp6. That’s how you do it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
dialer := &net.Dialer{ Timeout: dialTimeout, KeepAlive: keepAliveTimeout, } transport := &http.Transport{ Proxy: http.ProxyFromEnvironment, ForceAttemptHTTP2: false, DialContext: func(ctx context.Context, network string, addr string) (net.Conn, error) { ipv4, err := resolveIPv4(addr) if err != nil { return nil, err } return dialer.DialContext(ctx, network, ipv4) }, } httpClient := &http.Client{ Transport: transport, Timeout: args.HTTPTimeout, } // resolveIPv4 resolves an address to IPv4 address. func resolveIPv4(addr string) (string, error) { url := strings.Split(addr, ":") m := new(dns.Msg) m.SetQuestion(dns.Fqdn(url[0]), dns.TypeA) m.RecursionDesired = true config, _ := dns.ClientConfigFromFile("/etc/resolv.conf") c := new(dns.Client) r, _, err := c.Exchange(m, net.JoinHostPort(config.Servers[0], config.Port)) if err != nil { return "", err } for _, ans := range r.Answer { if a, ok := ans.(*dns.A); ok { url[0] = a.A.String() } } return strings.Join(url, ":"), nil } |
Mocking for unit-tests and e2e-tests in golang
Some patterns to test your golang app. Mocking an interface
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
mockS3 := &mocks.S3API{} mockResultFn := func(input *s3.ListObjectsInput) *s3.ListObjectsOutput { output := &s3.ListObjectsOutput{} output.SetCommonPrefixes([]*s3.CommonPrefix{ &s3.CommonPrefix{ Prefix: aws.String("2017-01-01"), }, }) return output } // NB: .Return(...) must return the same signature as the method being mocked. // In this case it's (*s3.ListObjectsOutput, error). mockS3.On("ListObjects", mock.MatchedBy(func(input *s3.ListObjectsInput) bool { return input.Delimiter != nil && *input.Delimiter == "/" && input.Prefix == nil })).Return(mockResultFn, nil) listingInput := &s3.ListObjectsInput{ Bucket: aws.String("foo"), Delimiter: aws.String("/"), } listingOutput, err := mockS3.ListObjects(listingInput) if err != nil { panic(err) } for _, x := range listingOutput.CommonPrefixes { fmt.Printf("common prefix: %+v\n", *x) } |
https://github.com/vektra/mockery Mocking SQL database
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// a successful case func TestShouldUpdateStats(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() mock.ExpectBegin() mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectExec("INSERT INTO product_viewers").WithArgs(2, 3).WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectCommit() // now we execute our method if err = recordStats(db, 2, 3); err != nil { t.Errorf("error was not expected while updating stats: %s", err) } // we make sure that all expectations were met if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("there were unfulfilled expectations: %s", err) } } |
https://github.com/DATA-DOG/go-sqlmock Mocking HTTP server for unit-tests
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
handler := func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "<html><body>Hello World!</body></html>") } req := httptest.NewRequest("GET", "http://example.com/foo", nil) w := httptest.NewRecorder() handler(w, req) resp := w.Result() body, _ := ioutil.ReadAll(resp.Body) fmt.Println(resp.StatusCode) fmt.Println(resp.Header.Get("Content-Type")) fmt.Println(string(body)) |
https://golang.org/pkg/net/http/httptest/ Stubbing HTTP server for e2e-tests
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{ "host": "example.com", "method": "GET|POST|PUT|PATCH|... (Mandatory)", "path": "/your/path/:variable (Mandatory)", "queryStringParameters": { "name": ["value"], "name": ["value", "value"] }, "headers": { "name": ["value"] }, "cookies": { "name": "value" }, "body": "Expected Body" } |
https://github.com/jmartin82/mmock Mocking for e2e-tests with dockertest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
var db *sql.DB func TestMain(m *testing.M) { // uses a sensible default on windows (tcp/http) and linux/osx (socket) pool, err := dockertest.NewPool("") if err != nil { log.Fatalf("Could not connect to docker: %s", err) } // pulls an image, creates a container based on it and runs it resource, err := pool.Run("mysql", "5.7", []string{"MYSQL_ROOT_PASSWORD=secret"}) if err != nil { log.Fatalf("Could not start resource: %s", err) } // exponential backoff-retry, because the application in the container might not be ready to accept connections yet if err := pool.Retry(func() error { var err error db, err = sql.Open("mysql", fmt.Sprintf("root:secret@(localhost:%s)/mysql", resource.GetPort("3306/tcp"))) if err != nil { return err } return db.Ping() }); err != nil { log.Fatalf("Could not connect to docker: %s", err) } code := m.Run() // You can't defer this because os.Exit doesn't care for defer if err := pool.Purge(resource); err != nil { log.Fatalf("Could not purge resource: %s", err) } os.Exit(code) } func TestSomething(t *testing.T) { // db.Query() } |
https://github.com/ory/dockertest
Install go2 beta on MacOS
A quick guide on installing golang v2 development revision. It works for my MacOS Big Sur (with an Intel processor).