package storage

import (
	"strings"

	"github.com/jmoiron/sqlx"
	"github.com/jmoiron/sqlx/reflectx"
	"github.com/ngaut/log"
	. "github.com/pingcap/check"
	"github.com/pingcap/schrodinger/pkg/storage/mysql"
	"github.com/pingcap/schrodinger/pkg/types"
	"github.com/pingcap/schrodinger/util"
)

var _ = Suite(&testResultSuite{})

type testResultSuite struct {
	store *Storage
}

func setupStore(dbName string) *Storage {
	db, err := sqlx.Connect("mysql", "root:@(localhost:4000)/")
	if err != nil {
		log.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}

	if _, err = db.Exec("DROP DATABASE IF EXISTS " + dbName); err != nil {
		log.Fatalf("an error '%s' was not expected when droping %s database", dbName, err)
	}

	if _, err = db.Exec("CREATE DATABASE " + dbName); err != nil {
		log.Fatalf("an error '%s' was not expected when creating %s database", dbName, err)
	}

	db, err = sqlx.Connect("mysql", "root:@(localhost:4000)/"+dbName)
	if err != nil {
		log.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
	}

	db.SetMaxIdleConns(0)

	db.Mapper = reflectx.NewMapperFunc("json", strings.ToLower)

	if err := mysql.Migrate(db.DB); err != nil {
		log.Fatalf("an error '%s' was not expected when execing ddl", err)
	}

	return &Storage{client: &mysqlClient{db: db}}
}

func (t *testResultSuite) SetUpSuite(c *C) {
	t.store = setupStore("testResult")
}

func (t *testResultSuite) TearDownSuite(c *C) {
	t.store.Close()
}

var testResult = &types.TestResult{
	ExperimentID: 1,
	Box:          "test-box",
	TestName:     "sysbench",
	Tag:          "xx",
	QPS:          10,
	Pct99:        3.0,
}

func (t *testResultSuite) TestTestResult(c *C) {
	tr := &types.TestResult{}
	err := util.Clone(tr, testResult)
	c.Assert(err, Equals, nil)

	err = t.store.CreateBox(insertBox)
	c.Assert(err, Equals, nil)

	// test for SetTestResult
	err = t.store.SetTestResult(tr)
	if err != nil {
		log.Error(err)
	}
	c.Assert(err, Equals, nil)

	tr1, ok := t.store.GetTestResult(tr.ID)
	c.Assert(ok, Equals, true)
	c.Assert(tr1, DeepEquals, tr)

	// test for updateTestResult
	tr.QPS = 9.0
	// test for SetTestResult
	err = t.store.SetTestResult(tr)
	if err != nil {
		log.Error(err)
	}
	c.Assert(err, Equals, nil)

	tr1, ok = t.store.GetTestResult(tr.ID)
	c.Assert(ok, Equals, true)
	c.Assert(tr1, DeepEquals, tr)

	tr2, ok := t.store.GetTestResultByExperimentWithTestName(tr.ExperimentID, tr.TestName)
	c.Assert(ok, Equals, true)
	c.Assert(tr2, DeepEquals, tr)

	_, ok = t.store.GetTestResultByExperimentWithTestName(tr.ExperimentID, "xxx")
	c.Assert(ok, Equals, false)

	trs1 := t.store.ListTestResultsByExperiment(tr.ExperimentID)
	c.Assert(len(trs1), Equals, 1)

	trs2 := t.store.ListTestResultsByExperiment(2)
	c.Assert(len(trs2), Equals, 0)
}
