Skip to content

Commit 7c5008d

Browse files
committed
Added all unit-tests to CI
1 parent ea8ad1e commit 7c5008d

File tree

21 files changed

+510
-69
lines changed

21 files changed

+510
-69
lines changed

.github/workflows/go.yml

Lines changed: 197 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,208 @@ jobs:
1313

1414
build:
1515
runs-on: ubuntu-latest
16+
17+
services:
18+
# Database service containers
19+
mariadb-vector:
20+
image: mariadb:11.7.2
21+
env:
22+
MARIADB_DATABASE: perfkit_db_ci
23+
MARIADB_USER: user
24+
MARIADB_PASSWORD: password # example value of a secret
25+
MARIADB_ROOT_PASSWORD: password # example value of a secret
26+
ports:
27+
- 3306:3306
28+
# Additional options to handle GitHub Actions environment limitations
29+
options: >-
30+
--health-cmd="healthcheck.sh --connect --innodb_initialized"
31+
--health-interval=10s
32+
--health-timeout=5s
33+
--health-retries=3
34+
35+
postgres:
36+
image: ankane/pgvector:v0.5.1
37+
env:
38+
POSTGRES_USER: root
39+
POSTGRES_PASSWORD: password # example value of a secret
40+
POSTGRES_DB: perfkit_pg_vector_db_ci
41+
ports:
42+
- 5432:5432
43+
# Health check to wait until postgres is ready
44+
options: >-
45+
--health-cmd pg_isready
46+
--health-interval 10s
47+
--health-timeout 5s
48+
--health-retries 5
49+
50+
mssql:
51+
image: mcr.microsoft.com/mssql/server:2019-latest
52+
env:
53+
ACCEPT_EULA: 'Y'
54+
MSSQL_SA_PASSWORD: MyP@ssw0rd123 # example value of a secret compliant with MS SQL Server password policy
55+
MSSQL_PID: Developer
56+
MSSQL_TCP_PORT: 1433
57+
MSSQL_COLLATION: SQL_Latin1_General_CP1_CI_AS
58+
MSSQL_DB: perfkit_db_ci
59+
MSSQL_USER: perfkit_db_runner
60+
MSSQL_PASSWORD: MyP@ssw0rd123 # example value of a secret compliant with MS SQL Server password policy
61+
MSSQL_DATA_DIR: /var/opt/mssql/data
62+
MSSQL_LOG_DIR: /var/opt/mssql/log
63+
MSSQL_BACKUP_DIR: /var/opt/mssql/backup
64+
MSSQL_AGENT_ENABLED: true
65+
ports:
66+
- 1433:1433
67+
68+
cassandra:
69+
image: cassandra:4.0
70+
env:
71+
CASSANDRA_USER: admin
72+
CASSANDRA_PASSWORD: password # example value of a secret
73+
ports:
74+
- "9042:9042"
75+
options: >-
76+
--health-cmd="cqlsh -u cassandra -p cassandra 127.0.0.1 9042 --execute='describe keyspaces'"
77+
--health-interval=20s
78+
--health-timeout=10s
79+
--health-retries=15
80+
--health-start-period=60s
81+
82+
clickhouse:
83+
image: clickhouse/clickhouse-server:24.10-alpine
84+
env:
85+
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
86+
CLICKHOUSE_DB: perfkit_db_ci
87+
CLICKHOUSE_USER: username
88+
CLICKHOUSE_PASSWORD: password # example value of a secret
89+
ports:
90+
- "8123:8123"
91+
- "9000:9000"
92+
93+
elasticsearch:
94+
image: docker.elastic.co/elasticsearch/elasticsearch:8.15.1
95+
env:
96+
node.name: es-test
97+
cluster.name: es-docker-cluster
98+
bootstrap.memory_lock: true
99+
discovery.type: single-node
100+
ES_JAVA_OPTS: -Xms1g -Xmx1g
101+
xpack.security.enabled: false
102+
xpack.security.http.ssl.enabled: false
103+
xpack.security.transport.ssl.enabled: false
104+
action.auto_create_index: true
105+
ports:
106+
- 9200:9200
107+
# Health check for Elasticsearch
108+
options: >-
109+
--health-cmd "curl -s http://127.0.0.1:9200/_cluster/health?wait_for_status=yellow&timeout=30s || exit 1"
110+
--health-interval 10s
111+
--health-timeout 5s
112+
--health-retries 10
113+
114+
opensearch:
115+
image: opensearchproject/opensearch:2.18.0
116+
env:
117+
node.name: os-test
118+
discovery.type: single-node
119+
OPENSEARCH_JAVA_OPTS: -Xms512m -Xmx512m
120+
OPENSEARCH_INITIAL_ADMIN_PASSWORD: bgnYFGR2RhN3SCX # example value of a secret compliant with OpenSearch password policy
121+
plugins.security.ssl.http.enabled: false
122+
ports:
123+
- 9201:9200
124+
- 9600:9600
125+
# Health check for OpenSearch
126+
options: >-
127+
--health-cmd "curl -s -u admin:bgnYFGR2RhN3SCX http://127.0.0.1:9201/_cluster/health?wait_for_status=yellow&timeout=30s || exit 1"
128+
--health-interval 20s
129+
--health-timeout 30s
130+
--health-retries 15
131+
--health-start-period 60s
132+
16133
steps:
17134
- uses: actions/checkout@v4
18135

