// Copyright 2014 The oauth2 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build appenginevm !appengine

package google

import (
	"fmt"
	"log"
	"sync"
	"testing"
	"time"

	"github.com/golang/oauth2"
	"google.golang.org/appengine"
	"google.golang.org/appengine/memcache"
)

type tokMap map[string]*oauth2.Token

type mockMemcache struct {
	mu                 sync.RWMutex
	vals               tokMap
	getCount, setCount int
}

func (m *mockMemcache) Get(c appengine.Context, key string, tok *oauth2.Token) (*memcache.Item, error) {
	m.mu.Lock()
	defer m.mu.Unlock()
	m.getCount++
	v, ok := m.vals[key]
	if !ok {
		return nil, fmt.Errorf("unexpected test error: key %q not found", key)
	}
	*tok = *v
	return nil, nil // memcache.Item is ignored anyway - return nil
}

func (m *mockMemcache) Set(c appengine.Context, item *memcache.Item) error {
	m.mu.Lock()
	defer m.mu.Unlock()
	m.setCount++
	tok, ok := item.Object.(oauth2.Token)
	if !ok {
		log.Fatalf("unexpected test error: item.Object is not an oauth2.Token: %#v", item)
	}
	m.vals[item.Key] = &tok
	return nil
}

var accessTokenCount = 0

func mockAccessToken(c appengine.Context, scopes ...string) (token string, expiry time.Time, err error) {
	accessTokenCount++
	return "mytoken", time.Now(), nil
}

const (
	testScope    = "myscope"
	testScopeKey = ":" + testScope
)

func init() {
	accessTokenFunc = mockAccessToken
}

func TestFetchTokenLocalCacheMiss(t *testing.T) {
	m := &mockMemcache{vals: make(tokMap)}
	memcacheGob = m
	accessTokenCount = 0
	delete(tokens, testScopeKey) // clear local cache
	config := NewAppEngineConfig(nil, testScope)
	_, err := config.FetchToken(nil)
	if err != nil {
		t.Errorf("unable to FetchToken: %v", err)
	}
	if w := 1; m.getCount != w {
		t.Errorf("bad memcache.Get count: got %v, want %v", m.getCount, w)
	}
	if w := 1; accessTokenCount != w {
		t.Errorf("bad AccessToken count: got %v, want %v", accessTokenCount, w)
	}
	if w := 1; m.setCount != w {
		t.Errorf("bad memcache.Set count: got %v, want %v", m.setCount, w)
	}
	// Make sure local cache has been populated
	_, ok := tokens[testScopeKey]
	if !ok {
		t.Errorf("local cache not populated!")
	}
}

func TestFetchTokenLocalCacheHit(t *testing.T) {
	m := &mockMemcache{vals: make(tokMap)}
	memcacheGob = m
	accessTokenCount = 0
	// Pre-populate the local cache
	tokens[testScopeKey] = &oauth2.Token{
		AccessToken: "mytoken",
		Expiry:      time.Now().Add(1 * time.Hour),
	}
	config := NewAppEngineConfig(nil, testScope)
	_, err := config.FetchToken(nil)
	if err != nil {
		t.Errorf("unable to FetchToken: %v", err)
	}
	if w := 0; m.getCount != w {
		t.Errorf("bad memcache.Get count: got %v, want %v", m.getCount, w)
	}
	if w := 0; accessTokenCount != w {
		t.Errorf("bad AccessToken count: got %v, want %v", accessTokenCount, w)
	}
	if w := 0; m.setCount != w {
		t.Errorf("bad memcache.Set count: got %v, want %v", m.setCount, w)
	}
	// Make sure local cache remains populated
	_, ok := tokens[testScopeKey]
	if !ok {
		t.Errorf("local cache not populated!")
	}
}

