<commit_before>package main

import (
	"log"
	"os"
	"path"
)

type UnpackAction struct {
	BaseAction  `yaml:",inline"`
	Compression string
	File        string
}

func (pf *UnpackAction) Run(context *DebosContext) error {
	pf.LogStart()
	infile := path.Join(context.artifactdir, pf.File)

	os.MkdirAll(context.rootdir, 0755)

	log.Printf("Unpacking %s\n", infile)
	return Command{}.Run("unpack", "tar", "xzf", infile, "-C", context.rootdir)
}
<commit_msg>Action 'unpack' refactored<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"path"
)

type UnpackAction struct {
	BaseAction  `yaml:",inline"`
	Compression string
	File        string
}

func tarOptions(compression string) string {
	unpackTarOpts := map[string]string{
		"gz":    "-z",
		"bzip2": "-j",
		"xz":    "-J",
	} // Trying to guess all other supported formats

	return unpackTarOpts[compression]
}

func UnpackTarArchive(infile, destination, compression string, options ...string) error {
	if err := os.MkdirAll(destination, 0755); err != nil {
		return err
	}
	log.Printf("Unpacking %s\n", infile)

	command := []string{"tar"}
	command = append(command, options...)
	command = append(command, "-x")
	if unpackTarOpt := tarOptions(compression); len(unpackTarOpt) > 0 {
		command = append(command, unpackTarOpt)
	}
	command = append(command, "-f", infile, "-C", destination)

	return Command{}.Run("unpack", command...)
}

func (pf *UnpackAction) Verify(context *DebosContext) error {
	unpackTarOpt := tarOptions(pf.Compression)
	if len(pf.Compression) > 0 && len(unpackTarOpt) == 0 {
		return fmt.Errorf("Compression '%s' is not supported.\n", pf.Compression)
	}

	return nil
}

func (pf *UnpackAction) Run(context *DebosContext) error {
	pf.LogStart()
	infile := path.Join(context.artifactdir, pf.File)

	return UnpackTarArchive(infile, context.rootdir, pf.Compression)
}
<|endoftext|>


<commit_before>package txtdirect

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

func TestParse(t *testing.T) {
	tests := []struct {
		txtRecord string
		expected  record
		err       error
	}{
		{
			"v=txtv0;to=https://example.com/;code=302",
			record{
				Version: "txtv0",
				To:      "https://example.com/",
				Code:    302,
			},
			nil,
		},
		{
			"v=txtv0;to=https://example.com/",
			record{
				Version: "txtv0",
				To:      "https://example.com/",
				Code:    301,
			},
			nil,
		},
		{
			"v=txtv0;https://example.com/;code=302",
			record{
				Version: "txtv0",
				To:      "https://example.com/",
				Code:    302,
			},
			nil,
		},
		{
			"v=txtv0;to=https://example.com/;code=test",
			record{},
			fmt.Errorf("could not parse status code"),
		},
		{
			"v=txtv0;https://example.com/;https://google.com;code=test",
			record{},
			fmt.Errorf("multiple values without keys"),
		},
		{
			"v=txtv1;to=https://example.com/;code=test",
			record{},
			fmt.Errorf("unhandled version 'txtv1'"),
		},
	}

	for i, test := range tests {
		r := record{}
		err := r.Parse(test.txtRecord)

		if err != nil {
			if test.err == nil || !strings.HasPrefix(err.Error(), test.err.Error()) {
				t.Errorf("Test %d: Unexpected error: %s", i, err)
			}
			continue
		}
		if err == nil && test.err != nil {
			t.Errorf("Test %d: Expected error, got nil", i)
			continue
		}

		if got, want := r.Version, test.expected.Version; got != want {
			t.Errorf("Test %d: Expected Version to be '%s', got '%s'", i, want, got)
		}
		if got, want := r.To, test.expected.To; got != want {
			t.Errorf("Test %d: Expected To to be '%s', got '%s'", i, want, got)
		}
		if got, want := r.Code, test.expected.Code; got != want {
			t.Errorf("Test %d: Expected Code to be '%d', got '%d'", i, want, got)
		}
	}
}

func TestHandleDefault(t *testing.T) {
	testURL := "https://%d._td.txtdirect.org"
	dnsURL := "_redirect.%d._td.txtdirect.org"

	for i := 0; ; i++ {
		_, err := net.LookupTXT(fmt.Sprintf(dnsURL, i))
		if err != nil {
			break
		}
		req, _ := http.NewRequest("GET", fmt.Sprintf(testURL, i), nil)
		rec := httptest.NewRecorder()
		err = Redirect(rec, req)
		if err != nil {
			t.Errorf("Unexpected error: %s", err)
		}
	}
}

func TestHandleSuccess(t *testing.T) {
	testURL := "https://%d._ths.txtdirect.org"
	dnsURL := "_redirect.%d._ths.txtdirect.org"

	for i := 0; ; i++ {
		_, err := net.LookupTXT(fmt.Sprintf(dnsURL, i))
		if err != nil {
			break
		}
		req, _ := http.NewRequest("GET", fmt.Sprintf(testURL, i), nil)
		rec := httptest.NewRecorder()
		err = Redirect(rec, req)
		if err != nil {
			t.Errorf("Unexpected error: %s", err)
		}
	}
}

func TestHandleFailure(t *testing.T) {
	testURL := "https://%d._thf.txtdirect.org"
	dnsURL := "_redirect.%d._thf.txtdirect.org"

	for i := 0; ; i++ {
		_, err := net.LookupTXT(fmt.Sprintf(dnsURL, i))
		if err != nil {
			log.Print(err, i)
			break
		}
		req, _ := http.NewRequest("GET", fmt.Sprintf(testURL, i), nil)
		rec := httptest.NewRecorder()
		err = Redirect(rec, req)
		if err == nil {
			t.Errorf("Expected error, got nil)")
		}
	}
}
<commit_msg>Rename Handle to Redirect in tests<commit_after>package txtdirect

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

func TestParse(t *testing.T) {
	tests := []struct {
		txtRecord string
		expected  record
		err       error
	}{
		{
			"v=txtv0;to=https://example.com/;code=302",
			record{
				Version: "txtv0",
				To:      "https://example.com/",
				Code:    302,
			},
			nil,
		},
		{
			"v=txtv0;to=https://example.com/",
			record{
				Version: "txtv0",
				To:      "https://example.com/",
				Code:    301,
			},
			nil,
		},
		{
			"v=txtv0;https://example.com/;code=302",
			record{
				Version: "txtv0",
				To:      "https://example.com/",
				Code:    302,
			},
			nil,
		},
		{
			"v=txtv0;to=https://example.com/;code=test",
			record{},
			fmt.Errorf("could not parse status code"),
		},
		{
			"v=txtv0;https://example.com/;https://google.com;code=test",
			record{},
			fmt.Errorf("multiple values without keys"),
		},
		{
			"v=txtv1;to=https://example.com/;code=test",
			record{},
			fmt.Errorf("unhandled version 'txtv1'"),
		},
	}

	for i, test := range tests {
		r := record{}
		err := r.Parse(test.txtRecord)

		if err != nil {
			if test.err == nil || !strings.HasPrefix(err.Error(), test.err.Error()) {
				t.Errorf("Test %d: Unexpected error: %s", i, err)
			}
			continue
		}
		if err == nil && test.err != nil {
			t.Errorf("Test %d: Expected error, got nil", i)
			continue
		}

		if got, want := r.Version, test.expected.Version; got != want {
			t.Errorf("Test %d: Expected Version to be '%s', got '%s'", i, want, got)
		}
		if got, want := r.To, test.expected.To; got != want {
			t.Errorf("Test %d: Expected To to be '%s', got '%s'", i, want, got)
		}
		if got, want := r.Code, test.expected.Code; got != want {
			t.Errorf("Test %d: Expected Code to be '%d', got '%d'", i, want, got)
		}
	}
}

func TestRedirectDefault(t *testing.T) {
	testURL := "https://%d._td.txtdirect.org"
	dnsURL := "_redirect.%d._td.txtdirect.org"

	for i := 0; ; i++ {
		_, err := net.LookupTXT(fmt.Sprintf(dnsURL, i))
		if err != nil {
			break
		}
		req, _ := http.NewRequest("GET", fmt.Sprintf(testURL, i), nil)
		rec := httptest.NewRecorder()
		err = Redirect(rec, req)
		if err != nil {
			t.Errorf("Unexpected error: %s", err)
		}
	}
}

func TestRedirectSuccess(t *testing.T) {
	testURL := "https://%d._ths.txtdirect.org"
	dnsURL := "_redirect.%d._ths.txtdirect.org"

	for i := 0; ; i++ {
		_, err := net.LookupTXT(fmt.Sprintf(dnsURL, i))
		if err != nil {
			break
		}
		req, _ := http.NewRequest("GET", fmt.Sprintf(testURL, i), nil)
		rec := httptest.NewRecorder()
		err = Redirect(rec, req)
		if err != nil {
			t.Errorf("Unexpected error: %s", err)
		}
	}
}

func TestRedirectFailure(t *testing.T) {
	testURL := "https://%d._thf.txtdirect.org"
	dnsURL := "_redirect.%d._thf.txtdirect.org"

	for i := 0; ; i++ {
		_, err := net.LookupTXT(fmt.Sprintf(dnsURL, i))
		if err != nil {
			log.Print(err, i)
			break
		}
		req, _ := http.NewRequest("GET", fmt.Sprintf(testURL, i), nil)
		rec := httptest.NewRecorder()
		err = Redirect(rec, req)
		if err == nil {
			t.Errorf("Expected error, got nil)")
		}
	}
}
<|endoftext|>


<commit_before>package types

// currency.go defines the internal currency object. One design goal of the
// currency type is immutability: the currency type should be safe to pass
// directly to other objects and packages. The currency object should never
// have a negative value. The currency should never overflow. There is a
// maximum size value that can be encoded (around 10^10^20), however exceeding
// this value will not result in overflow.

import (
	"errors"
	"fmt"
	"math"
	"math/big"

	"github.com/NebulousLabs/Sia/build"
)

type (
	// A Currency represents a number of siacoins or siafunds. Internally, a
	// Currency value is unbounded; however, Currency values sent over the wire
	// protocol are subject to a maximum size of 255 bytes (approximately 10^614).
	// Unlike the math/big library, whose methods modify their receiver, all
	// arithmetic Currency methods return a new value. Currency cannot be negative.
	Currency struct {
		i big.Int
	}
)

var (
	ZeroCurrency = NewCurrency64(0)

	ErrNegativeCurrency = errors.New("negative currency not allowed")
)

// NewCurrency creates a Currency value from a big.Int. Undefined behavior
// occurs if a negative input is used.
func NewCurrency(b *big.Int) (c Currency) {
	if b.Sign() < 0 {
		if build.DEBUG {
			panic(ErrNegativeCurrency)
		}
	} else {
		c.i = *b
	}
	return
}

// NewCurrency64 creates a Currency value from a uint64.
func NewCurrency64(x uint64) (c Currency) {
	c.i.SetUint64(x)
	return
}

// Add returns a new Currency value y = c + x.
func (c Currency) Add(x Currency) (y Currency) {
	y.i.Add(&c.i, &x.i)
	return
}

// Big returns the value of c as a *big.Int. Importantly, it does not provide
// access to the c's internal big.Int object, only a copy.
func (c Currency) Big() *big.Int {
	return new(big.Int).Set(&c.i)
}

// Cmp compares two Currency values. The return value follows the convention
// of math/big.
func (c Currency) Cmp(y Currency) int {
	return c.i.Cmp(&y.i)
}

// Div returns a new Currency value y = c / x.
func (c Currency) Div(x Currency) (y Currency) {
	y.i.Div(&c.i, &x.i)
	return
}

// Mul returns a new Currency value y = c * x.
func (c Currency) Mul(x Currency) (y Currency) {
	y.i.Mul(&c.i, &x.i)
	return
}

// MulFloat returns a new Currency value y = c * x, where x is a float64.
// Behavior is undefined when x is negative.
func (c Currency) MulFloat(x float64) (y Currency) {
	if x < 0 {
		if build.DEBUG {
			panic(ErrNegativeCurrency)
		}
	} else {
		yRat := new(big.Rat).Mul(
			new(big.Rat).SetInt(&c.i),
			new(big.Rat).SetFloat64(x),
		)
		y.i.Div(yRat.Num(), yRat.Denom())
	}
	return
}

// RoundDown returns the largest multiple of n <= c.
func (c Currency) RoundDown(n uint64) (y Currency) {
	diff := new(big.Int).Mod(&c.i, new(big.Int).SetUint64(n))
	y.i.Sub(&c.i, diff)
	return
}

// IsZero returns true if the value is 0, false otherwise.
func (c Currency) IsZero() bool {
	return c.i.Sign() <= 0
}

