Go语言 如何用testcontainers启动clickhouse容器?

jhiyze9q  于 2023-10-14  发布在  Go
关注(0)|答案(3)|浏览(111)

我想使用testcontainers进行集成测试。我需要测试一下点击室的存储器。
Docker镜像为yandex/clichouse-server
到目前为止,我的代码(主要是从testcontainers网站上的官方redis示例导入的):

ctx := context.Background()
    req := testcontainers.ContainerRequest{
        Image: "yandex/clickhouse-server",
        ExposedPorts: []string{"9000/tcp"},
    }
    chContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
        ContainerRequest: req,
        Started:          true,
    })
    require.NoError(t, err, "unexpected error while creating clickhouse container")

    endpoint, err := chContainer.Endpoint(ctx, "")
    require.NoError(t, err)

这在获取端点时抛出了一个错误port not found,我不确定从那里去哪里。

v64noz0r

v64noz0r1#

你试过在Testcontainers Go中使用wait API吗?https://github.com/testcontainers/testcontainers-go/tree/main/wait
有了它们,你就可以等待多个事情(甚至在同一时间):

  • 的日志条目
  • 港口准备就绪
  • sql查询
  • HTTP请求
  • 在容器中运行程序后的退出代码

您可以在存储库中找到有用的示例。也就是说,日志条目的示例:

ctx := context.Background()
    req := ContainerRequest{
        Image:        "docker.io/mysql:latest",
        ExposedPorts: []string{"3306/tcp", "33060/tcp"},
        Env: map[string]string{
            "MYSQL_ROOT_PASSWORD": "password",
            "MYSQL_DATABASE":      "database",
        },
        WaitingFor: wait.ForLog("test context timeout").WithStartupTimeout(1 * time.Second),
    }
    _, err := GenericContainer(ctx, GenericContainerRequest{
        ProviderType:     providerType,
        ContainerRequest: req,
        Started:          true,
    })

EDIT:一个更详细的例子,包括使用HTTP请求的等待策略:

const (
        dbName       = "crazy"
        fakeUser     = "jondoe"
        fakePassword = "bond girl"
    )

    ctx := context.Background()

    req := ContainerRequest{
        Image: "clickhouse/clickhouse-server",
        Env: map[string]string{
            "CLICKHOUSE_DB":       dbName,
            "CLICKHOUSE_USER":     fakeUser,
            "CLICKHOUSE_PASSWORD": fakePassword,
        },
        ExposedPorts: []string{
            "8123/tcp",
            "9000/tcp",
        },
        WaitingFor: wait.ForAll(
            wait.ForHTTP("/ping").WithPort("8123/tcp").WithStatusCodeMatcher(
                func(status int) bool {
                    return status == http.StatusOK
                },
            ),
        ),
    }

    clickhouseContainer, err := GenericContainer(ctx, GenericContainerRequest{
        ContainerRequest: req,
        Started:          true,
    })
    if err != nil {
        t.Fatal(err)
    }

    defer clickhouseContainer.Terminate(ctx)
s3fp2yjn

s3fp2yjn2#

仅供参考,从v0.23.0开始,存在一个用于testcontainers-go的ClickHouse模块:https://golang.testcontainers.org/modules/clickhouse/
你可以用一种非常简单的方式使用它:
添加依赖项:

go get github.com/testcontainers/testcontainers-go/modules/clickhouse

进口:

import "github.com/testcontainers/testcontainers-go/modules/clickhouse"

代码:

ctx := context.Background()

user := "clickhouse"
password := "password"
dbname := "testdb"

clickHouseContainer, err := clickhouse.RunContainer(ctx,
    testcontainers.WithImage("clickhouse/clickhouse-server:23.3.8.21-alpine"),
    clickhouse.WithUsername(user),
    clickhouse.WithPassword(password),
    clickhouse.WithDatabase(dbname),
    clickhouse.WithInitScripts(filepath.Join("testdata", "init-db.sh")),
    clickhouse.WithConfigFile(filepath.Join("testdata", "config.xml")),
)
if err != nil {
    panic(err)
}
defer func() {
    if err := clickHouseContainer.Terminate(ctx); err != nil {
        panic(err)
    }
}()
vc9ivgsu

vc9ivgsu3#

以下是我在试错后得到的结果:

const (
    dbName       = "crazy"
    fakeUser     = "jondoe"
    fakePassword = "bond girl"
)

// NewTestClickhouseDB spins up a new clickhouse container database
func NewTestClickhouseDB(t *testing.T) *sql.DB {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    t.Cleanup(cancel)
    req := testcontainers.ContainerRequest{
        Image: "clickhouse/clickhouse-server",
        Env: map[string]string{
            "CLICKHOUSE_DB":       dbName,
            "CLICKHOUSE_USER":     fakeUser,
            "CLICKHOUSE_PASSWORD": fakePassword,
        },

        ExposedPorts: []string{"9000/tcp"},
        WaitingFor:   wait.ForListeningPort("9000"),
    }
    chContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
        ContainerRequest: req,
        Started:          true,
    })
    require.NoError(t, err, "unexpected error while creating clickhouse container")

    p, err := chContainer.MappedPort(ctx, "9000")
    require.NoError(t, err, "expected mapped port to be found on clickhouse container")

    addr := fmt.Sprintf("127.0.0.1:%d", p.Int())
    conn := clickhouse.OpenDB(&clickhouse.Options{
        Addr: []string{addr},
        Auth: clickhouse.Auth{
            Database: dbName,
            Username: fakeUser,
            Password: fakePassword,
        },
    })

    for {
        if ctx.Err() != nil {
            t.Fatalf("time/out: ping db failed for 10seconds")
        }
        err := conn.Ping()
        if err != nil {
            time.Sleep(10 * time.Millisecond)
            continue
        }
        break
    }

    return conn
}

这将启动一个clickhouse容器,并在10秒后返回sql.Db或t/o。

相关问题