package drainer

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/pingcap/test-infra/common/model/resource"
	sdkresource "github.com/pingcap/test-infra/sdk/resource"

	"github.com/pingcap/test-infra/sdk/e2etest/framework"
)

var _ = Describe("TiDB Drainer Test", func() {
	Context("TiDBDrainer.Create", func() {
		f := framework.NewDefaultFramework("testbed-drainer-create")
		It("TiDBDrainer's testbed should equal to testbed's name", func() {
			drainer := f.CreateDrainer(f.CreateTestbed())
			Expect(drainer.Testbed).Should(Equal(f.Testbed()))
		})

		It("TiDBDrainer's should be ready after a while", func() {
			drainer := f.CreateDrainer(f.CreateTestbed())
			f.WaitForTiDBDrainerReady(drainer, framework.TestContext.ResourceWaitReadyTimeout)
		})
	})
	Context("TiDBDrainer.Get", func() {
		f := framework.NewDefaultFramework("testbed-drainer-create")

		It("TiDBDrainer.Get should restore the spec and status", func() {
			drainer := f.CreateDrainer(f.CreateTestbed())
			drainer = f.GetTiDBDrainer(drainer.Handle())
			f.WaitForTiDBDrainerReady(drainer, framework.TestContext.ResourceWaitReadyTimeout)

			Expect(drainer.Spec).Should(Equal(resource.TiDBDrainerSpec{
				Timezone:         "UTC",
				ClusterName:      "tc",
				ClusterVersion:   "v5.4.0",
				BaseImage:        "hub.pingcap.net/qa/tidb-binlog",
				ImagePullPolicy:  "IfNotPresent",
				StorageClassName: "local-path",
				LogLevel:         "info",
				Storage:          "10Gi",
				DisableDetect:    false,
				InitialCommitTs:  "-1",
				Config:           "detect-interval = 10\n[syncer]\nworker-count = 16\ntxn-batch = 20\ndisable-dispatch = false\nignore-schemas = \"INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql\"\nsafe-mode = false\ndb-type = \"tidb\"\n[syncer.to]\nhost = \"downstream-tidb\"\nuser = \"root\"\npassword = \"\"\nport = 4000\n",
				SyncToMySQLAddr:  "downstream-tidb:4000",
				Resources: resource.ResourceRequirements{Requests: map[resource.ResourceName]resource.Quantity{
					"cpu":    "2000m",
					"memory": "4Gi",
				}},
			}))

			Expect(drainer.Status).Should(Equal(resource.TiDBDrainerStatus{Phase: resource.TiDBDrainerReady}))
			Expect(drainer.Ready()).Should(Equal(true))
		})
	})

	Context("TiDBDrainer.Delete", func() {
		f := framework.NewDefaultFramework("testbed-drainer-delete")

		It("TiDBDrainer.Delete should clean all resources", func() {
			drainer := f.CreateDrainer(f.CreateTestbed())

			f.WaitForTiDBDrainerReady(drainer, framework.TestContext.ResourceWaitReadyTimeout)
			f.DeleteTiDBDrainerWaited(drainer)

			pods := f.AllPods()
			Expect(len(pods.Items)).Should(Equal(0))
			Expect(len(f.AllPVCs().Items)).Should(Equal(0))
			Expect(len(f.AllServices().Items)).Should(Equal(0))
		})
	})

	Context("TiDBDrainer.Exec", func() {
		f := framework.NewDefaultFramework("testbed-drainer-exec")
		It("TiDBDrainer's exec an normal command should work well", func() {
			drainer := f.CreateDrainer(f.CreateTestbed())
			f.WaitForTiDBDrainerReady(drainer, framework.TestContext.ResourceWaitReadyTimeout)

			_, _, exitCode, _ := drainer.Exec(sdkresource.TiDBDrainerExecOptions{
				Command: "echo hello > tmpfile",
				Peer:    0,
			})
			Expect(exitCode).Should(Equal(0))
			stdout, _, exitCode, _ := drainer.Exec(sdkresource.TiDBDrainerExecOptions{
				Command: "cat tmpfile",
				Peer:    0,
			})
			Expect(stdout).Should(Equal("hello"))
		})
	})

	Context("TiDBDrainer.Archive", func() {
		f := framework.NewDefaultFramework("testbed-drainer-archive")
		It("TiDBDrainer's Archive should work well", func() {
			testbed := f.CreateTestbed()
			tidb, downstream := f.CreateTiDBClusterWithPumpAndDownstream(testbed)
			f.WaitForTiDBClusterReadyWithoutPing(tidb, framework.TestContext.ResourceWaitReadyTimeout)
			f.WaitForTiDBClusterReadyWithoutPing(downstream, framework.TestContext.ResourceWaitReadyTimeout)
			drainer := f.CreateDrainer(testbed)
			f.WaitForTiDBDrainerReady(drainer, framework.TestContext.ResourceWaitReadyTimeout)

			var data []string
			f.ArchiveDrainer(drainer.Handle(), f.Archiver(&data))
			Expect(len(data)).Should(BeNumerically(">", 0))
			Expect(data[0]).Should(ContainSubstring(`["Welcome to Drainer"] ["Release Version"=v5.4.0]`))
		})
	})
})
