package router

import (
	"testing"

	. "github.com/onsi/gomega"
)

func TestCacheSetKeepsDesiredReplicasForEmptyBackend(t *testing.T) {
	g := NewWithT(t)
	cache := newCache()

	err := cache.set(&Backend{
		TidbPool:    "pool-a",
		ModRevision: 1,
		Replicas:    1,
	})

	g.Expect(err).To(Succeed())
	pods, replicas, replicasKnown := cache.getPoolBackend("pool-a")
	g.Expect(pods).To(BeEmpty())
	g.Expect(replicas).To(Equal(1))
	g.Expect(replicasKnown).To(BeTrue())
}

func TestCacheSetDeletesBackendForRemovedToken(t *testing.T) {
	g := NewWithT(t)
	cache := newCache()
	err := cache.set(&Backend{
		TidbPool:    "pool-a",
		ModRevision: 1,
		Replicas:    1,
		Pods:        []*Pod{{TidbPool: "pool-a", IP: "127.0.0.1", Name: "tidb-0"}},
	})
	g.Expect(err).To(Succeed())

	err = cache.set(&Backend{TidbPool: "pool-a"})

	g.Expect(err).To(Succeed())
	pods, replicas, replicasKnown := cache.getPoolBackend("pool-a")
	g.Expect(pods).To(BeEmpty())
	g.Expect(replicas).To(Equal(0))
	g.Expect(replicasKnown).To(BeFalse())
}

func TestCacheGetPoolBackendReportsUnknownReplicas(t *testing.T) {
	g := NewWithT(t)
	cache := newCache()

	pods, replicas, replicasKnown := cache.getPoolBackend("pool-a")
	g.Expect(pods).To(BeEmpty())
	g.Expect(replicas).To(Equal(0))
	g.Expect(replicasKnown).To(BeFalse())

	err := cache.set(&Backend{
		TidbPool:    "pool-a",
		ModRevision: 1,
		Pods:        []*Pod{{TidbPool: "pool-a", IP: "127.0.0.1", Name: "tidb-0"}},
	})

	g.Expect(err).To(Succeed())
	pods, replicas, replicasKnown = cache.getPoolBackend("pool-a")
	g.Expect(pods).To(HaveLen(1))
	g.Expect(replicas).To(Equal(0))
	g.Expect(replicasKnown).To(BeFalse())
}

func TestCacheSetEnrichesReplicasAtSameRevision(t *testing.T) {
	g := NewWithT(t)
	cache := newCache()
	pods := []*Pod{{TidbPool: "pool-a", IP: "127.0.0.1", Name: "tidb-0"}}

	err := cache.set(&Backend{
		TidbPool:    "pool-a",
		ModRevision: 42,
		Pods:        pods,
	})
	g.Expect(err).To(Succeed())

	err = cache.set(&Backend{
		TidbPool:    "pool-a",
		ModRevision: 42,
		Replicas:    1,
		Pods:        []*Pod{{TidbPool: "pool-a", IP: "127.0.0.1", Name: "tidb-0"}},
	})

	g.Expect(err).To(Succeed())
	gotPods, replicas, replicasKnown := cache.getPoolBackend("pool-a")
	g.Expect(gotPods).To(Equal(pods))
	g.Expect(replicas).To(Equal(1))
	g.Expect(replicasKnown).To(BeTrue())
}

func TestCacheSetDoesNotDowngradeReplicasAtSameRevision(t *testing.T) {
	g := NewWithT(t)
	cache := newCache()
	pods := []*Pod{{TidbPool: "pool-a", IP: "127.0.0.1", Name: "tidb-0"}}

	err := cache.set(&Backend{
		TidbPool:    "pool-a",
		ModRevision: 42,
		Replicas:    1,
		Pods:        pods,
	})
	g.Expect(err).To(Succeed())

	err = cache.set(&Backend{
		TidbPool:    "pool-a",
		ModRevision: 42,
		Pods:        pods,
	})

	g.Expect(err).To(HaveOccurred())
	gotPods, replicas, replicasKnown := cache.getPoolBackend("pool-a")
	g.Expect(gotPods).To(Equal(pods))
	g.Expect(replicas).To(Equal(1))
	g.Expect(replicasKnown).To(BeTrue())
}

func TestCacheSetDoesNotMergeDifferentPodsAtSameRevision(t *testing.T) {
	g := NewWithT(t)
	cache := newCache()
	pods := []*Pod{{TidbPool: "pool-a", IP: "127.0.0.1", Name: "tidb-0"}}

	err := cache.set(&Backend{
		TidbPool:    "pool-a",
		ModRevision: 42,
		Pods:        pods,
	})
	g.Expect(err).To(Succeed())

	err = cache.set(&Backend{
		TidbPool:    "pool-a",
		ModRevision: 42,
		Replicas:    1,
		Pods:        []*Pod{{TidbPool: "pool-a", IP: "127.0.0.2", Name: "tidb-1"}},
	})

	g.Expect(err).To(HaveOccurred())
	gotPods, replicas, replicasKnown := cache.getPoolBackend("pool-a")
	g.Expect(gotPods).To(Equal(pods))
	g.Expect(replicas).To(Equal(0))
	g.Expect(replicasKnown).To(BeFalse())
}