// Sqrt returns a new Currency value y = sqrt(c). Result is rounded down to the
// nearest integer.
func (c Currency) Sqrt() (y Currency) {
	f, _ := new(big.Rat).SetInt(&c.i).Float64()
	sqrt := new(big.Rat).SetFloat64(math.Sqrt(f))
	y.i.Div(sqrt.Num(), sqrt.Denom())
	return
}

// Sub returns a new Currency value y = c - x. Behavior is undefined when
// c < x.
func (c Currency) Sub(x Currency) (y Currency) {
	if c.Cmp(x) < 0 {
		y = c
		if build.DEBUG {
			panic(ErrNegativeCurrency)
		}
	} else {
		y.i.Sub(&c.i, &x.i)
	}
	return
}

// MarshalJSON implements the json.Marshaler interface.
func (c Currency) MarshalJSON() ([]byte, error) {
	return c.i.MarshalJSON()
}

// UnmarshalJSON implements the json.Unmarshaler interface. An error is
// returned if a negative number is provided.
func (c *Currency) UnmarshalJSON(b []byte) error {
	err := c.i.UnmarshalJSON(b)
	if err != nil {
		return err
	}
	if c.i.Sign() < 0 {
		c.i = *big.NewInt(0)
		return ErrNegativeCurrency
	}
	return nil
}

// MarshalSia implements the encoding.SiaMarshaler interface. It returns the
// byte-slice representation of the Currency's internal big.Int.  Note that as
// the bytes of the big.Int correspond to the absolute value of the integer,
// there is no way to marshal a negative Currency.
func (c Currency) MarshalSia() []byte {
	return c.i.Bytes()
}

// UnmarshalSia implements the encoding.SiaUnmarshaler interface.
func (c *Currency) UnmarshalSia(b []byte) {
	c.i.SetBytes(b)
}

// String implements the fmt.Stringer interface.
func (c Currency) String() string {
	return c.i.String()
}

// Scan implements the fmt.Scanner interface, allowing Currency values to be
// scanned from text.
func (c *Currency) Scan(s fmt.ScanState, ch rune) error {
	err := c.i.Scan(s, ch)
	if err != nil {
		return err
	}
	if c.i.Sign() < 0 {
		return ErrNegativeCurrency
	}
	return nil
}
<commit_msg>less confusing variable names in currency.go<commit_after>package types

// currency.go defines the internal currency object. One design goal of the
// currency type is immutability: the currency type should be safe to pass
// directly to other objects and packages. The currency object should never
// have a negative value. The currency should never overflow. There is a
// maximum size value that can be encoded (around 10^10^20), however exceeding
// this value will not result in overflow.

import (
	"errors"
	"fmt"
	"math"
	"math/big"

	"github.com/NebulousLabs/Sia/build"
)

type (
	// A Currency represents a number of siacoins or siafunds. Internally, a
	// Currency value is unbounded; however, Currency values sent over the wire
	// protocol are subject to a maximum size of 255 bytes (approximately 10^614).
	// Unlike the math/big library, whose methods modify their receiver, all
	// arithmetic Currency methods return a new value. Currency cannot be negative.
	Currency struct {
		i big.Int
	}
)

var (
	ZeroCurrency = NewCurrency64(0)

	ErrNegativeCurrency = errors.New("negative currency not allowed")
)

// NewCurrency creates a Currency value from a big.Int. Undefined behavior
// occurs if a negative input is used.
func NewCurrency(b *big.Int) (c Currency) {
	if b.Sign() < 0 {
		if build.DEBUG {
			panic(ErrNegativeCurrency)
		}
	} else {
		c.i = *b
	}
	return
}

// NewCurrency64 creates a Currency value from a uint64.
func NewCurrency64(x uint64) (c Currency) {
	c.i.SetUint64(x)
	return
}

// Add returns a new Currency value c = x + y
func (x Currency) Add(y Currency) (c Currency) {
	c.i.Add(&x.i, &y.i)
	return
}

// Big returns the value of c as a *big.Int. Importantly, it does not provide
// access to the c's internal big.Int object, only a copy.
func (c Currency) Big() *big.Int {
	return new(big.Int).Set(&c.i)
}

// Cmp compares two Currency values. The return value follows the convention
// of math/big.
func (x Currency) Cmp(y Currency) int {
	return x.i.Cmp(&y.i)
}

// Div returns a new Currency value c = x / y.
func (x Currency) Div(y Currency) (c Currency) {
	c.i.Div(&x.i, &y.i)
	return
}

// Mul returns a new Currency value c = x * y.
func (x Currency) Mul(y Currency) (c Currency) {
	c.i.Mul(&x.i, &y.i)
	return
}

// MulFloat returns a new Currency value y = c * x, where x is a float64.
// Behavior is undefined when x is negative.
func (x Currency) MulFloat(y float64) (c Currency) {
	if y < 0 {
		if build.DEBUG {
			panic(ErrNegativeCurrency)
		}
	} else {
		cRat := new(big.Rat).Mul(
			new(big.Rat).SetInt(&x.i),
			new(big.Rat).SetFloat64(y),
		)
		c.i.Div(cRat.Num(), cRat.Denom())
	}
	return
}

// RoundDown returns the largest multiple of y <= x.
func (x Currency) RoundDown(y uint64) (c Currency) {
	diff := new(big.Int).Mod(&x.i, new(big.Int).SetUint64(y))
	c.i.Sub(&x.i, diff)
	return
}

// IsZero returns true if the value is 0, false otherwise.
func (c Currency) IsZero() bool {
	return c.i.Sign() <= 0
}

// Sqrt returns a new Currency value y = sqrt(c). Result is rounded down to the
// nearest integer.
func (x Currency) Sqrt() (c Currency) {
	f, _ := new(big.Rat).SetInt(&x.i).Float64()
	sqrt := new(big.Rat).SetFloat64(math.Sqrt(f))
	c.i.Div(sqrt.Num(), sqrt.Denom())
	return
}

// Sub returns a new Currency value c = x - y. Behavior is undefined when
// x < y.
func (x Currency) Sub(y Currency) (c Currency) {
	if x.Cmp(y) < 0 {
		c = x
		if build.DEBUG {
			panic(ErrNegativeCurrency)
		}
	} else {
		c.i.Sub(&x.i, &y.i)
	}
	return
}

// MarshalJSON implements the json.Marshaler interface.
func (c Currency) MarshalJSON() ([]byte, error) {
	return c.i.MarshalJSON()
}

// UnmarshalJSON implements the json.Unmarshaler interface. An error is
// returned if a negative number is provided.
func (c *Currency) UnmarshalJSON(b []byte) error {
	err := c.i.UnmarshalJSON(b)
	if err != nil {
		return err
	}
	if c.i.Sign() < 0 {
		c.i = *big.NewInt(0)
		return ErrNegativeCurrency
	}
	return nil
}

// MarshalSia implements the encoding.SiaMarshaler interface. It returns the
// byte-slice representation of the Currency's internal big.Int.  Note that as
// the bytes of the big.Int correspond to the absolute value of the integer,
// there is no way to marshal a negative Currency.
func (c Currency) MarshalSia() []byte {
	return c.i.Bytes()
}

// UnmarshalSia implements the encoding.SiaUnmarshaler interface.
func (c *Currency) UnmarshalSia(b []byte) {
	c.i.SetBytes(b)
}

// String implements the fmt.Stringer interface.
func (c Currency) String() string {
	return c.i.String()
}

// Scan implements the fmt.Scanner interface, allowing Currency values to be
// scanned from text.
func (c *Currency) Scan(s fmt.ScanState, ch rune) error {
	err := c.i.Scan(s, ch)
	if err != nil {
		return err
	}
	if c.i.Sign() < 0 {
		return ErrNegativeCurrency
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gcscaching_test

import (
	"errors"
	"testing"
	"time"

	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/gcscaching"
	"github.com/jacobsa/gcloud/gcs/gcscaching/mock_gcscaching"
	"github.com/jacobsa/gcloud/gcs/mock_gcs"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
)

func TestFastStatBucket(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

const ttl = time.Second

type fastStatBucketTest struct {
	cache   mock_gcscaching.MockStatCache
	clock   timeutil.SimulatedClock
	wrapped mock_gcs.MockBucket

	bucket gcs.Bucket
}

func (t *fastStatBucketTest) SetUp(ti *TestInfo) {
	// Set up a fixed, non-zero time.
	t.clock.SetTime(time.Date(2015, 4, 5, 2, 15, 0, 0, time.Local))

	// Set up dependencies.
	t.cache = mock_gcscaching.NewMockStatCache(ti.MockController, "cache")
	t.wrapped = mock_gcs.NewMockBucket(ti.MockController, "wrapped")

	t.bucket = gcscaching.NewFastStatBucket(
		ttl,
		t.cache,
		&t.clock,
		t.wrapped)
}

////////////////////////////////////////////////////////////////////////
// CreateObject
////////////////////////////////////////////////////////////////////////

type CreateObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&CreateObjectTest{}) }

func (t *CreateObjectTest) CallsEraseAndWrapped() {
	const name = "taco"

	// Erase
	ExpectCall(t.cache, "Erase")(name)

	// Wrapped
	var wrappedReq *gcs.CreateObjectRequest
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(DoAll(SaveArg(1, &wrappedReq), Return(nil, errors.New(""))))

	// Call
	req := &gcs.CreateObjectRequest{
		Name: name,
	}

	_, _ = t.bucket.CreateObject(nil, req)

	AssertNe(nil, wrappedReq)
	ExpectEq(req, wrappedReq)
}

func (t *CreateObjectTest) WrappedFails() {
	const name = ""
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	_, err = t.bucket.CreateObject(nil, &gcs.CreateObjectRequest{})

	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *CreateObjectTest) WrappedSucceeds() {
	const name = "taco"
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	obj := &gcs.Object{
		Name:       name,
		Generation: 1234,
	}

	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(obj, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(obj, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	o, err := t.bucket.CreateObject(nil, &gcs.CreateObjectRequest{})

	AssertEq(nil, err)
	ExpectEq(obj, o)
}

////////////////////////////////////////////////////////////////////////
// StatObject
////////////////////////////////////////////////////////////////////////

type StatObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&StatObjectTest{}) }

func (t *StatObjectTest) CallsCache() {
	const name = "taco"

	// LookUp
	ExpectCall(t.cache, "LookUp")(name, timeutil.TimeEq(t.clock.Now())).
		WillOnce(Return(&gcs.Object{}))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	_, _ = t.bucket.StatObject(nil, req)
}

func (t *StatObjectTest) CacheHit() {
	const name = "taco"

	// LookUp
	obj := &gcs.Object{
		Name: name,
	}

	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(obj))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	o, err := t.bucket.StatObject(nil, req)
	AssertEq(nil, err)
	ExpectEq(obj, o)
}

func (t *StatObjectTest) CallsWrapped() {
	const name = ""
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	// LookUp
	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(nil))

	// Wrapped
	ExpectCall(t.wrapped, "StatObject")(Any(), req).
		WillOnce(Return(nil, errors.New("")))

	// Call
	_, _ = t.bucket.StatObject(nil, req)
}

func (t *StatObjectTest) WrappedFails() {
	const name = ""

	// LookUp
	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(nil))

	// Wrapped
	ExpectCall(t.wrapped, "StatObject")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	_, err := t.bucket.StatObject(nil, req)
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StatObjectTest) WrappedSucceeds() {
	const name = "taco"

	// LookUp
	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(nil))

	// Wrapped
	obj := &gcs.Object{
		Name: name,
	}

	ExpectCall(t.wrapped, "StatObject")(Any(), Any()).
		WillOnce(Return(obj, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(obj, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	o, err := t.bucket.StatObject(nil, req)
	AssertEq(nil, err)
	ExpectEq(obj, o)
}

////////////////////////////////////////////////////////////////////////
// ListObjects
////////////////////////////////////////////////////////////////////////

type ListObjectsTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&ListObjectsTest{}) }

func (t *ListObjectsTest) WrappedFails() {
	// Wrapped
	ExpectCall(t.wrapped, "ListObjects")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	_, err := t.bucket.ListObjects(nil, &gcs.ListObjectsRequest{})
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *ListObjectsTest) EmptyListing() {
	// Wrapped
	expected := &gcs.Listing{}

	ExpectCall(t.wrapped, "ListObjects")(Any(), Any()).
		WillOnce(Return(expected, nil))

	// Call
	listing, err := t.bucket.ListObjects(nil, &gcs.ListObjectsRequest{})

	AssertEq(nil, err)
	ExpectEq(expected, listing)
}