func TestFetchTokenMemcacheHit(t *testing.T) {
	m := &mockMemcache{vals: make(tokMap)}
	memcacheGob = m
	accessTokenCount = 0
	delete(tokens, testScopeKey) // clear local cache
	// Pre-populate the memcache
	tok := &oauth2.Token{
		AccessToken: "mytoken",
		Expiry:      time.Now().Add(1 * time.Hour),
	}
	m.Set(nil, &memcache.Item{
		Key:        testScopeKey,
		Object:     *tok,
		Expiration: 1 * time.Hour,
	})
	m.setCount = 0
	config := NewAppEngineConfig(nil, testScope)
	_, err := config.FetchToken(nil)
	if err != nil {
		t.Errorf("unable to FetchToken: %v", err)
	}
	if w := 1; m.getCount != w {
		t.Errorf("bad memcache.Get count: got %v, want %v", m.getCount, w)
	}
	if w := 0; accessTokenCount != w {
		t.Errorf("bad AccessToken count: got %v, want %v", accessTokenCount, w)
	}
	if w := 0; m.setCount != w {
		t.Errorf("bad memcache.Set count: got %v, want %v", m.setCount, w)
	}
	// Make sure local cache has been populated
	_, ok := tokens[testScopeKey]
	if !ok {
		t.Errorf("local cache not populated!")
	}
}

func TestFetchTokenLocalCacheExpired(t *testing.T) {
	m := &mockMemcache{vals: make(tokMap)}
	memcacheGob = m
	accessTokenCount = 0
	// Pre-populate the local cache
	tokens[testScopeKey] = &oauth2.Token{
		AccessToken: "mytoken",
		Expiry:      time.Now().Add(-1 * time.Hour),
	}
	// Pre-populate the memcache
	tok := &oauth2.Token{
		AccessToken: "mytoken",
		Expiry:      time.Now().Add(1 * time.Hour),
	}
	m.Set(nil, &memcache.Item{
		Key:        testScopeKey,
		Object:     *tok,
		Expiration: 1 * time.Hour,
	})
	m.setCount = 0
	config := NewAppEngineConfig(nil, testScope)
	_, err := config.FetchToken(nil)
	if err != nil {
		t.Errorf("unable to FetchToken: %v", err)
	}
	if w := 1; m.getCount != w {
		t.Errorf("bad memcache.Get count: got %v, want %v", m.getCount, w)
	}
	if w := 0; accessTokenCount != w {
		t.Errorf("bad AccessToken count: got %v, want %v", accessTokenCount, w)
	}
	if w := 0; m.setCount != w {
		t.Errorf("bad memcache.Set count: got %v, want %v", m.setCount, w)
	}
	// Make sure local cache remains populated
	_, ok := tokens[testScopeKey]
	if !ok {
		t.Errorf("local cache not populated!")
	}
}

func TestFetchTokenMemcacheExpired(t *testing.T) {
	m := &mockMemcache{vals: make(tokMap)}
	memcacheGob = m
	accessTokenCount = 0
	delete(tokens, testScopeKey) // clear local cache
	// Pre-populate the memcache
	tok := &oauth2.Token{
		AccessToken: "mytoken",
		Expiry:      time.Now().Add(-1 * time.Hour),
	}
	m.Set(nil, &memcache.Item{
		Key:        testScopeKey,
		Object:     *tok,
		Expiration: -1 * time.Hour,
	})
	m.setCount = 0
	config := NewAppEngineConfig(nil, testScope)
	_, err := config.FetchToken(nil)
	if err != nil {
		t.Errorf("unable to FetchToken: %v", err)
	}
	if w := 1; m.getCount != w {
		t.Errorf("bad memcache.Get count: got %v, want %v", m.getCount, w)
	}
	if w := 1; accessTokenCount != w {
		t.Errorf("bad AccessToken count: got %v, want %v", accessTokenCount, w)
	}
	if w := 1; m.setCount != w {
		t.Errorf("bad memcache.Set count: got %v, want %v", m.setCount, w)
	}
	// Make sure local cache has been populated
	_, ok := tokens[testScopeKey]
	if !ok {
		t.Errorf("local cache not populated!")
	}
}
