Skip to content

Commit

Permalink
Merge pull request go-kratos#364 from bilibili/go-common/testing_2019…
Browse files Browse the repository at this point in the history
…9197322

この全ては既に世界の選択だ!
  • Loading branch information
Terry-Mao authored Oct 12, 2019
2 parents 049dcfc + 1cc95ce commit a0a87b8
Show file tree
Hide file tree
Showing 17 changed files with 1,351 additions and 48 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ require (
github.com/mattn/go-colorable v0.1.2 // indirect
github.com/montanaflynn/stats v0.5.0
github.com/openzipkin/zipkin-go v0.2.1
github.com/otokaze/mock v0.0.0-20190125081256-8282b7a7c7c3
github.com/pkg/errors v0.8.1
github.com/prometheus/client_golang v1.1.0
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237 // indirect
Expand All @@ -44,6 +45,7 @@ require (
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect
golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2
golang.org/x/time v0.0.0-20190513212739-9d24e82272b4 // indirect
golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89
google.golang.org/appengine v1.6.1 // indirect
google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610
google.golang.org/grpc v1.23.1
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+L
github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw=
github.com/openzipkin/zipkin-go v0.2.1 h1:noL5/5Uf1HpVl3wNsfkZhIKbSWCVi5jgqkONNx8PXcA=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/otokaze/mock v0.0.0-20190125081256-8282b7a7c7c3 h1:zjmNboC3QFuMdJSaZJ7Qvi3HUxWXPdj7wb3rc4jH5HI=
github.com/otokaze/mock v0.0.0-20190125081256-8282b7a7c7c3/go.mod h1:pLR8n2aimFxvvDJ6n8JuQWthMGezCYMjuhlaTjPTZf0=
github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down Expand Up @@ -307,7 +309,9 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b h1:mSUCVIwDx4hfXJfWsOPfdzEHxzb2Xjl6BQ8YgPnazQA=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89 h1:WiVZGyzQN7gPNLRkkpsNX3jC0Jx5j9GxadCZW/8eXw0=
golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
Expand Down
48 changes: 0 additions & 48 deletions pkg/cache/memcache/test/BUILD.bazel

This file was deleted.

9 changes: 9 additions & 0 deletions pkg/cache/memcache/test/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: "3.7"

services:
mc:
image: memcached:1
ports:
- 11211:11211


4 changes: 4 additions & 0 deletions pkg/testing/lich/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## testing/lich 运行环境构建
基于 docker-compose 实现跨平台跨语言环境的容器依赖管理方案,以解决运行ut场景下的 (mysql, redis, mc)容器依赖问题。

使用说明参见:https://github.com/bilibili/kratos/tree/master/tool/testcli/README.md
125 changes: 125 additions & 0 deletions pkg/testing/lich/composer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package lich

import (
"bytes"
"crypto/md5"
"encoding/json"
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"time"

"github.com/bilibili/kratos/pkg/log"
)

var (
retry int
noDown bool
yamlPath string
pathHash string
services map[string]*Container
)

func init() {
flag.StringVar(&yamlPath, "f", "docker-compose.yaml", "composer yaml path.")
flag.BoolVar(&noDown, "nodown", false, "containers are not recycled.")
}

func runCompose(args ...string) (output []byte, err error) {
if _, err = os.Stat(yamlPath); os.IsNotExist(err) {
log.Error("os.Stat(%s) composer yaml is not exist!", yamlPath)
return
}
if yamlPath, err = filepath.Abs(yamlPath); err != nil {
log.Error("filepath.Abs(%s) error(%v)", yamlPath, err)
return
}
pathHash = fmt.Sprintf("%x", md5.Sum([]byte(yamlPath)))[:9]
args = append([]string{"-f", yamlPath, "-p", pathHash}, args...)
if output, err = exec.Command("docker-compose", args...).CombinedOutput(); err != nil {
log.Error("exec.Command(docker-compose) args(%v) stdout(%s) error(%v)", args, string(output), err)
return
}
return
}

// Setup setup UT related environment dependence for everything.
func Setup() (err error) {
if _, err = runCompose("up", "-d"); err != nil {
return
}
defer func() {
if err != err {
go Teardown()
}
}()
if _, err = getServices(); err != nil {
return
}
_, err = checkServices()
return
}

// Teardown unsetup all environment dependence.
func Teardown() (err error) {
if !noDown {
_, err = runCompose("down")
}
return
}

func getServices() (output []byte, err error) {
if output, err = runCompose("config", "--services"); err != nil {
return
}
services = make(map[string]*Container)
output = bytes.TrimSpace(output)
for _, svr := range bytes.Split(output, []byte("\n")) {
if output, err = runCompose("ps", "-a", "-q", string(svr)); err != nil {
return
}
var (
id = string(bytes.TrimSpace(output))
args = []string{"inspect", id, "--format", "'{{json .}}'"}
)
if output, err = exec.Command("docker", args...).CombinedOutput(); err != nil {
log.Error("exec.Command(docker) args(%v) stdout(%s) error(%v)", args, string(output), err)
return
}
if output = bytes.TrimSpace(output); bytes.Equal(output, []byte("")) {
err = fmt.Errorf("service: %s | container: %s fails to launch", svr, id)
log.Error("exec.Command(docker) args(%v) error(%v)", args, err)
return
}
var c = &Container{}
if err = json.Unmarshal(bytes.Trim(output, "'"), c); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", string(output), err)
return
}
services[string(svr)] = c
}
return
}

func checkServices() (output []byte, err error) {
defer func() {
if err != nil && retry < 4 {
retry++
getServices()
time.Sleep(time.Second * 5)
output, err = checkServices()
return
}
retry = 0
}()
for svr, c := range services {
if err = c.Healthcheck(); err != nil {
log.Error("healthcheck(%s) error(%v) retrying %d times...", svr, err, 5-retry)
return
}
// TODO About container check and more...
}
return
}
85 changes: 85 additions & 0 deletions pkg/testing/lich/healthcheck.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package lich

import (
"database/sql"
"fmt"
"net"
"strconv"
"strings"

"github.com/bilibili/kratos/pkg/log"
// Register go-sql-driver stuff
_ "github.com/go-sql-driver/mysql"
)

var healthchecks = map[string]func(*Container) error{"mysql": checkMysql, "mariadb": checkMysql}

// Healthcheck check container health.
func (c *Container) Healthcheck() (err error) {
if status, health := c.State.Status, c.State.Health.Status; !c.State.Running || (health != "" && health != "healthy") {
err = fmt.Errorf("service: %s | container: %s not running", c.GetImage(), c.GetID())
log.Error("docker status(%s) health(%s) error(%v)", status, health, err)
return
}
if check, ok := healthchecks[c.GetImage()]; ok {
err = check(c)
return
}
for proto, ports := range c.NetworkSettings.Ports {
if id := c.GetID(); !strings.Contains(proto, "tcp") {
log.Error("container: %s proto(%s) unsupported.", id, proto)
continue
}
for _, publish := range ports {
var (
ip = net.ParseIP(publish.HostIP)
port, _ = strconv.Atoi(publish.HostPort)
tcpAddr = &net.TCPAddr{IP: ip, Port: port}
tcpConn *net.TCPConn
)
if tcpConn, err = net.DialTCP("tcp", nil, tcpAddr); err != nil {
log.Error("net.DialTCP(%s:%s) error(%v)", publish.HostIP, publish.HostPort, err)
return
}
tcpConn.Close()
}
}
return
}

func checkMysql(c *Container) (err error) {
var ip, port, user, passwd string
for _, env := range c.Config.Env {
splits := strings.Split(env, "=")
if strings.Contains(splits[0], "MYSQL_ROOT_PASSWORD") {
user, passwd = "root", splits[1]
continue
}
if strings.Contains(splits[0], "MYSQL_ALLOW_EMPTY_PASSWORD") {
user, passwd = "root", ""
continue
}
if strings.Contains(splits[0], "MYSQL_USER") {
user = splits[1]
continue
}
if strings.Contains(splits[0], "MYSQL_PASSWORD") {
passwd = splits[1]
continue
}
}
var db *sql.DB
if ports, ok := c.NetworkSettings.Ports["3306/tcp"]; ok {
ip, port = ports[0].HostIP, ports[0].HostPort
}
var dsn = fmt.Sprintf("%s:%s@tcp(%s:%s)/", user, passwd, ip, port)
if db, err = sql.Open("mysql", dsn); err != nil {
log.Error("sql.Open(mysql) dsn(%s) error(%v)", dsn, err)
return
}
if err = db.Ping(); err != nil {
log.Error("ping(db) dsn(%s) error(%v)", dsn, err)
}
defer db.Close()
return
}
Loading

0 comments on commit a0a87b8

Please sign in to comment.