Skip to content

Commit

Permalink
chore: new endtoend test framework (#591)
Browse files Browse the repository at this point in the history
* chore: add new endtoend test
  • Loading branch information
earayu authored Nov 28, 2024
1 parent 455763a commit 8a81573
Show file tree
Hide file tree
Showing 22 changed files with 774 additions and 38 deletions.
118 changes: 118 additions & 0 deletions .github/workflows/new_endtoend_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
name: "New EndToEnd Test"

on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches:
- main
- 'release-*'
tags:
- '*'
workflow_dispatch:

env:
IMAGE_NAME: wescale_ci_image
REGISTRY: ghcr.io
IMAGE_TAG: test-${{ github.sha }}
MYSQL_VERSION: 8.0.32

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-endtoend
cancel-in-progress: true

jobs:
build-image:
permissions:
contents: read
packages: write
uses: ./.github/workflows/build_image.yml
with:
branch: ${{ github.ref }}
image_name: ${{ github.repository_owner }}/wescale_ci_image
tags: test-${{ github.sha }}
platforms: linux/amd64
want_push: false
want_load: true
want_artifact: true
artifact_name: 'image.tar'

setup:
name: "New EndToEnd Test"
needs: build-image
runs-on: ubuntu-latest

steps:
- name: Check if workflow needs to be skipped
id: skip-workflow
run: |
skip='false'
if [[ "${{github.event.pull_request}}" == "" ]] && [[ "${{github.ref}}" != "refs/heads/main" ]] && [[ ! "${{github.ref}}" =~ ^refs/heads/release-[0-9]+\.[0-9]$ ]] && [[ ! "${{github.ref}}" =~ "refs/tags/.*" ]]; then
skip='true'
fi
echo Skip ${skip}
echo "skip-workflow=${skip}" >> $GITHUB_OUTPUT
- name: Checkout code
if: steps.skip-workflow.outputs.skip-workflow == 'false'
uses: actions/checkout@v3

- name: Login to registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ github.token }}

- name: Download Docker image
uses: actions/download-artifact@v3
with:
name: image.tar
path: /tmp

- name: Load Docker image
run: |
docker load < /tmp/image.tar
echo "Verifying image loaded:"
docker images
- name: Set up cluster
run: |
MYSQL_IMG="mysql/mysql-server:${{ env.MYSQL_VERSION }}"
WESCALE_CI_IMAGE="${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}"
docker network create wescale-network
docker run -itd --network wescale-network --name mysql-server \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=passwd \
-e MYSQL_ROOT_HOST=% \
-e MYSQL_LOG_CONSOLE=true \
$MYSQL_IMG \
--bind-address=0.0.0.0 \
--port=3306 \
--log-bin=binlog \
--gtid_mode=ON \
--enforce_gtid_consistency=ON \
--log_replica_updates=ON \
--binlog_format=ROW
docker run -itd --network wescale-network --name wescale \
-p 15306:15306 \
-w /vt/examples/wesql-server \
-e MYSQL_ROOT_USER=root \
-e MYSQL_ROOT_PASSWORD=passwd \
-e MYSQL_PORT=3306 \
-e MYSQL_HOST=mysql-server \
-e CONFIG_PATH=/vt/config/wescale/default \
$WESCALE_CI_IMAGE \
/vt/examples/wesql-server/init_single_node_cluster.sh
- name: Run EndToEnd test
run: |
cd endtoend
go test ./... -v
- name: Print Wescale logs
run: |
docker logs wescale
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions docker/wesqlscale/Dockerfile.release
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ RUN cp /vt/src/vitess/bin/vtctld /vt/bin/ && \
cp /vt/src/vitess/bin/protoc /vt/bin && \
cp /vt/src/vitess/bin/etcd /vt/bin && \
cp /vt/src/vitess/bin/etcdctl /vt/bin && \
cp -rf $VTSOURCEROOT/config /vt && \
cp -rf $VTSOURCEROOT/examples /vt && \
rm -rf /vt/src

Expand Down
140 changes: 140 additions & 0 deletions endtoend/framework/clusters/single_node_cluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package clusters

import (
"database/sql"
"flag"
"fmt"
"github.com/wesql/wescale/endtoend/framework"
)

func (s *SingleNodeCluster) RegisterFlagsForSingleNodeCluster() {
flag.StringVar(&s.mysqlHost, fmt.Sprintf("%s_mysqlHost", s.ClusterName), s.mysqlHost, "Host of the MySQL server")
flag.IntVar(&s.mysqlPort, fmt.Sprintf("%s_mysqlPort", s.ClusterName), s.mysqlPort, "Port of the MySQL server")
flag.StringVar(&s.mysqlUser, fmt.Sprintf("%s_mysqlUser", s.ClusterName), s.mysqlUser, "User for the MySQL server")
flag.StringVar(&s.mysqlPasswd, fmt.Sprintf("%s_mysqlPasswd", s.ClusterName), s.mysqlPasswd, "Password for the MySQL server")

flag.StringVar(&s.wescaleHost, fmt.Sprintf("%s_wescaleHost", s.ClusterName), s.wescaleHost, "Host of the WeScale server")
flag.IntVar(&s.wescalePort, fmt.Sprintf("%s_wescalePort", s.ClusterName), s.wescalePort, "Port of the WeScale server")
flag.StringVar(&s.wescaleUser, fmt.Sprintf("%s_wescaleUser", s.ClusterName), s.wescaleUser, "User for the WeScale server")
flag.StringVar(&s.wescalePasswd, fmt.Sprintf("%s_wescalePasswd", s.ClusterName), s.wescalePasswd, "Password for the WeScale server")
}

type SingleNodeCluster struct {
ClusterName string

mysqlHost string
mysqlPort int
mysqlUser string
mysqlPasswd string

wescaleHost string
wescalePort int
wescaleUser string
wescalePasswd string

DbName string
SetUpScript string
CleanupScript string

MysqlDb *sql.DB
WescaleDb *sql.DB
}

func NewDefaultSingleNodeCluster() *SingleNodeCluster {
return newCustomSingleNodeCluster(
"default",
"127.0.0.1",
3306,
"root",
"passwd",
"127.0.0.1",
15306,
"root",
"passwd",
)
}

func newCustomSingleNodeCluster(clusterName string,
mysqlHost string, mysqlPort int, mysqlUser string, mysqlPasswd string,
wescaleHost string, wescalePort int, wescaleUser string, wescalePasswd string) *SingleNodeCluster {
s := &SingleNodeCluster{
ClusterName: clusterName,
mysqlHost: mysqlHost,
mysqlPort: mysqlPort,
mysqlUser: mysqlUser,
mysqlPasswd: mysqlPasswd,
wescaleHost: wescaleHost,
wescalePort: wescalePort,
wescaleUser: wescaleUser,
wescalePasswd: wescalePasswd,
}
return s
}

// SetUpSingleNodeCluster creates a single node cluster with a MySQL and WeScale database.
// dbName can be an empty string if no database is needed.
// setupScript can be an empty string if no setup script is needed.
// cleanupScript can be an empty string if no cleanup script is needed.
func (s *SingleNodeCluster) SetUp(dbName string, setupScript string, cleanupScript string) error {
// Create the database
db, err := framework.NewMysqlConnectionPool(s.wescaleHost, s.wescalePort, s.wescaleUser, s.wescalePasswd, "")
if err != nil {
return err
}
defer db.Close()
if dbName != "" {
_, err = db.Exec(fmt.Sprintf("create database if not exists `%s`", dbName))
if err != nil {
return err
}
}

// Create the connection pools
mysqlDb, err := framework.NewMysqlConnectionPool(s.mysqlHost, s.mysqlPort, s.mysqlUser, s.mysqlPasswd, dbName)
if err != nil {
return err
}
wescaleDb, err := framework.NewMysqlConnectionPool(s.wescaleHost, s.wescalePort, s.wescaleUser, s.wescalePasswd, dbName)
if err != nil {
return err
}

// Execute Set Up Script
if setupScript != "" {
err = framework.ExecuteSqlScript(wescaleDb, setupScript)
if err != nil {
return err
}
}

s.DbName = dbName
s.SetUpScript = setupScript
s.CleanupScript = cleanupScript
s.MysqlDb = mysqlDb
s.WescaleDb = wescaleDb
return nil
}

func (s *SingleNodeCluster) CleanUp() error {
// Execute Clean Up Script
if s.CleanupScript != "" {
err := framework.ExecuteSqlScript(s.WescaleDb, s.CleanupScript)
if err != nil {
return err
}
}

if s.MysqlDb != nil {
err := s.MysqlDb.Close()
if err != nil {
return err
}
}
if s.WescaleDb != nil {
err := s.WescaleDb.Close()
if err != nil {
return err
}
}
return nil
}
34 changes: 34 additions & 0 deletions endtoend/framework/connection_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package framework

import (
"database/sql"
"fmt"
"github.com/go-sql-driver/mysql"
)

func newMysqlConfig(host string, port int, user string, passwd string, dbName string) *mysql.Config {
return &mysql.Config{
Net: "tcp",
Addr: fmt.Sprintf("%s:%d", host, port),
User: user,
Passwd: passwd,
AllowNativePasswords: true,
DBName: dbName,
}
}

func NewMysqlConnectionPool(host string, port int, user string, passwd string, dbName string) (*sql.DB, error) {
c := newMysqlConfig(host, port, user, passwd, dbName)
c.MultiStatements = true
db, err := sql.Open("mysql", c.FormatDSN())
if err != nil {
return nil, err
}

if err := db.Ping(); err != nil {
db.Close()
return nil, err
}

return db, nil
}
Loading

0 comments on commit 8a81573

Please sign in to comment.