2

Golang newbie here :)
I have a redis client wrapper over go-redis and I want to test that it works properly. I have tried using miniredis to mock the redis server I would be connecting to, but I keep getting an error.

When I have everything in the same function then this works - I am able to run go-redis against the miniredis service. However, when I try to use my client it fails.
I've tried looking in the docs of go-redis and miniredis but couldn't find any answers. I've also tried having the miniredis server defined as a global variable but that didn't help as well.

client impl:

package redis

import (
    "errors"
    "fmt"
    "github.com/go-redis/redis"
    "go.uber.org/zap"
    "os"
    "strconv"
    "time"
)

var redisClient *redis.Client
var redisCert string

var redisURL = "localhost:6379"
var redisPass = ""
var redisDB = 0

type Client struct {
    redisClient *redis.Client
}
func newRedisClient() *Client {
    if os.Getenv("REDIS_URL") != "" {
        redisURL = os.Getenv("REDIS_URL")
    }
    if os.Getenv("REDIS_PASS") != "" {
        redisPass = os.Getenv("REDIS_PASS")
    }
    if os.Getenv("REDIS_DB") != "" {
        redisDB, _ = strconv.Atoi(os.Getenv("REDIS_DB"))
    }

    client := redis.NewClient(&redis.Options{
        Addr:      redisURL,
        Password:  redisPass,
        DB:        redisDB,
    })
    redisClient = client
    _, err := redisClient.Ping().Result()
    if err != nil {
        fmt.Println("Failed to connect", zap.Error(err))
        return nil
    }
    fmt.Println("Redis client is ready")
    return &Client{redisClient: client}
}

func (r *Client) Get(key string) (string, error) {
    res, err := redisClient.Get(key).Result()
    fmt.Println(res, err)
    if err == redis.Nil {
        return "", errors.New("Key Not Found")
    } else if err != nil {
        return "", err
    } else {
        return res, nil
    }

}

Test impl:

package redis

import (
    "github.com/alicebob/miniredis/v2"
    "gopkg.in/go-playground/assert.v1"
    "os"
    "testing"
)

var mr *miniredis.Miniredis

func TestGet(t *testing.T) {
    mr, _ = miniredis.Run()
    mr.Set("test1", "some")
    os.Setenv("REDIS_URL", mr.Addr())
    c := newRedisClient()
    r, err := c.Get("test1")
    assert.Equal(t, r, "")
    assert.Equal(t, err, "")
    mr.Close()
}

What am I doing wrong?

idohu
  • 133
  • 3
  • 7
  • What error exactly are you getting? – minitauros Mar 18 '20 at 08:32
  • @minitauros I'm getting EOF as the error. The ping call which ensures connection returns the following log error: `Failed to connect {"service": "redis", "error": "EOF"}` – idohu Mar 18 '20 at 09:23
  • And if you literally move the code from `TestGet` into your `newRedisClient` function, it works? – minitauros Mar 18 '20 at 09:57
  • yes. if the miniredis is started within the same function as the call to it, it works – idohu Mar 18 '20 at 10:20
  • Did you debug and find what the value of `redisURL` is that you connect to? Is it the same in both `newRedisClient` and what is returned by `mr.Addr()` in `TestGet()`? – minitauros Mar 18 '20 at 12:52
  • Also `mr, _ = miniredis.Run()` no err is returned there? – minitauros Mar 18 '20 at 12:52
  • I did - in both cases the url is similar (different port as it is generated randomly). and no error is returned - the mock server is working – idohu Mar 18 '20 at 13:47
  • That sounds extremely weird. What if you log the URL that miniredis has in test and enter it hard-coded into the redis client? Does it work then? Or does the URL constantly change? – minitauros Mar 19 '20 at 09:05
  • URL is changing with each run (or at least the port is changing). – idohu Mar 19 '20 at 17:33

2 Answers2

2

Mock failed through miniredis, you can use SetError: https://github.com/alicebob/miniredis/issues/36#issuecomment-642009898

func TestGet(t *testing.T) {
    mr, _ = miniredis.Run()

    // normal test
    // ...

    // error test
    mr.SetError("mock error")
    _, err = c.Get("test2")
    assert.EqualError(t, err, "mock error")

    mr.Close()
}
musique
  • 21
  • 3
0

Sorry it took so long to come with a reply. I've run your code locally and I do not get an error.

Normal file

package redis

import (
    "errors"
    "fmt"
    "os"
    "strconv"

    "github.com/go-redis/redis"
    "go.uber.org/zap"
)

var redisClient *redis.Client
var redisCert string

var redisURL = "localhost:6379"
var redisPass = ""
var redisDB = 0

type Client struct {
    redisClient *redis.Client
}

func newRedisClient() *Client {
    if os.Getenv("REDIS_URL") != "" {
        redisURL = os.Getenv("REDIS_URL")
    }
    if os.Getenv("REDIS_PASS") != "" {
        redisPass = os.Getenv("REDIS_PASS")
    }
    if os.Getenv("REDIS_DB") != "" {
        redisDB, _ = strconv.Atoi(os.Getenv("REDIS_DB"))
    }

    client := redis.NewClient(&redis.Options{
        Addr:     redisURL,
        Password: redisPass,
        DB:       redisDB,
    })
    redisClient = client
    _, err := redisClient.Ping().Result()
    if err != nil {
        fmt.Println("Failed to connect", zap.Error(err))
        return nil
    }
    fmt.Println("Redis client is ready")
    return &Client{redisClient: client}
}

func (r *Client) Get(key string) (string, error) {
    res, err := redisClient.Get(key).Result()
    if err == redis.Nil {
        return "", errors.New("Key Not Found")
    } else if err != nil {
        return "", err
    } else {
        return res, nil
    }

}

Test file

package redis

import (
    "fmt"
    "os"
    "testing"

    "github.com/alicebob/miniredis/v2"
)

var mr *miniredis.Miniredis

func TestGet(t *testing.T) {
    var err error

    mr, err = miniredis.Run()
    fmt.Printf("Run err: %v\n", err)
    fmt.Printf("mr.Addr(): %v\n", mr.Addr())

    err = mr.Set("test1", "some")
    fmt.Printf("Set err: %v\n", err)

    err = os.Setenv("REDIS_URL", mr.Addr())
    fmt.Printf("Setenv err: %v\n", err)

    c := newRedisClient()
    r, err := c.Get("test1")

    fmt.Printf("Get err: %v\n", err)
    fmt.Printf("r: %v\n", r)

    mr.Close()
}

Results

go test
Run err: <nil>
mr.Addr(): 127.0.0.1:54966
Set err: <nil>
Setenv err: <nil>
Redis client is ready
Get err: <nil>
r: some
PASS
ok      test/sof        0.536s
minitauros
  • 1,920
  • 18
  • 20