19136
- name: Set up Go
20137
uses: actions/setup-go@v4
21138
with:
22139
go-version: '1.22'
140+
141+
- name: Install database clients
142+
run: |
143+
# Install PostgreSQL client
144+
sudo apt-get update
145+
sudo apt-get install -y postgresql-client
146+
# Install SQL Server tools
147+
curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
148+
curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list
149+
sudo apt-get update
150+
sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev
23151
24-
- name: Test
25-
run: go test -v ./benchmark/...
152+
- name: Create SQL Server user and database
153+
run: |
154+
# Wait for SQL Server to be ready (max 30 attempts)
155+
for i in {1..30}; do
156+
if /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P MyP@ssw0rd123 -Q "SELECT 1" -b -o /dev/null; then
157+
echo "SQL Server is ready!"
158+
break
159+
fi
160+
echo "Waiting for SQL Server... (attempt $i/30)";
161+
sleep 5;
162+
done
163+
164+
# Create database and user
165+
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P MyP@ssw0rd123 -Q "
166+
IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'perfkit_db_ci')
167+
BEGIN
168+
CREATE DATABASE perfkit_db_ci;
169+
END
170+
GO
171+
USE perfkit_db_ci;
172+
GO
173+
IF NOT EXISTS (SELECT * FROM sys.server_principals WHERE name = 'perfkit_db_runner')
174+
BEGIN
175+
CREATE LOGIN perfkit_db_runner WITH PASSWORD = 'MyP@ssw0rd123';
176+
END
177+
GO
178+
IF NOT EXISTS (SELECT * FROM sys.database_principals WHERE name = 'perfkit_db_runner')
179+
BEGIN
180+
CREATE USER perfkit_db_runner FOR LOGIN perfkit_db_runner;
181+
END
182+
GO
183+
ALTER ROLE db_owner ADD MEMBER perfkit_db_runner;
184+
GO
185+
"
186+
echo "Database and user created successfully"
187+
188+
- name: Create vector extension
189+
run: PGPASSWORD=password psql -h localhost -U root -d perfkit_pg_vector_db_ci -c "CREATE EXTENSION vector;"
190+
191+
- name: Create Cassandra keyspace
192+
run: |
193+
# Wait for Cassandra to be ready (max 30 attempts)
194+
for i in {1..30}; do
195+
if printf "" 2>>/dev/null >>/dev/tcp/127.0.0.1/9042; then
196+
echo "Cassandra is ready!"
197+
break
198+
fi
199+
echo "Waiting for cassandra... (attempt $i/30)";
200+
sleep 5;
201+
done
202+
203+
echo "Creating keyspace..."
204+
docker exec ${{ job.services.cassandra.id }} cqlsh -u cassandra -p cassandra -e "CREATE KEYSPACE IF NOT EXISTS perfkit_db_ci WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};"
205+
echo "Keyspace created"
206+
207+
- name: Test with Coverage
208+
run: |
209+
go test -v -coverprofile=benchmark_coverage.txt -covermode=atomic ./benchmark/...
210+
go test -v -coverprofile=logger_coverage.txt -covermode=atomic ./logger/...
211+
go test -v -coverprofile=restrelay_coverage.txt -covermode=atomic ./acronis-restrelay-bench/...
212+
go test -v -coverprofile=db_coverage.txt -covermode=atomic ./db/...
213+
go test -v -coverprofile=db_bench_coverage.txt -covermode=atomic ./acronis-db-bench/...
214+
215+
- name: Upload results to Codecov
216+
uses: codecov/codecov-action@v5
217+
with:
218+
token: ${{ secrets.CODECOV_TOKEN }}
219+
files: benchmark_coverage.txt,logger_coverage.txt,restrelay_coverage.txt,db_coverage.txt,db_bench_coverage.txt
220+
fail_ci_if_error: true

