@@ -0,0 +1,121 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var registerSingleConnDriver sync.Once
|
||||
|
||||
func openSingleConnRegressionDB(t *testing.T) *sql.DB {
|
||||
t.Helper()
|
||||
registerSingleConnDriver.Do(func() { sql.Register("dockwatch-singleconn-regression", singleConnDriver{}) })
|
||||
db, err := sql.Open("dockwatch-singleconn-regression", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
db.SetMaxOpenConns(1)
|
||||
t.Cleanup(func() { _ = db.Close() })
|
||||
return db
|
||||
}
|
||||
|
||||
type singleConnDriver struct{}
|
||||
|
||||
func (singleConnDriver) Open(string) (driver.Conn, error) { return &singleConn{}, nil }
|
||||
|
||||
type singleConn struct{}
|
||||
|
||||
func (*singleConn) Prepare(string) (driver.Stmt, error) {
|
||||
return nil, errors.New("prepare not supported")
|
||||
}
|
||||
func (*singleConn) Close() error { return nil }
|
||||
func (*singleConn) Begin() (driver.Tx, error) { return nil, errors.New("tx not supported") }
|
||||
func (*singleConn) QueryContext(_ context.Context, query string, _ []driver.NamedValue) (driver.Rows, error) {
|
||||
switch {
|
||||
case strings.Contains(query, "FROM monitor_services ORDER BY name"):
|
||||
return newStaticRows([]string{"id", "name", "description", "created_at", "updated_at"}, [][]driver.Value{{int64(1), "Website", "", int64(1), int64(1)}}), nil
|
||||
case strings.Contains(query, "FROM status_pages ORDER BY name"):
|
||||
return newStaticRows([]string{"id", "name", "slug", "description", "enabled", "created_at", "updated_at"}, [][]driver.Value{{int64(1), "Public", "public", "", int64(1), int64(1), int64(1)}}), nil
|
||||
case strings.Contains(query, "FROM status_pages WHERE slug="):
|
||||
return newStaticRows([]string{"id", "name", "slug", "description", "enabled", "created_at", "updated_at"}, [][]driver.Value{{int64(1), "Public", "public", "", int64(1), int64(1), int64(1)}}), nil
|
||||
case strings.Contains(query, "FROM status_page_services WHERE page_id="):
|
||||
return newStaticRows([]string{"service_id"}, [][]driver.Value{{int64(1)}}), nil
|
||||
case strings.Contains(query, "JOIN status_page_services"):
|
||||
return newStaticRows([]string{"id", "name", "description", "created_at", "updated_at"}, [][]driver.Value{{int64(1), "Website", "", int64(1), int64(1)}}), nil
|
||||
case strings.Contains(query, "FROM monitors m"):
|
||||
// The regression only needs to verify that this second query can start
|
||||
// after the service rows were released. No monitor row is required.
|
||||
return newStaticRows([]string{"monitor"}, nil), nil
|
||||
default:
|
||||
return nil, errors.New("unexpected query: " + query)
|
||||
}
|
||||
}
|
||||
|
||||
var _ driver.QueryerContext = (*singleConn)(nil)
|
||||
|
||||
type staticRows struct {
|
||||
cols []string
|
||||
data [][]driver.Value
|
||||
pos int
|
||||
}
|
||||
|
||||
func newStaticRows(cols []string, data [][]driver.Value) *staticRows {
|
||||
return &staticRows{cols: cols, data: data}
|
||||
}
|
||||
func (r *staticRows) Columns() []string { return r.cols }
|
||||
func (r *staticRows) Close() error { return nil }
|
||||
func (r *staticRows) Next(dest []driver.Value) error {
|
||||
if r.pos >= len(r.data) {
|
||||
return io.EOF
|
||||
}
|
||||
copy(dest, r.data[r.pos])
|
||||
r.pos++
|
||||
return nil
|
||||
}
|
||||
|
||||
func shortContext(t *testing.T) context.Context {
|
||||
t.Helper()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
|
||||
t.Cleanup(cancel)
|
||||
return ctx
|
||||
}
|
||||
|
||||
func TestListGroupsDoesNotNestQueriesOnSingleConnection(t *testing.T) {
|
||||
s := &Service{db: openSingleConnRegressionDB(t)}
|
||||
groups, err := s.ListGroups(shortContext(t))
|
||||
if err != nil {
|
||||
t.Fatalf("ListGroups: %v", err)
|
||||
}
|
||||
if len(groups) != 1 || groups[0].Name != "Website" {
|
||||
t.Fatalf("unexpected groups: %#v", groups)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListStatusPagesDoesNotNestQueriesOnSingleConnection(t *testing.T) {
|
||||
s := &Service{db: openSingleConnRegressionDB(t)}
|
||||
pages, err := s.ListStatusPages(shortContext(t))
|
||||
if err != nil {
|
||||
t.Fatalf("ListStatusPages: %v", err)
|
||||
}
|
||||
if len(pages) != 1 || len(pages[0].ServiceIDs) != 1 || pages[0].ServiceIDs[0] != 1 {
|
||||
t.Fatalf("unexpected pages: %#v", pages)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicStatusPageDoesNotNestQueriesOnSingleConnection(t *testing.T) {
|
||||
s := &Service{db: openSingleConnRegressionDB(t)}
|
||||
page, err := s.PublicStatusPage(shortContext(t), "public")
|
||||
if err != nil {
|
||||
t.Fatalf("PublicStatusPage: %v", err)
|
||||
}
|
||||
if len(page.Services) != 1 || page.Services[0].Name != "Website" {
|
||||
t.Fatalf("unexpected public page: %#v", page)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user