func (t *ListObjectsTest) NonEmptyListing() {
	// Wrapped
	o0 := &gcs.Object{Name: "taco"}
	o1 := &gcs.Object{Name: "burrito"}

	expected := &gcs.Listing{
		Objects: []*gcs.Object{o0, o1},
	}

	ExpectCall(t.wrapped, "ListObjects")(Any(), Any()).
		WillOnce(Return(expected, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(o0, timeutil.TimeEq(t.clock.Now().Add(ttl)))
	ExpectCall(t.cache, "Insert")(o1, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	listing, err := t.bucket.ListObjects(nil, &gcs.ListObjectsRequest{})

	AssertEq(nil, err)
	ExpectEq(expected, listing)
}

////////////////////////////////////////////////////////////////////////
// UpdateObject
////////////////////////////////////////////////////////////////////////

type UpdateObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&UpdateObjectTest{}) }

func (t *UpdateObjectTest) CallsEraseAndWrapped() {
	const name = "taco"

	// Erase
	ExpectCall(t.cache, "Erase")(name)

	// Wrapped
	var wrappedReq *gcs.UpdateObjectRequest
	ExpectCall(t.wrapped, "UpdateObject")(Any(), Any()).
		WillOnce(DoAll(SaveArg(1, &wrappedReq), Return(nil, errors.New(""))))

	// Call
	req := &gcs.UpdateObjectRequest{
		Name: name,
	}

	_, _ = t.bucket.UpdateObject(nil, req)

	AssertNe(nil, wrappedReq)
	ExpectEq(req, wrappedReq)
}

func (t *UpdateObjectTest) WrappedFails() {
	const name = ""
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	ExpectCall(t.wrapped, "UpdateObject")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	_, err = t.bucket.UpdateObject(nil, &gcs.UpdateObjectRequest{})

	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *UpdateObjectTest) WrappedSucceeds() {
	const name = "taco"
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	obj := &gcs.Object{
		Name:       name,
		Generation: 1234,
	}

	ExpectCall(t.wrapped, "UpdateObject")(Any(), Any()).
		WillOnce(Return(obj, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(obj, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	o, err := t.bucket.UpdateObject(nil, &gcs.UpdateObjectRequest{})

	AssertEq(nil, err)
	ExpectEq(obj, o)
}
<commit_msg>DeleteObjectTest<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gcscaching_test

import (
	"errors"
	"testing"
	"time"

	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/gcscaching"
	"github.com/jacobsa/gcloud/gcs/gcscaching/mock_gcscaching"
	"github.com/jacobsa/gcloud/gcs/mock_gcs"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
)

func TestFastStatBucket(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

const ttl = time.Second

type fastStatBucketTest struct {
	cache   mock_gcscaching.MockStatCache
	clock   timeutil.SimulatedClock
	wrapped mock_gcs.MockBucket

	bucket gcs.Bucket
}

func (t *fastStatBucketTest) SetUp(ti *TestInfo) {
	// Set up a fixed, non-zero time.
	t.clock.SetTime(time.Date(2015, 4, 5, 2, 15, 0, 0, time.Local))

	// Set up dependencies.
	t.cache = mock_gcscaching.NewMockStatCache(ti.MockController, "cache")
	t.wrapped = mock_gcs.NewMockBucket(ti.MockController, "wrapped")

	t.bucket = gcscaching.NewFastStatBucket(
		ttl,
		t.cache,
		&t.clock,
		t.wrapped)
}

////////////////////////////////////////////////////////////////////////
// CreateObject
////////////////////////////////////////////////////////////////////////

type CreateObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&CreateObjectTest{}) }

func (t *CreateObjectTest) CallsEraseAndWrapped() {
	const name = "taco"

	// Erase
	ExpectCall(t.cache, "Erase")(name)

	// Wrapped
	var wrappedReq *gcs.CreateObjectRequest
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(DoAll(SaveArg(1, &wrappedReq), Return(nil, errors.New(""))))

	// Call
	req := &gcs.CreateObjectRequest{
		Name: name,
	}

	_, _ = t.bucket.CreateObject(nil, req)

	AssertNe(nil, wrappedReq)
	ExpectEq(req, wrappedReq)
}

func (t *CreateObjectTest) WrappedFails() {
	const name = ""
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	_, err = t.bucket.CreateObject(nil, &gcs.CreateObjectRequest{})

	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *CreateObjectTest) WrappedSucceeds() {
	const name = "taco"
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	obj := &gcs.Object{
		Name:       name,
		Generation: 1234,
	}

	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(obj, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(obj, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	o, err := t.bucket.CreateObject(nil, &gcs.CreateObjectRequest{})

	AssertEq(nil, err)
	ExpectEq(obj, o)
}

////////////////////////////////////////////////////////////////////////
// StatObject
////////////////////////////////////////////////////////////////////////

type StatObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&StatObjectTest{}) }

func (t *StatObjectTest) CallsCache() {
	const name = "taco"

	// LookUp
	ExpectCall(t.cache, "LookUp")(name, timeutil.TimeEq(t.clock.Now())).
		WillOnce(Return(&gcs.Object{}))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	_, _ = t.bucket.StatObject(nil, req)
}

func (t *StatObjectTest) CacheHit() {
	const name = "taco"

	// LookUp
	obj := &gcs.Object{
		Name: name,
	}

	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(obj))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	o, err := t.bucket.StatObject(nil, req)
	AssertEq(nil, err)
	ExpectEq(obj, o)
}

func (t *StatObjectTest) CallsWrapped() {
	const name = ""
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	// LookUp
	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(nil))

	// Wrapped
	ExpectCall(t.wrapped, "StatObject")(Any(), req).
		WillOnce(Return(nil, errors.New("")))

	// Call
	_, _ = t.bucket.StatObject(nil, req)
}

func (t *StatObjectTest) WrappedFails() {
	const name = ""

	// LookUp
	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(nil))

	// Wrapped
	ExpectCall(t.wrapped, "StatObject")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	_, err := t.bucket.StatObject(nil, req)
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StatObjectTest) WrappedSucceeds() {
	const name = "taco"

	// LookUp
	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(nil))

	// Wrapped
	obj := &gcs.Object{
		Name: name,
	}

	ExpectCall(t.wrapped, "StatObject")(Any(), Any()).
		WillOnce(Return(obj, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(obj, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	o, err := t.bucket.StatObject(nil, req)
	AssertEq(nil, err)
	ExpectEq(obj, o)
}

////////////////////////////////////////////////////////////////////////
// ListObjects
////////////////////////////////////////////////////////////////////////

type ListObjectsTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&ListObjectsTest{}) }

func (t *ListObjectsTest) WrappedFails() {
	// Wrapped
	ExpectCall(t.wrapped, "ListObjects")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	_, err := t.bucket.ListObjects(nil, &gcs.ListObjectsRequest{})
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *ListObjectsTest) EmptyListing() {
	// Wrapped
	expected := &gcs.Listing{}

	ExpectCall(t.wrapped, "ListObjects")(Any(), Any()).
		WillOnce(Return(expected, nil))

	// Call
	listing, err := t.bucket.ListObjects(nil, &gcs.ListObjectsRequest{})

	AssertEq(nil, err)
	ExpectEq(expected, listing)
}

func (t *ListObjectsTest) NonEmptyListing() {
	// Wrapped
	o0 := &gcs.Object{Name: "taco"}
	o1 := &gcs.Object{Name: "burrito"}

	expected := &gcs.Listing{
		Objects: []*gcs.Object{o0, o1},
	}

	ExpectCall(t.wrapped, "ListObjects")(Any(), Any()).
		WillOnce(Return(expected, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(o0, timeutil.TimeEq(t.clock.Now().Add(ttl)))
	ExpectCall(t.cache, "Insert")(o1, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	listing, err := t.bucket.ListObjects(nil, &gcs.ListObjectsRequest{})

	AssertEq(nil, err)
	ExpectEq(expected, listing)
}

////////////////////////////////////////////////////////////////////////
// UpdateObject
////////////////////////////////////////////////////////////////////////

type UpdateObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&UpdateObjectTest{}) }

func (t *UpdateObjectTest) CallsEraseAndWrapped() {
	const name = "taco"

	// Erase
	ExpectCall(t.cache, "Erase")(name)

	// Wrapped
	var wrappedReq *gcs.UpdateObjectRequest
	ExpectCall(t.wrapped, "UpdateObject")(Any(), Any()).
		WillOnce(DoAll(SaveArg(1, &wrappedReq), Return(nil, errors.New(""))))

	// Call
	req := &gcs.UpdateObjectRequest{
		Name: name,
	}

	_, _ = t.bucket.UpdateObject(nil, req)

	AssertNe(nil, wrappedReq)
	ExpectEq(req, wrappedReq)
}

func (t *UpdateObjectTest) WrappedFails() {
	const name = ""
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	ExpectCall(t.wrapped, "UpdateObject")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	_, err = t.bucket.UpdateObject(nil, &gcs.UpdateObjectRequest{})

	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *UpdateObjectTest) WrappedSucceeds() {
	const name = "taco"
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	obj := &gcs.Object{
		Name:       name,
		Generation: 1234,
	}

	ExpectCall(t.wrapped, "UpdateObject")(Any(), Any()).
		WillOnce(Return(obj, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(obj, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	o, err := t.bucket.UpdateObject(nil, &gcs.UpdateObjectRequest{})

	AssertEq(nil, err)
	ExpectEq(obj, o)
}

////////////////////////////////////////////////////////////////////////
// DeleteObject
////////////////////////////////////////////////////////////////////////

type DeleteObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&DeleteObjectTest{}) }

func (t *DeleteObjectTest) CallsEraseAndWrapped() {
	const name = "taco"

	// Erase
	ExpectCall(t.cache, "Erase")(name)

	// Wrapped
	ExpectCall(t.wrapped, "DeleteObject")(Any(), name).
		WillOnce(Return(errors.New("")))

	// Call
	_ = t.bucket.DeleteObject(nil, name)
}

func (t *DeleteObjectTest) WrappedFails() {
	const name = ""
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	ExpectCall(t.wrapped, "DeleteObject")(Any(), Any()).
		WillOnce(Return(errors.New("taco")))

	// Call
	err = t.bucket.DeleteObject(nil, name)

	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *DeleteObjectTest) WrappedSucceeds() {
	const name = ""
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	ExpectCall(t.wrapped, "DeleteObject")(Any(), Any()).
		WillOnce(Return(nil))

	// Call
	err = t.bucket.DeleteObject(nil, name)
	AssertEq(nil, err)
}
<|endoftext|>


<commit_before>// Copyright 2019 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package kubernetes

import (
	"context"
	"sync"
	"time"

	"github.com/pkg/errors"
	"github.com/tsuru/tsuru/log"
	"github.com/tsuru/tsuru/router/rebuild"
	apiv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/informers"
	v1informers "k8s.io/client-go/informers/core/v1"
	"k8s.io/client-go/informers/internalinterfaces"
	"k8s.io/client-go/tools/cache"
)

const (
	informerSyncTimeout = time.Minute
)

type clusterController struct {
	mu              sync.Mutex
	cluster         *ClusterClient
	informerFactory informers.SharedInformerFactory
	podInformer     v1informers.PodInformer
	serviceInformer v1informers.ServiceInformer
	nodeInformer    v1informers.NodeInformer
	stopCh          chan struct{}
}

func initAllControllers(p *kubernetesProvisioner) error {
	return forEachCluster(func(client *ClusterClient) error {
		_, err := getClusterController(p, client)
		return err
	})
}

func getClusterController(p *kubernetesProvisioner, cluster *ClusterClient) (*clusterController, error) {
	p.mu.Lock()
	defer p.mu.Unlock()
	if c, ok := p.clusterControllers[cluster.Name]; ok {
		return c, nil
	}
	c := &clusterController{
		cluster: cluster,
		stopCh:  make(chan struct{}),
	}
	err := c.start()
	if err != nil {
		return nil, err
	}
	p.clusterControllers[cluster.Name] = c
	return c, nil
}

func stopClusterController(p *kubernetesProvisioner, cluster *ClusterClient) {
	p.mu.Lock()
	defer p.mu.Unlock()
	if c, ok := p.clusterControllers[cluster.Name]; ok {
		c.stop()
	}
	delete(p.clusterControllers, cluster.Name)
}

func (c *clusterController) stop() {
	close(c.stopCh)
}

func (c *clusterController) start() error {
	informer, err := c.getPodInformerWait(false)
	if err != nil {
		return err
	}
	informer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			err := c.onAdd(obj)
			if err != nil {
				log.Errorf("[router-update-controller] error on add pod event: %v", err)
			}
		},
		UpdateFunc: func(oldObj, newObj interface{}) {
			err := c.onUpdate(oldObj, newObj)
			if err != nil {
				log.Errorf("[router-update-controller] error on update pod event: %v", err)
			}
		},
		DeleteFunc: func(obj interface{}) {
			err := c.onDelete(obj)
			if err != nil {
				log.Errorf("[router-update-controller] error on delete pod event: %v", err)
			}
		},
	})
	return nil
}