acronis-db-bench/test-groups/basic-scenarios/common_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
const (
1616
sqliteConnString = "sqlite://:memory:"
1717
mariaDBConnString = "mysql://user:password@tcp(localhost:3306)/perfkit_db_ci"
18-
postgresqlConnString = "postgresql://root:password@localhost:5432/perfkit_db_ci?sslmode=disable"
18+
postgresqlConnString = "postgresql://root:password@localhost:5432/perfkit_pg_vector_db_ci?sslmode=disable"
1919
)
2020

2121
type TestingSuite struct {

benchmark/helpers_unix.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,24 @@ package benchmark
66
import (
77
"bytes"
88
"fmt"
9+
"os"
910
"os/exec"
1011
"strconv"
1112
"strings"
1213
"syscall"
1314
)
1415

16+
func isGitHubCI() bool {
17+
return os.Getenv("GITHUB_ACTIONS") == "true"
18+
}
19+
1520
// adjustFilenoUlimit adjusts file descriptor limits on Linux and Darwin
1621
func (b *Benchmark) adjustFilenoUlimit() int {
22+
// Skip adjustment in GitHub Actions CI
23+
if isGitHubCI() {
24+
return 0
25+
}
26+
1727
var rLimit syscall.Rlimit
1828
fileno := uint64(1048576)
1929

benchmark/helpers_unix_test.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package benchmark
55

66
import (
7-
"os"
87
"os/exec"
98
"runtime"
109
"syscall"
@@ -15,11 +14,6 @@ import (
1514

1615
type LogLevel int
1716

18-
// isGitHubCI returns true if running in GitHub Actions CI environment
19-
func isGitHubCI() bool {
20-
return os.Getenv("GITHUB_ACTIONS") == "true"
21-
}
22-
2317
func TestAdjustFilenoUlimit(t *testing.T) {
2418
// Skip test in GitHub Actions
2519
if isGitHubCI() {

db/es/elasticsearch.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"os"
1414
"strconv"
1515
"strings"
16+
"time"
1617

1718
es8 "github.com/elastic/go-elasticsearch/v8"
1819
"github.com/elastic/go-elasticsearch/v8/esapi"
@@ -39,6 +40,10 @@ func (d *elasticSearchDialect) name() db.DialectName {
3940
return db.ELASTICSEARCH
4041
}
4142

43+
func (d *elasticSearchDialect) getVectorType() fieldType {
44+
return "dense_vector"
45+
}
46+
4247
// nolint:gocritic //TODO refactor unnamed returns
4348
func elasticCredentialsAndConnString(cs string, tlsEnabled bool) (string, string, string, error) {
4449
var u, err = url.Parse(cs)
@@ -261,7 +266,8 @@ func (q *esQuerier) insert(ctx context.Context, idxName indexName, query *BulkIn
261266
var res, err = q.es.Bulk(query.Reader(),
262267
q.es.Bulk.WithContext(ctx),
263268
q.es.Bulk.WithIndex(string(idxName)),
264-
q.es.Bulk.WithRefresh("wait_for"))
269+
q.es.Bulk.WithRefresh("wait_for"),
270+
q.es.Bulk.WithTimeout(30*time.Second))
265271
if err != nil {
266272
return nil, 0, fmt.Errorf("error from elasticsearch while performing bulk insert: %v", err)
267273
} else if res.IsError() {

db/es/es.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func (d *esDatabase) TableExists(tableName string) (bool, error) {
7878
}
7979

8080
func (d *esDatabase) CreateTable(tableName string, tableDefinition *db.TableDefinition, tableMigrationDDL string) error {
81-
return createIndex(d.mig, tableName, tableDefinition, tableMigrationDDL)
81+
return createIndex(d.dialect, d.mig, tableName, tableDefinition, tableMigrationDDL)
8282
}
8383

8484
func (d *esDatabase) DropTable(name string) error {
@@ -213,4 +213,5 @@ func (tq timedQuerier) count(ctx context.Context, idxName indexName, request *Co
213213

214214
type dialect interface {
215215
name() db.DialectName
216+
getVectorType() fieldType
216217
}

db/es/es_test.go

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package es
22

33
import (
44
"context"
5+
"fmt"
56
"testing"
67
"time"
78

@@ -13,8 +14,8 @@ import (
1314
)
1415

1516
const (
16-
esConnString = "es://0.0.0.0:9200"
17-
openSearchConnString = "opensearch://admin:%22ScoRpi0n$%22@0.0.0.0:9200" // example value of a secret compliant with OpenSearch password requirements
17+
esConnString = "es://localhost:9200"
18+
openSearchConnString = "opensearch://admin:bgnYFGR2RhN3SCX@localhost:9201" // example value of a secret compliant with OpenSearch password requirements
1819
)
1920

2021
type TestingSuite struct {
@@ -26,13 +27,10 @@ func TestDatabaseSuiteElasticSearch(t *testing.T) {
2627
suite.Run(t, &TestingSuite{ConnString: esConnString})
2728
}
2829

29-
/*
3030
func TestDatabaseSuiteOpenSearch(t *testing.T) {
3131
suite.Run(t, &TestingSuite{ConnString: openSearchConnString})
3232
}
3333

34-
*/
35-
3634
type testLogger struct {
3735
t *testing.T
3836
}
@@ -62,14 +60,16 @@ func (suite *TestingSuite) makeTestSession() (db.Database, db.Session, *db.Conte
6260
dbo, err := db.Open(db.Config{
6361
ConnString: suite.ConnString,
6462
MaxOpenConns: 16,
65-
MaxConnLifetime: 100 * time.Millisecond,
63+
MaxConnLifetime: 1000 * time.Millisecond,
6664
QueryLogger: logger,
6765
})
6866

6967
require.NoError(suite.T(), err, "making test esSession")
7068

7169
var tableSpec = testTableDefinition()
7270

71+
time.Sleep(1 * time.Second)
72+
7373
if err = dbo.CreateTable("perf_table", tableSpec, ""); err != nil {
7474
require.NoError(suite.T(), err, "init scheme")
7575
}
@@ -95,8 +95,34 @@ func logDbTime(t *testing.T, c *db.Context) {
9595
func cleanup(t *testing.T, dbo db.Database) {
9696
t.Helper()
9797

98+
exists, err := dbo.TableExists("perf_table")
99+
if err != nil {
100+
t.Error("check table exists", err)
101+
return
102+
}
103+
104+
if !exists {
105+
return
106+
}
107+
98108
if err := dbo.DropTable("perf_table"); err != nil {
99109
t.Error("drop table", err)
100110
return
101111
}
102112
}
113+
114+
func dbDialect(connString string) (dialect, error) {
115+
scheme, _, err := db.ParseScheme(connString)
116+
if err != nil {
117+
return nil, fmt.Errorf("cannot parse connection string scheme '%v', error: %v", connString, err)
118+
}
119+
120+
switch scheme {
121+
case "es", "elastic", "elasticsearch":
122+
return &elasticSearchDialect{}, nil
123+
case "os", "opensearch":
124+
return &openSearchDialect{}, nil
125+
default:
126+
return nil, fmt.Errorf("db: unsupported backend '%v'", scheme)
127+
}
128+
}

0 commit comments

Comments
 (0)