package main

import (
	"math/rand"
	"sync"
	"testing"

	. "github.com/smartystreets/goconvey/convey"

	"code.justin.tv/d8a/pg-healthcheck/common"
)

func TestPortUp(t *testing.T) {
	Convey("Status should return no error when service is up", t, func() {
		st := htStatusTracker()
		So(st.MarkUp(1000, "healthy"), ShouldBeNil)
		_, err := st.Status(1000)
		if err != nil {
			t.Errorf("Expected no error and found: %v", err)
		}
	})
}

func TestPortDown(t *testing.T) {
	Convey("Status should return no error when the service is down", t, func() {
		st := htStatusTracker()
		So(st.MarkDown(1000, "testing"), ShouldBeNil)
		_, err := st.Status(1000)
		if err != nil {
			t.Errorf("Expected no error and found: %v", err)
		}
	})
}

func TestConcurrency(t *testing.T) {
	Convey("Status can be manipulated and retrieved concurrently", t, func(c C) {
		st := htStatusTracker()
		var wg sync.WaitGroup
		for ii := 0; ii < 5000; ii++ {
			wg.Add(3)
			go func() {
				defer wg.Done()
				port := 1000 + rand.Intn(3)
				c.So(st.MarkDown(port, "marked as down"), ShouldBeNil)
			}()
			go func() {
				defer wg.Done()
				port := 1000 + rand.Intn(3)
				c.So(st.MarkUp(port, "marked as up"), ShouldBeNil)
			}()
			go func() {
				defer wg.Done()
				port := 1000 + rand.Intn(3)
				_, _ = st.Status(port)
			}()
		}
		wg.Wait()
	})
}

func htStatusTracker() common.StatusTracker {
	p := new(intslice)
	*p = append(*p, 1000)
	*p = append(*p, 1001)
	*p = append(*p, 1002)
	return NewStatusTracker(*p)
}
