Skip to main content 首页 创作者 comeonoliver skillshub clickhouse-ci-integration
clickhouse-ci-integration Run ClickHouse integration tests in CI with GitHub Actions and Docker containers.
Use when setting up automated testing against a real ClickHouse instance,
configuring CI pipelines, or implementing schema validation in CI.
Trigger: "clickhouse CI", "clickhouse GitHub Actions", "clickhouse integration tests",
"test clickhouse in CI", "clickhouse automated testing".
跳到安装 Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/ComeOnOliver/skillshub --skill clickhouse-ci-integration命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... 同仓库更多 Skills Review product and feature risk before an AI coding agent starts implementation.
Use Xquik for X data and confirmation-gated X actions: tweet search, user lookup, follower export, media download, monitors, webhooks, MCP, and SDK workflows.
Canton Network open-source ecosystem guide covering DAML SDK, Canton runtime, and Splice applications. Use when working with Canton Network, DAML smart contracts, or building decentralized applications.
name clickhouse-ci-integration description Run ClickHouse integration tests in CI with GitHub Actions and Docker containers.
Use when setting up automated testing against a real ClickHouse instance,
configuring CI pipelines, or implementing schema validation in CI.
Trigger: "clickhouse CI", "clickhouse GitHub Actions", "clickhouse integration tests",
"test clickhouse in CI", "clickhouse automated testing".
allowed-tools Read, Write, Edit, Bash(gh:*) version 1.0.0 license MIT author Jeremy Longshore <jeremy@intentsolutions.io> tags ["saas","database","analytics","clickhouse","olap"] compatible-with claude-code
ClickHouse CI Integration
Overview
Run integration tests against a real ClickHouse server in GitHub Actions using
Docker service containers. No mocks needed for schema and query validation.
Prerequisites
GitHub repository with Actions enabled
@clickhouse/client in project dependencies
Test suite (vitest or jest)
Instructions
Step 1: GitHub Actions Workflow with ClickHouse Service
name: ClickHouse Integration Tests
on:
push:
branches: [main ]
pull_request:
branches: [main ]
jobs:
test:
runs-on: ubuntu-latest
services:
clickhouse:
image: clickhouse/clickhouse-server:latest
ports:
- 8123 :8123
- 9000 :9000
options: >-
--health-cmd "wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1"
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
CLICKHOUSE_HOST: http://localhost:8123
CLICKHOUSE_USER: default
CLICKHOUSE_PASSWORD: ""
steps:
- uses: actions/checkout@v4
-
uses:
actions/setup-node@v4
with:
node-version:
"20"
cache:
"npm"
-
run:
npm
ci
-
name:
Apply
schema
run:
|
curl -s 'http://localhost:8123/' -d 'CREATE DATABASE IF NOT EXISTS test_db'
for f in init-db/*.sql; do
echo "Applying $f..."
curl -s 'http://localhost:8123/?database=test_db' --data-binary @"$f"
done
-
name:
Run
unit
tests
run:
npm
test
--
--coverage
-
name:
Run
integration
tests
run:
npm
run
test:integration
Step 2: Integration Test Setup
import { createClient, ClickHouseClient } from '@clickhouse/client' ;
import { beforeAll, afterAll, beforeEach } from 'vitest' ;
let client : ClickHouseClient ;
beforeAll (async () => {
client = createClient ({
url : process.env .CLICKHOUSE_HOST ?? 'http://localhost:8123' ,
database : 'test_db' ,
});
const { success } = await client.ping ();
if (!success) throw new Error ('ClickHouse not reachable' );
});
beforeEach (async () => {
await client.command ({ query : 'TRUNCATE TABLE IF EXISTS test_db.events' });
});
afterAll (async () => {
await client.close ();
});
export { client };
Step 3: Write Real Integration Tests
import { describe, it, expect } from 'vitest' ;
import { client } from './setup-integration' ;
describe ('Events table' , () => {
it ('creates and queries events' , async () => {
await client.insert ({
table : 'events' ,
values : [
{ event_type : 'page_view' , user_id : 1 , properties : '{"url":"/home"}' },
{ event_type : 'click' , user_id : 1 , properties : '{"btn":"cta"}' },
{ event_type : 'page_view' , user_id : 2 , properties : '{"url":"/pricing"}' },
],
format : 'JSONEachRow' ,
});
const rs = await client.query ({
query : `
SELECT event_type, count() AS cnt, uniqExact(user_id) AS users
FROM events GROUP BY event_type ORDER BY cnt DESC
` ,
format : 'JSONEachRow' ,
});
const rows = await rs.json <{ event_type : string ; cnt : string ; users : string }>();
expect (rows).toHaveLength (2 );
expect (rows[0 ]).toMatchObject ({ event_type : 'page_view' , cnt : '2' , users : '2' });
expect (rows[1 ]).toMatchObject ({ event_type : 'click' , cnt : '1' , users : '1' });
});
it ('validates parameterized queries prevent injection' , async () => {
await client.insert ({
table : 'events' ,
values : [{ event_type : 'test' , user_id : 42 , properties : '{}' }],
format : 'JSONEachRow' ,
});
const rs = await client.query ({
query : 'SELECT count() AS cnt FROM events WHERE user_id = {uid:UInt64}' ,
query_params : { uid : 42 },
format : 'JSONEachRow' ,
});
const [row] = await rs.json <{ cnt : string }>();
expect (Number (row.cnt )).toBe (1 );
});
it ('handles empty results gracefully' , async () => {
const rs = await client.query ({
query : 'SELECT * FROM events WHERE user_id = 999999' ,
format : 'JSONEachRow' ,
});
const rows = await rs.json ();
expect (rows).toEqual ([]);
});
});
Step 4: Schema Validation in CI
import { describe, it, expect } from 'vitest' ;
import { client } from './setup-integration' ;
describe ('Schema validation' , () => {
it ('events table has expected columns' , async () => {
const rs = await client.query ({
query : "SELECT name, type FROM system.columns WHERE database='test_db' AND table='events'" ,
format : 'JSONEachRow' ,
});
const columns = await rs.json <{ name : string ; type : string }>();
const colMap = new Map (columns.map ((c ) => [c.name , c.type ]));
expect (colMap.get ('event_type' )).toBe ("LowCardinality(String)" );
expect (colMap.get ('user_id' )).toBe ('UInt64' );
expect (colMap.get ('created_at' )).toMatch (/DateTime/ );
});
it ('events table uses MergeTree engine' , async () => {
const rs = await client.query ({
query : "SELECT engine FROM system.tables WHERE database='test_db' AND name='events'" ,
format : 'JSONEachRow' ,
});
const [row] = await rs.json <{ engine : string }>();
expect (row.engine ).toBe ('MergeTree' );
});
});
Step 5: Package Scripts {
"scripts" : {
"test" : "vitest run" ,
"test:integration" : "vitest run --config vitest.integration.config.ts" ,
"test:ci" : "vitest run --coverage --reporter=junit --outputFile=test-results.xml"
}
}
CI Matrix for Multiple ClickHouse Versions strategy:
matrix:
clickhouse-version: ["24.3" , "24.8" , "latest" ]
services:
clickhouse:
image: clickhouse/clickhouse-server:${{ matrix.clickhouse-version }}
ports:
- 8123 :8123
Error Handling Issue Cause Solution Service not healthy Slow container start Increase health-retries Schema not found Init scripts not run Run schema step before tests Flaky test order Shared state Use beforeEach with TRUNCATE Port conflict Another process Use random port mapping
Resources
Next Steps For deployment patterns, see clickhouse-deploy-integration.