integration testing – Mocking Hashicorp vault in Go-ThrowExceptions

Exception or error:

Is there an easy way to mock Hashicorp vault in go tests ?

I created a service in Go that accesses Vault, and would like to create proper testing for it.

I didn’t find a simple solution I like (like moto in python).
I also tried using a vault in dev mode in docker (take the system test route) but I have trouble writing to it via API.
Ideas ?

How to solve:

Is there an easy way to mock HashiCorp Vault in Go tests?

Don’t. Use the real thing! HashiCorp helpfully provides utility functions for starting a server on the fly1. This makes your tests much more useful, and can often serve as an actionable guide for developers on how to setup local development servers too.

Here is a very basic example. The testing framework is very flexible (which also makes them fairly complicated). Refer to the package documentations for more options, including running multiple servers in HA mode. I found Vault’s own test cases very useful when setting up more complicated scenarios.

package main

import (
    "net"
    "testing"

    "github.com/hashicorp/vault/api"
    "github.com/hashicorp/vault/http"
    "github.com/hashicorp/vault/vault"
)

func TestVaultStuff(t *testing.T) {
    ln, client := createTestVault(t)
    defer ln.Close()

    // Pass the client to the code under test.
    myFunction(client)
}

func createTestVault(t *testing.T) (net.Listener, *api.Client) {
    t.Helper()

    // Create an in-memory, unsealed core (the "backend", if you will).
    core, keyShares, rootToken := vault.TestCoreUnsealed(t)
    _ = keyShares

    // Start an HTTP server for the core.
    ln, addr := http.TestServer(t, core)

    // Create a client that talks to the server, initially authenticating with
    // the root token.
    conf := api.DefaultConfig()
    conf.Address = addr

    client, err := api.NewClient(conf)
    if err != nil {
        t.Fatal(err)
    }
    client.SetToken(rootToken)

    // Setup required secrets, policies, etc.
    _, err = client.Logical().Write("secret/foo", map[string]interface{}{
        "secret": "bar",
    })
    if err != nil {
        t.Fatal(err)
    }

    return ln, client
}

1 They provide test servers for all of their projects, not just Vault. Mitchell Hashimoto explained the rational in his talk on advanced testing.

Answer´╝Ü

Because Go is a statically typed language we have to know the type of things at compile time. So to do this type of independent testing we need to create boundaries in our code that make logical sense in terms of testing.

Interfaces are created in Go to define these boundaries, so in this sense you want to create an interface between you and this third party library so that you can replace the inputs and outputs of the libraries functions/methods/types with ones that you can control and have defined conditions so that you can test how your code behaves to outputs or conditions of the third party.

See the below for examples of interfaces.

https://gobyexample.com/interfaces

if you share some example code perhaps we can be a little more specific and give you some code examples.

Leave a Reply

Your email address will not be published. Required fields are marked *