func (m *clusterController) onAdd(obj interface{}) error {
	// Pods are never ready on add, ignore and do nothing
	return nil
}

func (c *clusterController) onUpdate(oldObj, newObj interface{}) error {
	newPod := oldObj.(*apiv1.Pod)
	oldPod := newObj.(*apiv1.Pod)
	if newPod.ResourceVersion == oldPod.ResourceVersion {
		return nil
	}
	c.addPod(newPod)
	return nil
}

func (c *clusterController) onDelete(obj interface{}) error {
	if pod, ok := obj.(*apiv1.Pod); ok {
		c.addPod(pod)
		return nil
	}
	tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
	if !ok {
		return errors.Errorf("couldn't get object from tombstone %#v", obj)
	}
	pod, ok := tombstone.Obj.(*apiv1.Pod)
	if !ok {
		return errors.Errorf("tombstone contained object that is not a Pod: %#v", obj)
	}
	c.addPod(pod)
	return nil
}

func (c *clusterController) addPod(pod *apiv1.Pod) {
	labelSet := labelSetFromMeta(&pod.ObjectMeta)
	appName := labelSet.AppName()
	if appName == "" {
		return
	}
	if labelSet.IsDeploy() || labelSet.IsIsolatedRun() {
		return
	}
	routerLocal, _ := c.cluster.RouterAddressLocal(labelSet.AppPool())
	if routerLocal {
		rebuild.EnqueueRoutesRebuild(appName)
	}
}

func (p *clusterController) getPodInformer() (v1informers.PodInformer, error) {
	return p.getPodInformerWait(true)
}

func (p *clusterController) getServiceInformer() (v1informers.ServiceInformer, error) {
	p.mu.Lock()
	defer p.mu.Unlock()
	if p.serviceInformer == nil {
		err := p.withInformerFactory(func(factory informers.SharedInformerFactory) {
			p.serviceInformer = factory.Core().V1().Services()
			p.serviceInformer.Informer()
		})
		if err != nil {
			return nil, err
		}
	}
	err := p.waitForSync(p.serviceInformer.Informer())
	return p.serviceInformer, err
}

func (p *clusterController) getNodeInformer() (v1informers.NodeInformer, error) {
	p.mu.Lock()
	defer p.mu.Unlock()
	if p.nodeInformer == nil {
		err := p.withInformerFactory(func(factory informers.SharedInformerFactory) {
			p.nodeInformer = factory.Core().V1().Nodes()
			p.nodeInformer.Informer()
		})
		if err != nil {
			return nil, err
		}
	}
	err := p.waitForSync(p.nodeInformer.Informer())
	return p.nodeInformer, err
}

func (p *clusterController) getPodInformerWait(wait bool) (v1informers.PodInformer, error) {
	p.mu.Lock()
	defer p.mu.Unlock()
	if p.podInformer == nil {
		err := p.withInformerFactory(func(factory informers.SharedInformerFactory) {
			p.podInformer = factory.Core().V1().Pods()
			p.podInformer.Informer()
		})
		if err != nil {
			return nil, err
		}
	}
	var err error
	if wait {
		err = p.waitForSync(p.podInformer.Informer())
	}
	return p.podInformer, err
}

func (p *clusterController) withInformerFactory(fn func(factory informers.SharedInformerFactory)) error {
	factory, err := p.getFactory()
	if err != nil {
		return err
	}
	fn(factory)
	factory.Start(p.stopCh)
	return nil
}

func (p *clusterController) getFactory() (informers.SharedInformerFactory, error) {
	if p.informerFactory != nil {
		return p.informerFactory, nil
	}
	var err error
	p.informerFactory, err = InformerFactory(p.cluster)
	return p.informerFactory, err
}

func contextWithCancelByChannel(ctx context.Context, ch chan struct{}, timeout time.Duration) (context.Context, func()) {
	ctx, cancel := context.WithTimeout(ctx, timeout)
	go func() {
		select {
		case <-ch:
			cancel()
		case <-ctx.Done():
			return
		}
	}()
	return ctx, cancel
}

func (p *clusterController) waitForSync(informer cache.SharedInformer) error {
	if informer.HasSynced() {
		return nil
	}
	ctx, cancel := contextWithCancelByChannel(context.Background(), p.stopCh, informerSyncTimeout)
	defer cancel()
	cache.WaitForCacheSync(ctx.Done(), informer.HasSynced)
	return ctx.Err()
}

var InformerFactory = func(client *ClusterClient) (informers.SharedInformerFactory, error) {
	timeout := client.restConfig.Timeout
	restConfig := *client.restConfig
	restConfig.Timeout = 0
	cli, err := ClientForConfig(&restConfig)
	if err != nil {
		return nil, err
	}
	tweakFunc := internalinterfaces.TweakListOptionsFunc(func(opts *metav1.ListOptions) {
		if opts.TimeoutSeconds == nil {
			timeoutSec := int64(timeout.Seconds())
			opts.TimeoutSeconds = &timeoutSec
		}
	})
	return informers.NewFilteredSharedInformerFactory(cli, time.Minute, metav1.NamespaceAll, tweakFunc), nil
}
<commit_msg>provision/kubernetes: fix receiver name in cluster controller methods<commit_after>// Copyright 2019 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package kubernetes

import (
	"context"
	"sync"
	"time"

	"github.com/pkg/errors"
	"github.com/tsuru/tsuru/log"
	"github.com/tsuru/tsuru/router/rebuild"
	apiv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/informers"
	v1informers "k8s.io/client-go/informers/core/v1"
	"k8s.io/client-go/informers/internalinterfaces"
	"k8s.io/client-go/tools/cache"
)

const (
	informerSyncTimeout = time.Minute
)

type clusterController struct {
	mu              sync.Mutex
	cluster         *ClusterClient
	informerFactory informers.SharedInformerFactory
	podInformer     v1informers.PodInformer
	serviceInformer v1informers.ServiceInformer
	nodeInformer    v1informers.NodeInformer
	stopCh          chan struct{}
}

func initAllControllers(p *kubernetesProvisioner) error {
	return forEachCluster(func(client *ClusterClient) error {
		_, err := getClusterController(p, client)
		return err
	})
}

func getClusterController(p *kubernetesProvisioner, cluster *ClusterClient) (*clusterController, error) {
	p.mu.Lock()
	defer p.mu.Unlock()
	if c, ok := p.clusterControllers[cluster.Name]; ok {
		return c, nil
	}
	c := &clusterController{
		cluster: cluster,
		stopCh:  make(chan struct{}),
	}
	err := c.start()
	if err != nil {
		return nil, err
	}
	p.clusterControllers[cluster.Name] = c
	return c, nil
}

func stopClusterController(p *kubernetesProvisioner, cluster *ClusterClient) {
	p.mu.Lock()
	defer p.mu.Unlock()
	if c, ok := p.clusterControllers[cluster.Name]; ok {
		c.stop()
	}
	delete(p.clusterControllers, cluster.Name)
}

func (c *clusterController) stop() {
	close(c.stopCh)
}

func (c *clusterController) start() error {
	informer, err := c.getPodInformerWait(false)
	if err != nil {
		return err
	}
	informer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			err := c.onAdd(obj)
			if err != nil {
				log.Errorf("[router-update-controller] error on add pod event: %v", err)
			}
		},
		UpdateFunc: func(oldObj, newObj interface{}) {
			err := c.onUpdate(oldObj, newObj)
			if err != nil {
				log.Errorf("[router-update-controller] error on update pod event: %v", err)
			}
		},
		DeleteFunc: func(obj interface{}) {
			err := c.onDelete(obj)
			if err != nil {
				log.Errorf("[router-update-controller] error on delete pod event: %v", err)
			}
		},
	})
	return nil
}

func (c *clusterController) onAdd(obj interface{}) error {
	// Pods are never ready on add, ignore and do nothing
	return nil
}

func (c *clusterController) onUpdate(oldObj, newObj interface{}) error {
	newPod := oldObj.(*apiv1.Pod)
	oldPod := newObj.(*apiv1.Pod)
	if newPod.ResourceVersion == oldPod.ResourceVersion {
		return nil
	}
	c.addPod(newPod)
	return nil
}

func (c *clusterController) onDelete(obj interface{}) error {
	if pod, ok := obj.(*apiv1.Pod); ok {
		c.addPod(pod)
		return nil
	}
	tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
	if !ok {
		return errors.Errorf("couldn't get object from tombstone %#v", obj)
	}
	pod, ok := tombstone.Obj.(*apiv1.Pod)
	if !ok {
		return errors.Errorf("tombstone contained object that is not a Pod: %#v", obj)
	}
	c.addPod(pod)
	return nil
}

func (c *clusterController) addPod(pod *apiv1.Pod) {
	labelSet := labelSetFromMeta(&pod.ObjectMeta)
	appName := labelSet.AppName()
	if appName == "" {
		return
	}
	if labelSet.IsDeploy() || labelSet.IsIsolatedRun() {
		return
	}
	routerLocal, _ := c.cluster.RouterAddressLocal(labelSet.AppPool())
	if routerLocal {
		rebuild.EnqueueRoutesRebuild(appName)
	}
}

func (c *clusterController) getPodInformer() (v1informers.PodInformer, error) {
	return c.getPodInformerWait(true)
}

func (c *clusterController) getServiceInformer() (v1informers.ServiceInformer, error) {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.serviceInformer == nil {
		err := c.withInformerFactory(func(factory informers.SharedInformerFactory) {
			c.serviceInformer = factory.Core().V1().Services()
			c.serviceInformer.Informer()
		})
		if err != nil {
			return nil, err
		}
	}
	err := c.waitForSync(c.serviceInformer.Informer())
	return c.serviceInformer, err
}

func (c *clusterController) getNodeInformer() (v1informers.NodeInformer, error) {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.nodeInformer == nil {
		err := c.withInformerFactory(func(factory informers.SharedInformerFactory) {
			c.nodeInformer = factory.Core().V1().Nodes()
			c.nodeInformer.Informer()
		})
		if err != nil {
			return nil, err
		}
	}
	err := c.waitForSync(c.nodeInformer.Informer())
	return c.nodeInformer, err
}

func (c *clusterController) getPodInformerWait(wait bool) (v1informers.PodInformer, error) {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.podInformer == nil {
		err := c.withInformerFactory(func(factory informers.SharedInformerFactory) {
			c.podInformer = factory.Core().V1().Pods()
			c.podInformer.Informer()
		})
		if err != nil {
			return nil, err
		}
	}
	var err error
	if wait {
		err = c.waitForSync(c.podInformer.Informer())
	}
	return c.podInformer, err
}

func (c *clusterController) withInformerFactory(fn func(factory informers.SharedInformerFactory)) error {
	factory, err := c.getFactory()
	if err != nil {
		return err
	}
	fn(factory)
	factory.Start(c.stopCh)
	return nil
}

func (c *clusterController) getFactory() (informers.SharedInformerFactory, error) {
	if c.informerFactory != nil {
		return c.informerFactory, nil
	}
	var err error
	c.informerFactory, err = InformerFactory(c.cluster)
	return c.informerFactory, err
}

func contextWithCancelByChannel(ctx context.Context, ch chan struct{}, timeout time.Duration) (context.Context, func()) {
	ctx, cancel := context.WithTimeout(ctx, timeout)
	go func() {
		select {
		case <-ch:
			cancel()
		case <-ctx.Done():
			return
		}
	}()
	return ctx, cancel
}

func (c *clusterController) waitForSync(informer cache.SharedInformer) error {
	if informer.HasSynced() {
		return nil
	}
	ctx, cancel := contextWithCancelByChannel(context.Background(), c.stopCh, informerSyncTimeout)
	defer cancel()
	cache.WaitForCacheSync(ctx.Done(), informer.HasSynced)
	return ctx.Err()
}

var InformerFactory = func(client *ClusterClient) (informers.SharedInformerFactory, error) {
	timeout := client.restConfig.Timeout
	restConfig := *client.restConfig
	restConfig.Timeout = 0
	cli, err := ClientForConfig(&restConfig)
	if err != nil {
		return nil, err
	}
	tweakFunc := internalinterfaces.TweakListOptionsFunc(func(opts *metav1.ListOptions) {
		if opts.TimeoutSeconds == nil {
			timeoutSec := int64(timeout.Seconds())
			opts.TimeoutSeconds = &timeoutSec
		}
	})
	return informers.NewFilteredSharedInformerFactory(cli, time.Minute, metav1.NamespaceAll, tweakFunc), nil
}
<|endoftext|>


<commit_before>package main

// #cgo LDFLAGS: -framework GLUT -framework OpenGL
//
// #include <stdlib.h>
// #include <GLUT/glut.h>
//
// void display(void);
// void idle(void);
//
// static void setGlutFuncs(void) {
//   glutDisplayFunc(display);
//   glutIdleFunc(idle);
// }
//
import "C"
import (
	"github.com/hajimehoshi/go.ebiten"
	"github.com/hajimehoshi/go.ebiten/example/game"
	"github.com/hajimehoshi/go.ebiten/graphics"
	"os"
	"runtime"
	"unsafe"
)

type GlutUI struct {
	screenWidth  int
	screenHeight int
	screenScale  int
	device       graphics.Device
}

var currentUI *GlutUI

//export display
func display() {
	currentUI.device.Update()
	C.glutSwapBuffers()
}

//export idle
func idle() {
	C.glutPostRedisplay()
}

func (ui *GlutUI) Init() {
	cargs := []*C.char{}
	for _, arg := range os.Args {
		cargs = append(cargs, C.CString(arg))
	}
	defer func() {
		for _, carg := range cargs {
			C.free(unsafe.Pointer(carg))
		}
	}()
	cargc := C.int(len(cargs))

	ui.screenWidth = 256
	ui.screenHeight = 240
	ui.screenScale = 2

	C.glutInit(&cargc, &cargs[0])
	C.glutInitDisplayMode(C.GLUT_RGBA)
	C.glutInitWindowSize(
		C.int(ui.screenWidth*ui.screenScale),
		C.int(ui.screenHeight*ui.screenScale))

	title := C.CString("Ebiten Demo")
	defer C.free(unsafe.Pointer(title))
	C.glutCreateWindow(title)

	C.setGlutFuncs()
}

func (ui *GlutUI) ScreenWidth() int {
	return ui.screenWidth
}

func (ui *GlutUI) ScreenHeight() int {
	return ui.screenHeight
}

func (ui *GlutUI) ScreenScale() int {
	return ui.screenScale
}

func (ui *GlutUI) Run(device graphics.Device) {
	ui.device = device
	C.glutMainLoop()
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	game := game.NewRotatingImage()
	currentUI = &GlutUI{}
	currentUI.Init()

	ebiten.OpenGLRun(game, currentUI)
}
<commit_msg>Run Sprites<commit_after>package main

// #cgo LDFLAGS: -framework GLUT -framework OpenGL
//
// #include <stdlib.h>
// #include <GLUT/glut.h>
//
// void display(void);
// void idle(void);
//
// static void setGlutFuncs(void) {
//   glutDisplayFunc(display);
//   glutIdleFunc(idle);
// }
//
import "C"
import (
	"github.com/hajimehoshi/go.ebiten"
	"github.com/hajimehoshi/go.ebiten/example/game"
	"github.com/hajimehoshi/go.ebiten/graphics"
	"os"
	"runtime"
	"unsafe"
)

type GlutUI struct {
	screenWidth  int
	screenHeight int
	screenScale  int
	device       graphics.Device
}

var currentUI *GlutUI

//export display
func display() {
	currentUI.device.Update()
	C.glutSwapBuffers()
}

//export idle
func idle() {
	C.glutPostRedisplay()
}

func (ui *GlutUI) Init() {
	cargs := []*C.char{}
	for _, arg := range os.Args {
		cargs = append(cargs, C.CString(arg))
	}
	defer func() {
		for _, carg := range cargs {
			C.free(unsafe.Pointer(carg))
		}
	}()
	cargc := C.int(len(cargs))

	ui.screenWidth = 256
	ui.screenHeight = 240
	ui.screenScale = 2

	C.glutInit(&cargc, &cargs[0])
	C.glutInitDisplayMode(C.GLUT_RGBA)
	C.glutInitWindowSize(
		C.int(ui.screenWidth*ui.screenScale),
		C.int(ui.screenHeight*ui.screenScale))

	title := C.CString("Ebiten Demo")
	defer C.free(unsafe.Pointer(title))
	C.glutCreateWindow(title)

	C.setGlutFuncs()
}

func (ui *GlutUI) ScreenWidth() int {
	return ui.screenWidth
}

func (ui *GlutUI) ScreenHeight() int {
	return ui.screenHeight
}

func (ui *GlutUI) ScreenScale() int {
	return ui.screenScale
}

func (ui *GlutUI) Run(device graphics.Device) {
	ui.device = device
	C.glutMainLoop()
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	gameName := ""
	if 2 <= len(os.Args) {
		gameName = os.Args[1]
	}

	var gm ebiten.Game
	switch gameName {
	case "sprites":
		gm = game.NewSprites()
	default:
		gm = game.NewRotatingImage()
	}
	currentUI = &GlutUI{}
	currentUI.Init()

	ebiten.OpenGLRun(gm, currentUI)
}
<|endoftext|>


<commit_before>package eth

import (
	"fmt"
)

const (
	ErrMsgTooLarge = iota
	ErrDecode
	ErrInvalidMsgCode
	ErrProtocolVersionMismatch
	ErrNetworkIdMismatch
	ErrGenesisBlockMismatch
	ErrNoStatusMsg
	ErrExtraStatusMsg
	ErrInvalidBlock
	ErrInvalidPoW
	ErrUnrequestedBlock
)

var errorToString = map[int]string{
	ErrMsgTooLarge:             "Message too long",
	ErrDecode:                  "Invalid message",
	ErrInvalidMsgCode:          "Invalid message code",
	ErrProtocolVersionMismatch: "Protocol version mismatch",
	ErrNetworkIdMismatch:       "NetworkId mismatch",
	ErrGenesisBlockMismatch:    "Genesis block mismatch",
	ErrNoStatusMsg:             "No status message",
	ErrExtraStatusMsg:          "Extra status message",
	ErrInvalidBlock:            "Invalid block",
	ErrInvalidPoW:              "Invalid PoW",
	ErrUnrequestedBlock:        "Unrequested block",
}

type protocolError struct {
	Code    int
	fatal   bool
	message string
	format  string
	params  []interface{}
	// size    int
}

func newProtocolError(code int, format string, params ...interface{}) *protocolError {
	return &protocolError{Code: code, format: format, params: params}
}

func ProtocolError(code int, format string, params ...interface{}) (err *protocolError) {
	err = newProtocolError(code, format, params...)
	// report(err)
	return
}

func (self protocolError) Error() (message string) {
	if len(message) == 0 {
		var ok bool
		self.message, ok = errorToString[self.Code]
		if !ok {
			panic("invalid error code")
		}
		if self.format != "" {
			self.message += ": " + fmt.Sprintf(self.format, self.params...)
		}
	}
	return self.message
}

func (self *protocolError) Fatal() bool {
	return self.fatal
}
<commit_msg>add ErrInsufficientChainInfo error<commit_after>package eth

import (
	"fmt"
)

const (
	ErrMsgTooLarge = iota
	ErrDecode
	ErrInvalidMsgCode
	ErrProtocolVersionMismatch
	ErrNetworkIdMismatch
	ErrGenesisBlockMismatch
	ErrNoStatusMsg
	ErrExtraStatusMsg
	ErrInvalidBlock
	ErrInvalidPoW
	ErrUnrequestedBlock
	ErrInsufficientChainInfo
)

var errorToString = map[int]string{
	ErrMsgTooLarge:             "Message too long",
	ErrDecode:                  "Invalid message",
	ErrInvalidMsgCode:          "Invalid message code",
	ErrProtocolVersionMismatch: "Protocol version mismatch",
	ErrNetworkIdMismatch:       "NetworkId mismatch",
	ErrGenesisBlockMismatch:    "Genesis block mismatch",
	ErrNoStatusMsg:             "No status message",
	ErrExtraStatusMsg:          "Extra status message",
	ErrInvalidBlock:            "Invalid block",
	ErrInvalidPoW:              "Invalid PoW",
	ErrUnrequestedBlock:        "Unrequested block",
	ErrInsufficientChainInfo:   "Insufficient chain info",
}

type protocolError struct {
	Code    int
	fatal   bool
	message string
	format  string
	params  []interface{}
	// size    int
}

func newProtocolError(code int, format string, params ...interface{}) *protocolError {
	return &protocolError{Code: code, format: format, params: params}
}

func ProtocolError(code int, format string, params ...interface{}) (err *protocolError) {
	err = newProtocolError(code, format, params...)
	// report(err)
	return
}

func (self protocolError) Error() (message string) {
	if len(message) == 0 {
		var ok bool
		self.message, ok = errorToString[self.Code]
		if !ok {
			panic("invalid error code")
		}
		if self.format != "" {
			self.message += ": " + fmt.Sprintf(self.format, self.params...)
		}
	}
	return self.message
}

func (self *protocolError) Fatal() bool {
	return self.fatal
}
<|endoftext|>


<commit_before>package mint_test

import "testing"
import "github.com/otiai10/mint"

func TestMint_ToBe(t *testing.T) {
	mint.Expect(t, 1).ToBe(1)
}
func TestMint_ToBe_Fail(t *testing.T) {
	r := mint.Expect(t, 2).Dry().ToBe(1)
	// assert mint by using mint
	mint.Expect(t, r.OK()).ToBe(false)
}

type MyStruct struct{}

func TestMint_TypeOf(t *testing.T) {
	mint.Expect(t, "foo").TypeOf("string")

	bar := MyStruct{}
	mint.Expect(t, bar).TypeOf("mint_test.MyStruct")
}
func TestMint_TypeOf_Fail(t *testing.T) {
	r := mint.Expect(t, "foo").Dry().TypeOf("int")
	// assert mint by using mint
	mint.Expect(t, r.OK()).ToBe(false)

	bar := MyStruct{}
	r = mint.Expect(t, bar).Dry().TypeOf("foo.Bar")
	// assert mint by using mint
	mint.Expect(t, r.OK()).ToBe(false)
	mint.Expect(t, r.Message()).ToBe("all_test.go at line 29\nExpected type\t`foo.Bar`\nBut actual\t`mint_test.MyStruct`")
}

func TestMint_Not(t *testing.T) {
	mint.Expect(t, 100).Not().ToBe(200)
	mint.Expect(t, "foo").Not().TypeOf("int")
	mint.Expect(t, true).Not().ToBe(nil)
}
func TestMint_Not_Fail(t *testing.T) {
	r := mint.Expect(t, "foo").Dry().Not().TypeOf("string")
	// assert mint by using mint
	mint.Expect(t, r.OK()).Not().ToBe(true)
}

func TestMint_Deeply(t *testing.T) {
	map0 := &map[int]string{
		3:  "three",
		5:  "five",
		10: "ten",
	}
	map1 := &map[int]string{
		3:  "three",
		5:  "five",
		10: "ten",
	}
	// It SHALLOWLY different.
	mint.Expect(t, map0).Not().ToBe(map1)
	// But it DEEPLY equal.
	mint.Expect(t, map0).Deeply().ToBe(map1)
}

func TestMint_Deeply_slice(t *testing.T) {
	s1 := []int{1, 2, 3}
	s2 := []int{4, 5, 6}
	s3 := []int{1, 2, 3}
	mint.Expect(t, s1).Not().ToBe(s2)
	mint.Expect(t, s1).ToBe(s3)
}
func TestMint_Deeply_map(t *testing.T) {
	m1 := map[int]int{1: 1, 2: 4, 3: 9}
	m2 := map[int]int{1: 1, 2: 4, 3: 6}
	m3 := map[int]int{1: 1, 2: 4, 3: 9}
	mint.Expect(t, m1).Not().ToBe(m2)
	mint.Expect(t, m1).ToBe(m3)
}

// Blend is a shorhand to get testee
func TestMint_Blend(t *testing.T) {
	m := mint.Blend(t)
	// assert mint by using mint
	mint.Expect(t, m).TypeOf("*mint.Mint")
	mint.Expect(t, m.Expect("foo")).TypeOf("*mint.Testee")
}
<commit_msg>Fix for travis<commit_after>package mint_test

import "testing"
import "github.com/otiai10/mint"

func TestMint_ToBe(t *testing.T) {
	mint.Expect(t, 1).ToBe(1)
}
func TestMint_ToBe_Fail(t *testing.T) {
	r := mint.Expect(t, 2).Dry().ToBe(1)
	// assert mint by using mint
	mint.Expect(t, r.OK()).ToBe(false)
}

type MyStruct struct{}

func TestMint_TypeOf(t *testing.T) {
	mint.Expect(t, "foo").TypeOf("string")

	bar := MyStruct{}
	mint.Expect(t, bar).TypeOf("mint_test.MyStruct")
}
func TestMint_TypeOf_Fail(t *testing.T) {
	r := mint.Expect(t, "foo").Dry().TypeOf("int")
	// assert mint by using mint
	mint.Expect(t, r.OK()).ToBe(false)

	bar := MyStruct{}
	r = mint.Expect(t, bar).Dry().TypeOf("foo.Bar")
	// assert mint by using mint
	mint.Expect(t, r.OK()).ToBe(false)
	mint.Expect(t, r.Message()).ToBe("all_test.go at line 29\n\tExpected type\t`foo.Bar`\n\tBut actual\t`mint_test.MyStruct`")
}

func TestMint_Not(t *testing.T) {
	mint.Expect(t, 100).Not().ToBe(200)
	mint.Expect(t, "foo").Not().TypeOf("int")
	mint.Expect(t, true).Not().ToBe(nil)
}
func TestMint_Not_Fail(t *testing.T) {
	r := mint.Expect(t, "foo").Dry().Not().TypeOf("string")
	// assert mint by using mint
	mint.Expect(t, r.OK()).Not().ToBe(true)
}

func TestMint_Deeply(t *testing.T) {
	map0 := &map[int]string{
		3:  "three",
		5:  "five",
		10: "ten",
	}
	map1 := &map[int]string{
		3:  "three",
		5:  "five",
		10: "ten",
	}
	// It SHALLOWLY different.
	mint.Expect(t, map0).Not().ToBe(map1)
	// But it DEEPLY equal.
	mint.Expect(t, map0).Deeply().ToBe(map1)
}

func TestMint_Deeply_slice(t *testing.T) {
	s1 := []int{1, 2, 3}
	s2 := []int{4, 5, 6}
	s3 := []int{1, 2, 3}
	mint.Expect(t, s1).Not().ToBe(s2)
	mint.Expect(t, s1).ToBe(s3)
}
func TestMint_Deeply_map(t *testing.T) {
	m1 := map[int]int{1: 1, 2: 4, 3: 9}
	m2 := map[int]int{1: 1, 2: 4, 3: 6}
	m3 := map[int]int{1: 1, 2: 4, 3: 9}
	mint.Expect(t, m1).Not().ToBe(m2)
	mint.Expect(t, m1).ToBe(m3)
}

// Blend is a shorhand to get testee
func TestMint_Blend(t *testing.T) {
	m := mint.Blend(t)
	// assert mint by using mint
	mint.Expect(t, m).TypeOf("*mint.Mint")
	mint.Expect(t, m.Expect("foo")).TypeOf("*mint.Testee")
}
<|endoftext|>


<commit_before>package main

import "fmt"

const rowLength = 8
const colLength = 8

type game struct {
	board [rowLength][colLength]int
	score map[int]int
	turn  int
}

var theGame = game{
	[8][8]int{},
	map[int]int{},
	1,
}

func setupGame() {
	theGame.board[3][3] = 1
	theGame.board[4][4] = 1
	theGame.board[3][4] = 2
	theGame.board[4][3] = 2
	theGame.score[1] = 2
	theGame.score[2] = 2
	printGame(&theGame.board)
	findPotentialMoves(theGame.board, 1)
}

func findPotentialMoves(board [8][8]int, p int) {
	for rowIndex, row := range board {
		for colIndex := range row {
			if board[rowIndex][colIndex] == p {
				checkDirection(0, 1, rowIndex, colIndex, p, &board)
				checkDirection(1, 1, rowIndex, colIndex, p, &board)
				checkDirection(0, -1, rowIndex, colIndex, p, &board)
				checkDirection(1, -1, rowIndex, colIndex, p, &board)
				checkDirection(1, 0, rowIndex, colIndex, p, &board)
				checkDirection(-1, -1, rowIndex, colIndex, p, &board)
				checkDirection(-1, 0, rowIndex, colIndex, p, &board)
				checkDirection(-1, 1, rowIndex, colIndex, p, &board)
			}
		}
	}
	printGame(&board)
}

func checkDirection(offsetY int, offsetX int, originX int, originY int, p int, board *[8][8]int) {
	if moveInBounds(offsetX+originX, offsetY+originY) {
		previousTile := board[originX][originY]
		tile := board[originX+offsetX][originY+offsetY]

		if tile != p && tile != 0 && tile != 3 {
			checkDirection(offsetY, offsetX, originX+offsetX, originY+offsetY, p, board)
		} else if previousTile != p && previousTile != 0 && previousTile != 3 && tile == 0 {
			board[originX+offsetX][originY+offsetY] = 3
		}
	}
}

func movePiece(move moveData) bool {
	var valid = false

	for i := -1; i < 2; i++ {
		for j := -1; j < 2; j++ {
			if i != 0 || j != 0 {
				moveMaid := validateCheckDirection(i, j, move.Row, move.Col, move.Player)
				if moveMaid == true {
					valid = true
				}
			}
		}
	}
	if valid {
		printGame(&theGame.board)
		findPotentialMoves(theGame.board, getOpposingPlayer(move.Player))
		theGame.turn = getOpposingPlayer(theGame.turn)
	}
	return valid
}

func validateCheckDirection(offsetY int, offsetX int, originX int, originY int, p int) bool {
	if moveInBounds(offsetX+originX, offsetY+originY) {
		oP := getOpposingPlayer(p)
		previousTile := theGame.board[originX][originY]
		tile := theGame.board[originX+offsetX][originY+offsetY]

		if tile != p && tile != 0 {
			if validateCheckDirection(offsetY, offsetX, originX+offsetX, originY+offsetY, p) {
				theGame.board[originX][originY] = p
				theGame.score[p] = theGame.score[p] + 1
				theGame.score[oP] = theGame.score[oP] - 1
				return true
			}
		} else if previousTile != p && previousTile != 0 && tile == p {
			theGame.board[originX][originY] = p
			theGame.score[p] = theGame.score[p] + 1
			return true
		}

		return false
	}
	return false
}

func getValueAt(move moveData) {
	if moveInBounds(move.Row, move.Col) {
		fmt.Println(move)
		fmt.Println(theGame.board[move.Row][move.Col])
	} else {
		fmt.Println("Move Out Of Bounds")
	}
}

func getOpposingPlayer(p int) int {
	if p == 1 {
		return 2
	}
	return 1
}

func moveInBounds(x int, y int) bool {
	return x > 0 && y > 0 && x < rowLength-1 && y < colLength-1
}

func printGame(board *[8][8]int) {
	for _, row := range board {
		fmt.Println(row)
	}
	fmt.Printf("Player1: %v - Player2: %v\n", theGame.score[1], theGame.score[2])
}
<commit_msg>Fixed bug with turn not resetting on new game<commit_after>package main

import "fmt"

const rowLength = 8
const colLength = 8

type game struct {
	board [rowLength][colLength]int
	score map[int]int
	turn  int
}

var theGame = game{
	[8][8]int{},
	map[int]int{},
	1,
}

func setupGame() {
	theGame.board[3][3] = 1
	theGame.board[4][4] = 1
	theGame.board[3][4] = 2
	theGame.board[4][3] = 2
	theGame.score[1] = 2
	theGame.score[2] = 2
	theGame.turn = 1
	printGame(&theGame.board)
	findPotentialMoves(theGame.board, 1)
}

func findPotentialMoves(board [8][8]int, p int) {
	for rowIndex, row := range board {
		for colIndex := range row {
			if board[rowIndex][colIndex] == p {
				checkDirection(0, 1, rowIndex, colIndex, p, &board)
				checkDirection(1, 1, rowIndex, colIndex, p, &board)
				checkDirection(0, -1, rowIndex, colIndex, p, &board)
				checkDirection(1, -1, rowIndex, colIndex, p, &board)
				checkDirection(1, 0, rowIndex, colIndex, p, &board)
				checkDirection(-1, -1, rowIndex, colIndex, p, &board)
				checkDirection(-1, 0, rowIndex, colIndex, p, &board)
				checkDirection(-1, 1, rowIndex, colIndex, p, &board)
			}
		}
	}
	printGame(&board)
}

func checkDirection(offsetY int, offsetX int, originX int, originY int, p int, board *[8][8]int) {
	if moveInBounds(offsetX+originX, offsetY+originY) {
		previousTile := board[originX][originY]
		tile := board[originX+offsetX][originY+offsetY]

		if tile != p && tile != 0 && tile != 3 {
			checkDirection(offsetY, offsetX, originX+offsetX, originY+offsetY, p, board)
		} else if previousTile != p && previousTile != 0 && previousTile != 3 && tile == 0 {
			board[originX+offsetX][originY+offsetY] = 3
		}
	}
}

func movePiece(move moveData) bool {
	var valid = false

	for i := -1; i < 2; i++ {
		for j := -1; j < 2; j++ {
			if i != 0 || j != 0 {
				moveMaid := validateCheckDirection(i, j, move.Row, move.Col, move.Player)
				if moveMaid == true {
					valid = true
				}
			}
		}
	}
	if valid {
		printGame(&theGame.board)
		findPotentialMoves(theGame.board, getOpposingPlayer(move.Player))
		theGame.turn = getOpposingPlayer(theGame.turn)
	}
	return valid
}

func validateCheckDirection(offsetY int, offsetX int, originX int, originY int, p int) bool {
	if moveInBounds(offsetX+originX, offsetY+originY) {
		oP := getOpposingPlayer(p)
		previousTile := theGame.board[originX][originY]
		tile := theGame.board[originX+offsetX][originY+offsetY]

		if tile != p && tile != 0 {
			if validateCheckDirection(offsetY, offsetX, originX+offsetX, originY+offsetY, p) {
				theGame.board[originX][originY] = p
				theGame.score[p] = theGame.score[p] + 1
				theGame.score[oP] = theGame.score[oP] - 1
				return true
			}
		} else if previousTile != p && previousTile != 0 && tile == p {
			theGame.board[originX][originY] = p
			theGame.score[p] = theGame.score[p] + 1
			return true
		}

		return false
	}
	return false
}

func getValueAt(move moveData) {
	if moveInBounds(move.Row, move.Col) {
		fmt.Println(move)
		fmt.Println(theGame.board[move.Row][move.Col])
	} else {
		fmt.Println("Move Out Of Bounds")
	}
}

func getOpposingPlayer(p int) int {
	if p == 1 {
		return 2
	}
	return 1
}

func moveInBounds(x int, y int) bool {
	return x > 0 && y > 0 && x < rowLength-1 && y < colLength-1
}

func printGame(board *[8][8]int) {
	for _, row := range board {
		fmt.Println(row)
	}
	fmt.Printf("Player1: %v - Player2: %v\n", theGame.score[1], theGame.score[2])
}
<|endoftext|>


<commit_before>// unico - Send Google+ activities to other networks
//
// Copyright 2011 The Unico Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package unico

import (
	"http"
	"os"
	"facebooklib"
	plus "google-api-go-client.googlecode.com/hg/plus/v1"
	"appengine"
	"appengine/urlfetch"

	"gorilla.googlecode.com/hg/gorilla/sessions"
)

func fbHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	id := "" //r.FormValue("id")

	if session, err := sessions.Session(r, "", "datastore"); err == nil {
		id = session["userID"].(string)
	}

	if id == "" {
		serveError(c, w, os.NewError("Missing ID Parameter"))
		return
	}

	fc := facebooklib.NewFacebookClient(appConfig.FacebookAppId, appConfig.FacebookAppSecret)
	fc.Transport = &urlfetch.Transport{Context: c}

	code := r.FormValue("code")
	if code == "" {

		http.Redirect(w, r, fc.AuthURL("http://"+appConfig.AppHost+"/fb?id="+id, "offline_access,publish_stream"), http.StatusFound)
		return
	}

	fc.RequestAccessToken(code, "http://"+appConfig.AppHost+"/fb?id="+id)
	user := loadUser(r, id)
	if user.Id == "" {
		serveError(c, w, os.NewError("Invalid user ID"))
		return
	}

	user.FBAccessToken = fc.AccessToken
	fbuser, _ := fc.CurrentUser()
	user.FBId = fbuser.Id
	user.FBName = fbuser.Name
	saveUser(r, &user)

	http.Redirect(w, r, "/", http.StatusFound)

}

func publishActivityToFacebook(w http.ResponseWriter, r *http.Request, act *plus.Activity, user *User) {
	c := appengine.NewContext(r)
	fc := facebooklib.NewFacebookClient(appConfig.FacebookAppId, appConfig.FacebookAppSecret)
	fc.Transport = &urlfetch.Transport{Context: c}
	fc.AccessToken = user.FBAccessToken

	_ = w

	var attachment *plus.ActivityObjectAttachments
	obj := act.Object
	kind := ""
	content := ""

	if act.Verb == "share" {
		content = act.Annotation
		if content == "" {
			content = "Resharing " + obj.Actor.DisplayName
		}
		kind = "status_share"
	} else {
		kind = "status"
		if obj != nil {
			if len(obj.Attachments) > 0 {
				attachment = obj.Attachments[0]
				kind = attachment.ObjectType
			}
			content = obj.Content
		} else {
			content = act.Title
		}

	}
	content = removeTags(content)

	var err os.Error

	switch kind {
	case "status":
		// post a status update
		err = fc.PostStatus(content)
		return
	case "article":
		// post a link
		err = fc.PostLink(content, attachment.Url)
	default:
		if obj != nil {
			err = fc.PostLink(content, obj.Url)
		}
	}

	if err == facebooklib.ErrOAuth {
		user.DisableFacebook()
		saveUser(r, user)
	}
	c.Debugf("publishActivityToFacebook(%s): err=%v\n", kind, err)

}
<commit_msg>No longer post "Resharing Someone" to FB<commit_after>// unico - Send Google+ activities to other networks
//
// Copyright 2011 The Unico Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package unico

import (
	"http"
	"os"
	"facebooklib"
	plus "google-api-go-client.googlecode.com/hg/plus/v1"
	"appengine"
	"appengine/urlfetch"

	"gorilla.googlecode.com/hg/gorilla/sessions"
)

func fbHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	id := "" //r.FormValue("id")

	if session, err := sessions.Session(r, "", "datastore"); err == nil {
		id = session["userID"].(string)
	}

	if id == "" {
		serveError(c, w, os.NewError("Missing ID Parameter"))
		return
	}

	fc := facebooklib.NewFacebookClient(appConfig.FacebookAppId, appConfig.FacebookAppSecret)
	fc.Transport = &urlfetch.Transport{Context: c}

	code := r.FormValue("code")
	if code == "" {

		http.Redirect(w, r, fc.AuthURL("http://"+appConfig.AppHost+"/fb?id="+id, "offline_access,publish_stream"), http.StatusFound)
		return
	}

	fc.RequestAccessToken(code, "http://"+appConfig.AppHost+"/fb?id="+id)
	user := loadUser(r, id)
	if user.Id == "" {
		serveError(c, w, os.NewError("Invalid user ID"))
		return
	}

	user.FBAccessToken = fc.AccessToken
	fbuser, _ := fc.CurrentUser()
	user.FBId = fbuser.Id
	user.FBName = fbuser.Name
	saveUser(r, &user)

	http.Redirect(w, r, "/", http.StatusFound)

}

func publishActivityToFacebook(w http.ResponseWriter, r *http.Request, act *plus.Activity, user *User) {
	c := appengine.NewContext(r)
	fc := facebooklib.NewFacebookClient(appConfig.FacebookAppId, appConfig.FacebookAppSecret)
	fc.Transport = &urlfetch.Transport{Context: c}
	fc.AccessToken = user.FBAccessToken

	_ = w

	var attachment *plus.ActivityObjectAttachments
	obj := act.Object
	kind := ""
	content := ""

	if act.Verb == "share" {
		content = act.Annotation
		//if content == "" {
		//	content = "Resharing " + obj.Actor.DisplayName
		//}
		kind = "status_share"
	} else {
		kind = "status"
		if obj != nil {
			if len(obj.Attachments) > 0 {
				attachment = obj.Attachments[0]
				kind = attachment.ObjectType
			}
			content = obj.Content
		} else {
			content = act.Title
		}

	}
	content = removeTags(content)

	var err os.Error

	switch kind {
	case "status":
		// post a status update
		err = fc.PostStatus(content)
		return
	case "article":
		// post a link
		err = fc.PostLink(content, attachment.Url)
	default:
		if obj != nil {
			err = fc.PostLink(content, obj.Url)
		}
	}

	if err == facebooklib.ErrOAuth {
		user.DisableFacebook()
		saveUser(r, user)
	}
	c.Debugf("publishActivityToFacebook(%s): err=%v\n", kind, err)

}
<|endoftext|>


<commit_before>package api

import (
	"fmt"
	"sort"
	"time"
)

const (
	// JobTypeService indicates a long-running processes
	JobTypeService = "service"

	// JobTypeBatch indicates a short-lived process
	JobTypeBatch = "batch"
)

const (
	// RegisterEnforceIndexErrPrefix is the prefix to use in errors caused by
	// enforcing the job modify index during registers.
	RegisterEnforceIndexErrPrefix = "Enforcing job modify index"
)

// Jobs is used to access the job-specific endpoints.
type Jobs struct {
	client *Client
}

// Jobs returns a handle on the jobs endpoints.
func (c *Client) Jobs() *Jobs {
	return &Jobs{client: c}
}

// Register is used to register a new job. It returns the ID
// of the evaluation, along with any errors encountered.
func (j *Jobs) Register(job *Job, q *WriteOptions) (string, *WriteMeta, error) {

	var resp registerJobResponse

	req := &RegisterJobRequest{Job: job}
	wm, err := j.client.write("/v1/jobs", req, &resp, q)
	if err != nil {
		return "", nil, err
	}
	return resp.EvalID, wm, nil
}

// EnforceRegister is used to register a job enforcing its job modify index.
func (j *Jobs) EnforceRegister(job *Job, modifyIndex uint64, q *WriteOptions) (string, *WriteMeta, error) {

	var resp registerJobResponse

	req := &RegisterJobRequest{
		Job:            job,
		EnforceIndex:   true,
		JobModifyIndex: modifyIndex,
	}
	wm, err := j.client.write("/v1/jobs", req, &resp, q)
	if err != nil {
		return "", nil, err
	}
	return resp.EvalID, wm, nil
}

// List is used to list all of the existing jobs.
func (j *Jobs) List(q *QueryOptions) ([]*JobListStub, *QueryMeta, error) {
	var resp []*JobListStub
	qm, err := j.client.query("/v1/jobs", &resp, q)
	if err != nil {
		return nil, qm, err
	}
	sort.Sort(JobIDSort(resp))
	return resp, qm, nil
}

// PrefixList is used to list all existing jobs that match the prefix.
func (j *Jobs) PrefixList(prefix string) ([]*JobListStub, *QueryMeta, error) {
	return j.List(&QueryOptions{Prefix: prefix})
}

// Info is used to retrieve information about a particular
// job given its unique ID.
func (j *Jobs) Info(jobID string, q *QueryOptions) (*Job, *QueryMeta, error) {
	var resp Job
	qm, err := j.client.query("/v1/job/"+jobID, &resp, q)
	if err != nil {
		return nil, nil, err
	}
	return &resp, qm, nil
}

// Allocations is used to return the allocs for a given job ID.
func (j *Jobs) Allocations(jobID string, q *QueryOptions) ([]*AllocationListStub, *QueryMeta, error) {
	var resp []*AllocationListStub
	qm, err := j.client.query("/v1/job/"+jobID+"/allocations", &resp, q)
	if err != nil {
		return nil, nil, err
	}
	sort.Sort(AllocIndexSort(resp))
	return resp, qm, nil
}

// Evaluations is used to query the evaluations associated with
// the given job ID.
func (j *Jobs) Evaluations(jobID string, q *QueryOptions) ([]*Evaluation, *QueryMeta, error) {
	var resp []*Evaluation
	qm, err := j.client.query("/v1/job/"+jobID+"/evaluations", &resp, q)
	if err != nil {
		return nil, nil, err
	}
	sort.Sort(EvalIndexSort(resp))
	return resp, qm, nil
}

// Deregister is used to remove an existing job.
func (j *Jobs) Deregister(jobID string, q *WriteOptions) (string, *WriteMeta, error) {
	var resp deregisterJobResponse
	wm, err := j.client.delete("/v1/job/"+jobID, &resp, q)
	if err != nil {
		return "", nil, err
	}
	return resp.EvalID, wm, nil
}

// ForceEvaluate is used to force-evaluate an existing job.
func (j *Jobs) ForceEvaluate(jobID string, q *WriteOptions) (string, *WriteMeta, error) {
	var resp registerJobResponse
	wm, err := j.client.write("/v1/job/"+jobID+"/evaluate", nil, &resp, q)
	if err != nil {
		return "", nil, err
	}
	return resp.EvalID, wm, nil
}

// PeriodicForce spawns a new instance of the periodic job and returns the eval ID
func (j *Jobs) PeriodicForce(jobID string, q *WriteOptions) (string, *WriteMeta, error) {
	var resp periodicForceResponse
	wm, err := j.client.write("/v1/job/"+jobID+"/periodic/force", nil, &resp, q)
	if err != nil {
		return "", nil, err
	}
	return resp.EvalID, wm, nil
}

func (j *Jobs) Plan(job *Job, diff bool, q *WriteOptions) (*JobPlanResponse, *WriteMeta, error) {
	if job == nil {
		return nil, nil, fmt.Errorf("must pass non-nil job")
	}

	var resp JobPlanResponse
	req := &JobPlanRequest{
		Job:  job,
		Diff: diff,
	}
	wm, err := j.client.write("/v1/job/"+job.ID+"/plan", req, &resp, q)
	if err != nil {
		return nil, nil, err
	}

	return &resp, wm, nil
}

func (j *Jobs) Summary(jobID string, q *QueryOptions) (*JobSummary, *QueryMeta, error) {
	var resp JobSummary
	qm, err := j.client.query("/v1/job/"+jobID+"/summary", &resp, q)
	if err != nil {
		return nil, nil, err
	}
	return &resp, qm, nil
}

// periodicForceResponse is used to deserialize a force response
type periodicForceResponse struct {
	EvalID string
}

// UpdateStrategy is for serializing update strategy for a job.
type UpdateStrategy struct {
	Stagger     time.Duration
	MaxParallel int
}

// PeriodicConfig is for serializing periodic config for a job.
type PeriodicConfig struct {
	Enabled         bool
	Spec            string
	SpecType        string
	ProhibitOverlap bool
}

// Job is used to serialize a job.
type Job struct {
	Region            string
	ID                string
	Name              string
	Type              string
	Priority          int
	AllAtOnce         bool
	Datacenters       []string
	Constraints       []*Constraint
	TaskGroups        []*TaskGroup
	Update            *UpdateStrategy
	Periodic          *PeriodicConfig
	Meta              map[string]string
	VaultToken        string
	Status            string
	StatusDescription string
	CreateIndex       uint64
	ModifyIndex       uint64
	JobModifyIndex    uint64
}

// JobSummary summarizes the state of the allocations of a job
type JobSummary struct {
	JobID   string
	Summary map[string]TaskGroupSummary

	// Raft Indexes
	CreateIndex uint64
	ModifyIndex uint64
}

// TaskGroup summarizes the state of all the allocations of a particular
// TaskGroup
type TaskGroupSummary struct {
	Queued   int
	Complete int
	Failed   int
	Running  int
	Starting int
	Lost     int
}

// JobListStub is used to return a subset of information about
// jobs during list operations.
type JobListStub struct {
	ID                string
	ParentID          string
	Name              string
	Type              string
	Priority          int
	Status            string
	StatusDescription string
	JobSummary        *JobSummary
	CreateIndex       uint64
	ModifyIndex       uint64
	JobModifyIndex    uint64
}

// JobIDSort is used to sort jobs by their job ID's.
type JobIDSort []*JobListStub

func (j JobIDSort) Len() int {
	return len(j)
}

func (j JobIDSort) Less(a, b int) bool {
	return j[a].ID < j[b].ID
}

func (j JobIDSort) Swap(a, b int) {
	j[a], j[b] = j[b], j[a]
}

// NewServiceJob creates and returns a new service-style job
// for long-lived processes using the provided name, ID, and
// relative job priority.
func NewServiceJob(id, name, region string, pri int) *Job {
	return newJob(id, name, region, JobTypeService, pri)
}

// NewBatchJob creates and returns a new batch-style job for
// short-lived processes using the provided name and ID along
// with the relative job priority.
func NewBatchJob(id, name, region string, pri int) *Job {
	return newJob(id, name, region, JobTypeBatch, pri)
}

// newJob is used to create a new Job struct.
func newJob(id, name, region, typ string, pri int) *Job {
	return &Job{
		Region:   region,
		ID:       id,
		Name:     name,
		Type:     typ,
		Priority: pri,
	}
}

// SetMeta is used to set arbitrary k/v pairs of metadata on a job.
func (j *Job) SetMeta(key, val string) *Job {
	if j.Meta == nil {
		j.Meta = make(map[string]string)
	}
	j.Meta[key] = val
	return j
}

// AddDatacenter is used to add a datacenter to a job.
func (j *Job) AddDatacenter(dc string) *Job {
	j.Datacenters = append(j.Datacenters, dc)
	return j
}

// Constrain is used to add a constraint to a job.
func (j *Job) Constrain(c *Constraint) *Job {
	j.Constraints = append(j.Constraints, c)
	return j
}

// AddTaskGroup adds a task group to an existing job.
func (j *Job) AddTaskGroup(grp *TaskGroup) *Job {
	j.TaskGroups = append(j.TaskGroups, grp)
	return j
}

// AddPeriodicConfig adds a periodic config to an existing job.
func (j *Job) AddPeriodicConfig(cfg *PeriodicConfig) *Job {
	j.Periodic = cfg
	return j
}

// RegisterJobRequest is used to serialize a job registration
type RegisterJobRequest struct {
	Job            *Job
	EnforceIndex   bool   `json:",omitempty"`
	JobModifyIndex uint64 `json:",omitempty"`
}

// registerJobResponse is used to deserialize a job response
type registerJobResponse struct {
	EvalID string
}

// deregisterJobResponse is used to decode a deregister response
type deregisterJobResponse struct {
	EvalID string
}

type JobPlanRequest struct {
	Job  *Job
	Diff bool
}

type JobPlanResponse struct {
	JobModifyIndex     uint64
	CreatedEvals       []*Evaluation
	Diff               *JobDiff
	Annotations        *PlanAnnotations
	FailedTGAllocs     map[string]*AllocationMetric
	NextPeriodicLaunch time.Time
}

type JobDiff struct {
	Type       string
	ID         string
	Fields     []*FieldDiff
	Objects    []*ObjectDiff
	TaskGroups []*TaskGroupDiff
}

type TaskGroupDiff struct {
	Type    string
	Name    string
	Fields  []*FieldDiff
	Objects []*ObjectDiff
	Tasks   []*TaskDiff
	Updates map[string]uint64
}

type TaskDiff struct {
	Type        string
	Name        string
	Fields      []*FieldDiff
	Objects     []*ObjectDiff
	Annotations []string
}

type FieldDiff struct {
	Type        string
	Name        string
	Old, New    string
	Annotations []string
}

type ObjectDiff struct {
	Type    string
	Name    string
	Fields  []*FieldDiff
	Objects []*ObjectDiff
}

type PlanAnnotations struct {
	DesiredTGUpdates map[string]*DesiredUpdates
}

type DesiredUpdates struct {
	Ignore            uint64
	Place             uint64
	Migrate           uint64
	Stop              uint64
	InPlaceUpdate     uint64
	DestructiveUpdate uint64
}
<commit_msg>Include parent ID in job info returned by Go API<commit_after>package api

import (
	"fmt"
	"sort"
	"time"
)

const (
	// JobTypeService indicates a long-running processes
	JobTypeService = "service"

	// JobTypeBatch indicates a short-lived process
	JobTypeBatch = "batch"
)

const (
	// RegisterEnforceIndexErrPrefix is the prefix to use in errors caused by
	// enforcing the job modify index during registers.
	RegisterEnforceIndexErrPrefix = "Enforcing job modify index"
)

// Jobs is used to access the job-specific endpoints.
type Jobs struct {
	client *Client
}

// Jobs returns a handle on the jobs endpoints.
func (c *Client) Jobs() *Jobs {
	return &Jobs{client: c}
}

// Register is used to register a new job. It returns the ID
// of the evaluation, along with any errors encountered.
func (j *Jobs) Register(job *Job, q *WriteOptions) (string, *WriteMeta, error) {

	var resp registerJobResponse

	req := &RegisterJobRequest{Job: job}
	wm, err := j.client.write("/v1/jobs", req, &resp, q)
	if err != nil {
		return "", nil, err
	}
	return resp.EvalID, wm, nil
}

// EnforceRegister is used to register a job enforcing its job modify index.
func (j *Jobs) EnforceRegister(job *Job, modifyIndex uint64, q *WriteOptions) (string, *WriteMeta, error) {

	var resp registerJobResponse

	req := &RegisterJobRequest{
		Job:            job,
		EnforceIndex:   true,
		JobModifyIndex: modifyIndex,
	}
	wm, err := j.client.write("/v1/jobs", req, &resp, q)
	if err != nil {
		return "", nil, err
	}
	return resp.EvalID, wm, nil
}

// List is used to list all of the existing jobs.
func (j *Jobs) List(q *QueryOptions) ([]*JobListStub, *QueryMeta, error) {
	var resp []*JobListStub
	qm, err := j.client.query("/v1/jobs", &resp, q)
	if err != nil {
		return nil, qm, err
	}
	sort.Sort(JobIDSort(resp))
	return resp, qm, nil
}

// PrefixList is used to list all existing jobs that match the prefix.
func (j *Jobs) PrefixList(prefix string) ([]*JobListStub, *QueryMeta, error) {
	return j.List(&QueryOptions{Prefix: prefix})
}

// Info is used to retrieve information about a particular
// job given its unique ID.
func (j *Jobs) Info(jobID string, q *QueryOptions) (*Job, *QueryMeta, error) {
	var resp Job
	qm, err := j.client.query("/v1/job/"+jobID, &resp, q)
	if err != nil {
		return nil, nil, err
	}
	return &resp, qm, nil
}

// Allocations is used to return the allocs for a given job ID.
func (j *Jobs) Allocations(jobID string, q *QueryOptions) ([]*AllocationListStub, *QueryMeta, error) {
	var resp []*AllocationListStub
	qm, err := j.client.query("/v1/job/"+jobID+"/allocations", &resp, q)
	if err != nil {
		return nil, nil, err
	}
	sort.Sort(AllocIndexSort(resp))
	return resp, qm, nil
}

// Evaluations is used to query the evaluations associated with
// the given job ID.
func (j *Jobs) Evaluations(jobID string, q *QueryOptions) ([]*Evaluation, *QueryMeta, error) {
	var resp []*Evaluation
	qm, err := j.client.query("/v1/job/"+jobID+"/evaluations", &resp, q)
	if err != nil {
		return nil, nil, err
	}
	sort.Sort(EvalIndexSort(resp))
	return resp, qm, nil
}

// Deregister is used to remove an existing job.
func (j *Jobs) Deregister(jobID string, q *WriteOptions) (string, *WriteMeta, error) {
	var resp deregisterJobResponse
	wm, err := j.client.delete("/v1/job/"+jobID, &resp, q)
	if err != nil {
		return "", nil, err
	}
	return resp.EvalID, wm, nil
}

// ForceEvaluate is used to force-evaluate an existing job.
func (j *Jobs) ForceEvaluate(jobID string, q *WriteOptions) (string, *WriteMeta, error) {
	var resp registerJobResponse
	wm, err := j.client.write("/v1/job/"+jobID+"/evaluate", nil, &resp, q)
	if err != nil {
		return "", nil, err
	}
	return resp.EvalID, wm, nil
}

// PeriodicForce spawns a new instance of the periodic job and returns the eval ID
func (j *Jobs) PeriodicForce(jobID string, q *WriteOptions) (string, *WriteMeta, error) {
	var resp periodicForceResponse
	wm, err := j.client.write("/v1/job/"+jobID+"/periodic/force", nil, &resp, q)
	if err != nil {
		return "", nil, err
	}
	return resp.EvalID, wm, nil
}

func (j *Jobs) Plan(job *Job, diff bool, q *WriteOptions) (*JobPlanResponse, *WriteMeta, error) {
	if job == nil {
		return nil, nil, fmt.Errorf("must pass non-nil job")
	}

	var resp JobPlanResponse
	req := &JobPlanRequest{
		Job:  job,
		Diff: diff,
	}
	wm, err := j.client.write("/v1/job/"+job.ID+"/plan", req, &resp, q)
	if err != nil {
		return nil, nil, err
	}

	return &resp, wm, nil
}

func (j *Jobs) Summary(jobID string, q *QueryOptions) (*JobSummary, *QueryMeta, error) {
	var resp JobSummary
	qm, err := j.client.query("/v1/job/"+jobID+"/summary", &resp, q)
	if err != nil {
		return nil, nil, err
	}
	return &resp, qm, nil
}

// periodicForceResponse is used to deserialize a force response
type periodicForceResponse struct {
	EvalID string
}

// UpdateStrategy is for serializing update strategy for a job.
type UpdateStrategy struct {
	Stagger     time.Duration
	MaxParallel int
}

// PeriodicConfig is for serializing periodic config for a job.
type PeriodicConfig struct {
	Enabled         bool
	Spec            string
	SpecType        string
	ProhibitOverlap bool
}

// Job is used to serialize a job.
type Job struct {
	Region            string
	ID                string
	ParentID          string
	Name              string
	Type              string
	Priority          int
	AllAtOnce         bool
	Datacenters       []string
	Constraints       []*Constraint
	TaskGroups        []*TaskGroup
	Update            *UpdateStrategy
	Periodic          *PeriodicConfig
	Meta              map[string]string
	VaultToken        string
	Status            string
	StatusDescription string
	CreateIndex       uint64
	ModifyIndex       uint64
	JobModifyIndex    uint64
}

// JobSummary summarizes the state of the allocations of a job
type JobSummary struct {
	JobID   string
	Summary map[string]TaskGroupSummary

	// Raft Indexes
	CreateIndex uint64
	ModifyIndex uint64
}

// TaskGroup summarizes the state of all the allocations of a particular
// TaskGroup
type TaskGroupSummary struct {
	Queued   int
	Complete int
	Failed   int
	Running  int
	Starting int
	Lost     int
}

// JobListStub is used to return a subset of information about
// jobs during list operations.
type JobListStub struct {
	ID                string
	ParentID          string
	Name              string
	Type              string
	Priority          int
	Status            string
	StatusDescription string
	JobSummary        *JobSummary
	CreateIndex       uint64
	ModifyIndex       uint64
	JobModifyIndex    uint64
}

// JobIDSort is used to sort jobs by their job ID's.
type JobIDSort []*JobListStub

func (j JobIDSort) Len() int {
	return len(j)
}

func (j JobIDSort) Less(a, b int) bool {
	return j[a].ID < j[b].ID
}

func (j JobIDSort) Swap(a, b int) {
	j[a], j[b] = j[b], j[a]
}

// NewServiceJob creates and returns a new service-style job
// for long-lived processes using the provided name, ID, and
// relative job priority.
func NewServiceJob(id, name, region string, pri int) *Job {
	return newJob(id, name, region, JobTypeService, pri)
}

// NewBatchJob creates and returns a new batch-style job for
// short-lived processes using the provided name and ID along
// with the relative job priority.
func NewBatchJob(id, name, region string, pri int) *Job {
	return newJob(id, name, region, JobTypeBatch, pri)
}

// newJob is used to create a new Job struct.
func newJob(id, name, region, typ string, pri int) *Job {
	return &Job{
		Region:   region,
		ID:       id,
		Name:     name,
		Type:     typ,
		Priority: pri,
	}
}

// SetMeta is used to set arbitrary k/v pairs of metadata on a job.
func (j *Job) SetMeta(key, val string) *Job {
	if j.Meta == nil {
		j.Meta = make(map[string]string)
	}
	j.Meta[key] = val
	return j
}

// AddDatacenter is used to add a datacenter to a job.
func (j *Job) AddDatacenter(dc string) *Job {
	j.Datacenters = append(j.Datacenters, dc)
	return j
}

// Constrain is used to add a constraint to a job.
func (j *Job) Constrain(c *Constraint) *Job {
	j.Constraints = append(j.Constraints, c)
	return j
}

// AddTaskGroup adds a task group to an existing job.
func (j *Job) AddTaskGroup(grp *TaskGroup) *Job {
	j.TaskGroups = append(j.TaskGroups, grp)
	return j
}

// AddPeriodicConfig adds a periodic config to an existing job.
func (j *Job) AddPeriodicConfig(cfg *PeriodicConfig) *Job {
	j.Periodic = cfg
	return j
}

// RegisterJobRequest is used to serialize a job registration
type RegisterJobRequest struct {
	Job            *Job
	EnforceIndex   bool   `json:",omitempty"`
	JobModifyIndex uint64 `json:",omitempty"`
}

// registerJobResponse is used to deserialize a job response
type registerJobResponse struct {
	EvalID string
}

// deregisterJobResponse is used to decode a deregister response
type deregisterJobResponse struct {
	EvalID string
}

type JobPlanRequest struct {
	Job  *Job
	Diff bool
}

type JobPlanResponse struct {
	JobModifyIndex     uint64
	CreatedEvals       []*Evaluation
	Diff               *JobDiff
	Annotations        *PlanAnnotations
	FailedTGAllocs     map[string]*AllocationMetric
	NextPeriodicLaunch time.Time
}

type JobDiff struct {
	Type       string
	ID         string
	Fields     []*FieldDiff
	Objects    []*ObjectDiff
	TaskGroups []*TaskGroupDiff
}

type TaskGroupDiff struct {
	Type    string
	Name    string
	Fields  []*FieldDiff
	Objects []*ObjectDiff
	Tasks   []*TaskDiff
	Updates map[string]uint64
}

type TaskDiff struct {
	Type        string
	Name        string
	Fields      []*FieldDiff
	Objects     []*ObjectDiff
	Annotations []string
}

type FieldDiff struct {
	Type        string
	Name        string
	Old, New    string
	Annotations []string
}

type ObjectDiff struct {
	Type    string
	Name    string
	Fields  []*FieldDiff
	Objects []*ObjectDiff
}

type PlanAnnotations struct {
	DesiredTGUpdates map[string]*DesiredUpdates
}

type DesiredUpdates struct {
	Ignore            uint64
	Place             uint64
	Migrate           uint64
	Stop              uint64
	InPlaceUpdate     uint64
	DestructiveUpdate uint64
}
<|endoftext|>