きょこみのーと

元六本木でGo書いてました。今はVRでGo書いてます。

CircleCI上でdynamodb-localを使ったgo testを実行する

はじめに

本当は、dynamodbを呼び出す箇所をinterface化してgolang/mockとかでmockしてtestするほうが良い思います。

ただ、そうもいかない状況とかもあるのでdynamodb-localでtest用のregionを使ってtestする方法を紹介したいと思います。

例)とあるテーブルにupdateとgetするコード

以下の updateExampleDatafetchExampleDataをテストしたいという状況。

package main

import (
    "fmt"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/guregu/dynamo"
    "github.com/labstack/gommon/log"
)

const (
    region    = "us-west-2"
    endpoint  = "http://127.0.0.1:7777"
    tableName = "example-table"
)

var (
    dyn *dynamo.DB
)

type exampleDynamoTable struct {
    ID      int `dynamo:"ID,hash"`
    Count   int
    Message string
}

func main() {
    dyn = dynamo.New(session.New(), &aws.Config{
        Region:   aws.String(region),
        Endpoint: aws.String(endpoint),
    })

    if err := dyn.CreateTable(tableName, exampleDynamoTable{}).Run(); err != nil {
        fmt.Println() // 二度目のtable作成は雑にスルーしてる
    }

    // tableのデータを更新
    id := 1
    if err := updateExampleData(id, 100, "test"); err != nil {
        log.Fatal(err)
    }

    // 更新したデータを取得
    exampleData, err := fetchExampleData(id)
    if err != nil {
        log.Fatal(err)
    }
 
    fmt.Printf("%#v\n", exampleData)
}

func updateExampleData(id int, count int, message string) error {
    updater := dyn.Table(tableName).Update("ID", id)
    updater.Set("Count", count)
    updater.Set("Message", message)
    return updater.Run()
}

func fetchExampleData(id int) (exampleDynamoTable, error) {
    var e exampleDynamoTable
    return e, dyn.Table(tableName).Get("ID", id).One(&e)
}

testコード

package main

import (
    "fmt"
    "testing"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/guregu/dynamo"
    "github.com/stretchr/testify/assert"
)

func TestExampleData(t *testing.T) {
    as := assert.New(t)

    dyn = dynamo.New(session.New(), &aws.Config{
        Region:   aws.String("test-region"),
        Endpoint: aws.String(endpoint),
    })

    // 前回のデータを雑に削除
    if err := dyn.Table(tableName).DeleteTable().Run(); err != nil {
        fmt.Println()
    }
    // テーブルを雑に作成
    if err := dyn.CreateTable(tableName, exampleDynamoTable{}).Run(); err != nil {
        fmt.Println()
    }

    testCase := exampleDynamoTable{
        ID:      2,
        Count:   300,
        Message: "hoge",
    }

    as.NoError(updateExampleData(testCase.ID, testCase.Count, testCase.Message))

    exampleData, err := fetchExampleData(testCase.ID)
    as.NoError(err)
    as.EqualValues(exampleData, testCase)
}

ローカル環境でのtest

以下のようなdocker-compose.ymlを用意して、dockerでdynamodb-localを立ち上げてtestを実行すればOKです。 (別にbrewとかで入れても良いです)

version: '2'
services:
  dynamodb:
    image: tray/dynamodb-local
    command: tray/dynamodb-local -port 7777
    ports:
      - "7777:7777"

test実行

$ go test . -v
=== RUN   TestExampleData
{
  ExpressionAttributeNames: {
    #sQ291bnQ: "Count"
  },
  ExpressionAttributeValues: {
    :v0: {
      N: "300"
    },
    :v1: {
      S: "hoge"
    }
  },
  Key: {
    ID: {
      N: "2"
    }
  },
  ReturnValues: "NONE",
  TableName: "example-table",
  UpdateExpression: "SET #sQ291bnQ = :v0, Message = :v1"
}
--- PASS: TestExampleData (0.21s)
PASS
ok      github.com/kyokomi/example-circleci-dynamodb-go 0.235s

CircleCIの設定

circle.yml

# dynamodb-local
# https://discuss.circleci.com/t/how-to-install-dynamodb-local/2018/2
machine:
  environment:
    _JAVA_OPTIONS: "-Xms512m -Xmx1024m"
  java:
    version: openjdk7
  post:
    - curl -k -L -o dynamodb-local.tgz http://dynamodb-local.s3-website-us-west-2.amazonaws.com/dynamodb_local_latest.tar.gz
    - tar -xzf dynamodb-local.tgz
    - java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -port 7777:
        background: true

checkout:
  pre:
    - go env
    - go version

コンソールからは、 AWS permissionだけ設定しておきましょう

f:id:kyokomi:20160909143730p:plain

awsのライブラリとdynamodb-localが作成するDBの名前とかに使うだけなので、上記のような適当な値でOKです。

実行結果

f:id:kyokomi:20160909145406p:plain

f:id:kyokomi:20160909145348p:plain

https://circleci.com/gh/kyokomi/example-circleci-dynamodb-go/2

ライブラリ

ちなみにdynamodbのライブラリはこちらを使ってます。mgoっぽく使えて使いやすくて便利です。

github.com

サンプルコード

サンプルコードはすべて、こちらに上げておきましたので宜しければご覧ください。

github.com