Skip to content

Instantly share code, notes, and snippets.

@maddyblue
Last active April 13, 2017 06:37
Show Gist options
  • Save maddyblue/7848515394c6caeaeb7615a659632c8f to your computer and use it in GitHub Desktop.
Save maddyblue/7848515394c6caeaeb7615a659632c8f to your computer and use it in GitHub Desktop.
package test
import (
"bytes"
"database/sql"
"flag"
"fmt"
"math"
"math/rand"
"runtime"
"strings"
"testing"
"time"
"github.com/cockroachdb/apd"
_ "github.com/lib/pq"
"github.com/pkg/errors"
)
var (
flagPostgres = flag.String("postgres", "postgres://postgres@localhost?sslmode=disable;postgresql://root@localhost:26257?sslmode=disable", "Postgres connection strings; specify multiple with semicolons")
)
var operators = [...]string{
"+",
"-",
"*",
"/",
"&",
"^",
"&",
"|",
"#",
//"<<",
//">>",
}
func TestPostgres(t *testing.T) {
rand.Seed(time.Now().UnixNano())
cs := strings.Split(*flagPostgres, ";")
conns := make([]*sql.DB, len(cs))
for i, s := range cs {
conn, err := sql.Open("postgres", s)
if err != nil {
t.Fatalf("%s: %s", s, err)
}
conns[i] = conn
}
slots := make(chan struct{}, runtime.GOMAXPROCS(0))
errch := make(chan error)
go func() {
for {
slots <- struct{}{}
go func() {
defer func() { <-slots }()
var buf bytes.Buffer
for i := 0; i < 3; i++ {
if i > 0 {
op := operators[rand.Intn(len(operators))]
fmt.Fprintf(&buf, " %s ", op)
}
v := getRandValue()
buf.WriteString(v)
}
q := fmt.Sprintf("SELECT (%s)::text;", buf.String())
res := make([]string, len(conns))
for i, db := range conns {
var s string
if err := db.QueryRow(q).Scan(&s); err != nil {
return
errch <- errors.Errorf("%s: %s: %s", cs[i], q, err)
}
res[i] = s
}
cut := func(s string) string {
d, _, err := apd.NewFromString(s)
if err != nil {
panic(err)
}
d.Reduce(d)
r := strings.TrimRight(d.ToStandard(), "0")
return r
}
comp := func(i, j int) {
const cutset = ".0"
a := cut(res[i])
b := cut(res[j])
sd, tot := sameDigits(a, b)
info := errors.Errorf("%s\n%s (%s)\n%s (%s)", q, a, cs[i], b, cs[j])
if sd < (tot-3) && sd < 14 {
fmt.Println(info)
fmt.Println(sd, tot)
fmt.Println()
//errch <- info
}
}
comp(0, 1)
}()
}
}()
t.Fatalf("%+v", <-errch)
}
func getRandValue() string {
var s string
switch rand.Intn(3) {
case 0:
suffix := ""
switch rand.Intn(3) {
case 0:
suffix = "::bigint"
case 1:
suffix = "::int"
case 2:
// ignore
}
switch rand.Intn(4) {
case 0:
s = "0"
case 1:
s = "1"
case 2:
s = "2"
case 3:
s = fmt.Sprintf("%d", rand.Uint64())
}
s += suffix
case 1:
v := rand.Float64()
switch rand.Intn(3) {
case 0:
i := rand.Intn(75)
v *= math.Pow10(i)
case 1:
i := rand.Intn(75)
v *= math.Pow10(-i)
case 2:
// ignore
}
s = fmt.Sprintf("%f::float", v)
case 2:
switch rand.Intn(4) {
case 0:
s = "0::decimal"
case 1:
s = "1::decimal"
case 2:
s = "2::decimal"
case 3:
d := apd.New(rand.Int63(), int32(rand.Intn(10)-4))
s = fmt.Sprintf("%s::decimal", d.ToStandard())
}
}
if s == "" {
panic("unknown")
}
switch rand.Intn(3) {
case 0:
s = fmt.Sprintf("~%s", s)
case 1:
s = fmt.Sprintf("-%s", s)
case 2:
// ignore
}
return s
}
// sameDigits returns the number of identical digits of a and b and the
// total number of digits of min(a, b).
func sameDigits(a, b string) (int, int) {
s := 0
m := 0
i := 0
for ; i < len(a) && i < len(b); i++ {
switch a[s] {
case '-', '.':
m++
}
if a[s] == b[s] {
s++
}
}
return s - m, i - m
}
func Float64() float64 {
v := rand.Float64()
switch rand.Intn(3) {
case 0:
i := rand.Intn(75)
v *= math.Pow10(i)
case 1:
i := rand.Intn(75)
v *= math.Pow10(-i)
case 2:
// ignore
default:
panic("nope")
}
return v
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment