package cache

import (
	"testing"
	"time"

	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/apiserver/pkg/authentication/user"
)

func newTestWatcher(username string, groups []string) (*cacheWatcher, *ClusterCache, chan struct{}) {
	stopCh := make(chan struct{})
	clusterCache := fakeNewClusterCache(stopCh)
	return NewCacheWatcher(&user.DefaultInfo{Name: username, Groups: groups}, clusterCache, true), clusterCache, stopCh
}

func TestFullIncoming(t *testing.T) {
	watcher, _, stopCh := newTestWatcher("user1", nil)
	defer close(stopCh)
	watcher.cacheIncoming = make(chan watch.Event)

	go watcher.Watch()
	watcher.cacheIncoming <- watch.Event{Type: watch.Added}

	// this call should not block and we should see a failure
	watcher.GroupMembershipChanged(sets.NewString("cluster1"), sets.NewString("user1"), sets.String{})

	err := wait.PollImmediate(10*time.Millisecond, 5*time.Second, func() (done bool, err error) {
		if len(watcher.cacheError) > 0 {
			return true, nil
		}
		return false, nil
	})
	if err != nil {
		t.Fatalf("unexpected error %v", err)
	}

	for {
		repeat := false
		select {
		case event, ok := <-watcher.ResultChan():
			if !ok {
				t.Fatalf("channel closed")
			}
			// this happens when the cacheIncoming block wins the select race
			if event.Type == watch.Added {
				repeat = true
				break
			}
			// this should be an error
			if event.Type != watch.Error {
				t.Errorf("expected error, got %v", event)
			}
		case <-time.After(3 * time.Second):
			t.Fatalf("timeout")
		}
		if !repeat {
			break
		}
	}
}
