<commit_before>package db

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path"
	"testing"
)

/*
 * Lowest-layer database tests
 */

func Test_DbFileCreation(t *testing.T) {
	dir, err := ioutil.TempDir("", "rqlite-test-")
	defer os.RemoveAll(dir)

	db, err := Open(path.Join(dir, "test_db"))
	if err != nil {
		t.Fatalf("failed to open new database: %s", err.Error())
	}
	if db == nil {
		t.Fatal("database is nil")
	}
	err = db.Close()
	if err != nil {
		t.Fatalf("failed to close database: %s", err.Error())
	}
}

func Test_TableCreation(t *testing.T) {
	db, path := mustOpenDatabase()
	defer db.Close()
	defer os.Remove(path)

	err := db.Execute("create table foo (id integer not null primary key, name text)")
	if err != nil {
		t.Fatalf("failed to create table: %s", err.Error())
	}

	r, err := db.Query("SELECT * FROM foo")
	if err != nil {
		t.Fatalf("failed to query empty table: %s", err.Error())
	}
	if len(r) != 0 {
		t.Fatalf("expected 0 results, got %d", len(r))
	}
}

func Test_SimpleStatements(t *testing.T) {
	db, path := mustOpenDatabase()
	defer db.Close()
	defer os.Remove(path)

	if err := db.Execute("create table foo (id integer not null primary key, name text)"); err != nil {
		t.Fatalf("failed to create table: %s", err.Error())
	}

	if err := db.Execute(`INSERT INTO foo(name) VALUES("fiona")`); err != nil {
		t.Fatalf("failed to insert record: %s", err.Error())
	}
	r, err := db.Query("SELECT * FROM foo")
	if err != nil {
		t.Fatalf("failed to query empty table: %s", err.Error())
	}
	if exp, got := `[{"id":"1","name":"fiona"}]`, asJson(r); exp != got {
		t.Fatalf("unexpected results for query, expected %s, got %s", exp, got)
	}

	if err := db.Execute(`INSERT INTO foo(name) VALUES("aoife")`); err != nil {
		t.Fatalf("failed to insert record: %s", err.Error())
	}
	r, err = db.Query("SELECT * FROM foo")
	if err != nil {
		t.Fatalf("failed to query table: %s", err.Error())
	}
	if exp, got := `[{"id":"1","name":"fiona"},{"id":"2","name":"aoife"}]`, asJson(r); exp != got {
		t.Fatalf("unexpected results for query, expected %s, got %s", exp, got)
	}

	if err := db.Execute("UPDATE foo SET Name='Who knows?' WHERE Id=1"); err != nil {
		t.Fatalf("failed to update record: %s", err.Error())
	}
	r, err = db.Query("SELECT * FROM foo")
	if err != nil {
		t.Fatalf("failed to query table: %s", err.Error())
	}
	if exp, got := `[{"id":"1","name":"Who knows?"},{"id":"2","name":"aoife"}]`, asJson(r); exp != got {
		t.Fatalf("unexpected results for query, expected %s, got %s", exp, got)
	}

	if err := db.Execute("DELETE FROM foo WHERE Id=2"); err != nil {
		t.Fatalf("failed to delete record: %s", err.Error())
	}
	r, err = db.Query("SELECT * FROM foo")
	if err != nil {
		t.Fatalf("failed to query table: %s", err.Error())
	}
	if exp, got := `[{"id":"1","name":"Who knows?"}]`, asJson(r); exp != got {
		t.Fatalf("unexpected results for query, expected %s, got %s", exp, got)
	}
}

func Test_FailingSimpleStatements(t *testing.T) {
	db, path := mustOpenDatabase()
	defer db.Close()
	defer os.Remove(path)

	err := db.Execute(`INSERT INTO foo(name) VALUES("fiona")`)
	if err == nil {
		t.Fatal("inserted record into empty table OK")
	}
	if err.Error() != "no such table: foo" {
		t.Fatal("unexpected error returned")
	}

	if err = db.Execute("create table foo (id integer not null primary key, name text)"); err != nil {
		t.Fatalf("failed to create table: %s", err.Error())
	}
	if err = db.Execute("create table foo (id integer not null primary key, name text)"); err == nil {
		t.Fatal("duplicate table created OK")
	}
	if err.Error() != "table foo already exists" {
		t.Fatalf("unexpected error returned: %s", err.Error())
	}

	if err = db.Execute(`INSERT INTO foo(id, name) VALUES(11, "fiona")`); err != nil {
		t.Fatalf("failed to insert record: %s", err.Error())
	}
	if err = db.Execute(`INSERT INTO foo(id, name) VALUES(11, "fiona")`); err == nil {
		t.Fatal("duplicated record inserted OK")
	}
	if err.Error() != "UNIQUE constraint failed: foo.id" {
		t.Fatal("unexpected error returned")
	}

	if err = db.Execute("SELECT * FROM bar"); err == nil {
		t.Fatal("no error when querying non-existant table")
	}
	if err.Error() != "no such table: bar" {
		t.Fatal("unexpected error returned")
	}

	if err = db.Execute("utter nonsense"); err == nil {
		t.Fatal("no error when issuing nonsense query")
	}
	if err.Error() != `near "utter": syntax error` {
		t.Fatal("unexpected error returned")
	}
}

func Test_SimpleTransactions(t *testing.T) {
	db, path := mustOpenDatabase()
	defer db.Close()
	defer os.Remove(path)

	if err := db.Execute("create table foo (id integer not null primary key, name text)"); err != nil {
		t.Fatalf("failed to create table: %s", err.Error())
	}

	if err := db.StartTransaction(); err != nil {
		t.Fatalf("failed to start transaction: %s", err.Error())
	}
	for i := 0; i < 10; i++ {
		_ = db.Execute(`INSERT INTO foo(name) VALUES("philip")`)
	}
	if err := db.CommitTransaction(); err != nil {
		t.Fatalf("failed to commit transaction: %s", err.Error())
	}

	r, err := db.Query("SELECT name FROM foo")
	if err != nil {
		t.Fatalf("failed to query after commited transaction: %s", err.Error())
	}
	if len(r) != 10 {
		t.Fatalf("incorrect number of results returned: %d", len(r))
	}

	if err := db.StartTransaction(); err != nil {
		t.Fatalf("failed to start transaction: %s", err.Error())
	}
	for i := 0; i < 10; i++ {
		_ = db.Execute(`INSERT INTO foo(name) VALUES("philip")`)
	}
	if err := db.RollbackTransaction(); err != nil {
		t.Fatalf("failed to rollback transaction: %s", err.Error())
	}

	r, err = db.Query("SELECT name FROM foo")
	if err != nil {
		t.Fatalf("failed to query after commited transaction: %s", err.Error())
	}
	if len(r) != 10 {
		t.Fatalf("incorrect number of results returned: %d", len(r))
	}
}

func Test_TransactionsConstraintViolation(t *testing.T) {
	db, path := mustOpenDatabase()
	defer db.Close()
	defer os.Remove(path)
	var err error

	if err = db.Execute("create table foo (id integer not null primary key, name text)"); err != nil {
		t.Fatalf("failed to create table: %s", err.Error())
	}

	if err = db.StartTransaction(); err != nil {
		t.Fatalf("failed to start transaction: %s", err.Error())
	}
	if err = db.Execute(`INSERT INTO foo(id, name) VALUES(11, "fiona")`); err != nil {
		t.Fatalf("failed to insert record: %s", err.Error())
	}
	if err = db.Execute(`INSERT INTO foo(id, name) VALUES(11, "fiona")`); err == nil {
		t.Fatal("duplicated record inserted OK")
	}
	if err.Error() != "UNIQUE constraint failed: foo.id" {
		t.Fatal("unexpected error returned")
	}
	if err := db.RollbackTransaction(); err != nil {
		t.Fatalf("failed to rollback transaction: %s", err.Error())
	}
	r, err := db.Query("SELECT name FROM foo")
	if err != nil {
		t.Fatalf("failed to query after commited transaction: %s", err.Error())
	}
	if len(r) != 0 {
		t.Fatalf("incorrect number of results returned: %d", len(r))
	}
}

func Test_TransactionsHardFail(t *testing.T) {
	db, path := mustOpenDatabase()
	defer db.Close()
	defer os.Remove(path)
	var err error

	if err = db.Execute("create table foo (id integer not null primary key, name text)"); err != nil {
		t.Fatalf("failed to create table: %s", err.Error())
	}
	if err = db.Execute(`INSERT INTO foo(id, name) VALUES(1, "fiona")`); err != nil {
		t.Fatalf("failed to insert record: %s", err.Error())
	}

	if err = db.StartTransaction(); err != nil {
		t.Fatalf("failed to start transaction: %s", err.Error())
	}
	if err = db.Execute(`INSERT INTO foo(id, name) VALUES(2, "fiona")`); err != nil {
		t.Fatalf("failed to insert record: %s", err.Error())
	}
	if err = db.Close(); err != nil {
		t.Fatalf("failed to close database: %s", err.Error())
	}

	db, err = Open(path)
	if err != nil {
		t.Fatalf("failed to re-open database: %s", err.Error())
	}
	r, err := db.Query("SELECT * FROM foo")
	if err != nil {
		t.Fatalf("failed to query after hard close: %s", err.Error())
	}
	if len(r) != 1 {
		t.Fatalf("incorrect number of results returned: %d", len(r))
	}
}

func mustOpenDatabase() (*DB, string) {
	var err error
	f, err := ioutil.TempFile("", "rqlilte-test-")
	if err != nil {
		panic("failed to create temp file")
	}
	f.Close()

	db, err := Open(f.Name())
	if err != nil {
		panic("failed to open database")
	}

	return db, f.Name()
}

func asJson(v interface{}) string {
	b, err := json.Marshal(v)
	if err != nil {
		panic("failed to JSON marshal value")
	}
	return string(b)
}
<commit_msg>Better name for test helper<commit_after>package db

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path"
	"testing"
)

/*
 * Lowest-layer database tests
 */

func Test_DbFileCreation(t *testing.T) {
	dir, err := ioutil.TempDir("", "rqlite-test-")
	defer os.RemoveAll(dir)

	db, err := Open(path.Join(dir, "test_db"))
	if err != nil {
		t.Fatalf("failed to open new database: %s", err.Error())
	}
	if db == nil {
		t.Fatal("database is nil")
	}
	err = db.Close()
	if err != nil {
		t.Fatalf("failed to close database: %s", err.Error())
	}
}

func Test_TableCreation(t *testing.T) {
	db, path := mustCreateDatabase()
	defer db.Close()
	defer os.Remove(path)

	err := db.Execute("create table foo (id integer not null primary key, name text)")
	if err != nil {
		t.Fatalf("failed to create table: %s", err.Error())
	}

	r, err := db.Query("SELECT * FROM foo")
	if err != nil {
		t.Fatalf("failed to query empty table: %s", err.Error())
	}
	if len(r) != 0 {
		t.Fatalf("expected 0 results, got %d", len(r))
	}
}

func Test_SimpleStatements(t *testing.T) {
	db, path := mustCreateDatabase()
	defer db.Close()
	defer os.Remove(path)

	if err := db.Execute("create table foo (id integer not null primary key, name text)"); err != nil {
		t.Fatalf("failed to create table: %s", err.Error())
	}

	if err := db.Execute(`INSERT INTO foo(name) VALUES("fiona")`); err != nil {
		t.Fatalf("failed to insert record: %s", err.Error())
	}
	r, err := db.Query("SELECT * FROM foo")
	if err != nil {
		t.Fatalf("failed to query empty table: %s", err.Error())
	}
	if exp, got := `[{"id":"1","name":"fiona"}]`, asJson(r); exp != got {
		t.Fatalf("unexpected results for query, expected %s, got %s", exp, got)
	}

	if err := db.Execute(`INSERT INTO foo(name) VALUES("aoife")`); err != nil {
		t.Fatalf("failed to insert record: %s", err.Error())
	}
	r, err = db.Query("SELECT * FROM foo")
	if err != nil {
		t.Fatalf("failed to query table: %s", err.Error())
	}
	if exp, got := `[{"id":"1","name":"fiona"},{"id":"2","name":"aoife"}]`, asJson(r); exp != got {
		t.Fatalf("unexpected results for query, expected %s, got %s", exp, got)
	}

	if err := db.Execute("UPDATE foo SET Name='Who knows?' WHERE Id=1"); err != nil {
		t.Fatalf("failed to update record: %s", err.Error())
	}
	r, err = db.Query("SELECT * FROM foo")
	if err != nil {
		t.Fatalf("failed to query table: %s", err.Error())
	}
	if exp, got := `[{"id":"1","name":"Who knows?"},{"id":"2","name":"aoife"}]`, asJson(r); exp != got {
		t.Fatalf("unexpected results for query, expected %s, got %s", exp, got)
	}

	if err := db.Execute("DELETE FROM foo WHERE Id=2"); err != nil {
		t.Fatalf("failed to delete record: %s", err.Error())
	}
	r, err = db.Query("SELECT * FROM foo")
	if err != nil {
		t.Fatalf("failed to query table: %s", err.Error())
	}
	if exp, got := `[{"id":"1","name":"Who knows?"}]`, asJson(r); exp != got {
		t.Fatalf("unexpected results for query, expected %s, got %s", exp, got)
	}
}

func Test_FailingSimpleStatements(t *testing.T) {
	db, path := mustCreateDatabase()
	defer db.Close()
	defer os.Remove(path)

	err := db.Execute(`INSERT INTO foo(name) VALUES("fiona")`)
	if err == nil {
		t.Fatal("inserted record into empty table OK")
	}
	if err.Error() != "no such table: foo" {
		t.Fatal("unexpected error returned")
	}

	if err = db.Execute("create table foo (id integer not null primary key, name text)"); err != nil {
		t.Fatalf("failed to create table: %s", err.Error())
	}
	if err = db.Execute("create table foo (id integer not null primary key, name text)"); err == nil {
		t.Fatal("duplicate table created OK")
	}
	if err.Error() != "table foo already exists" {
		t.Fatalf("unexpected error returned: %s", err.Error())
	}

	if err = db.Execute(`INSERT INTO foo(id, name) VALUES(11, "fiona")`); err != nil {
		t.Fatalf("failed to insert record: %s", err.Error())
	}
	if err = db.Execute(`INSERT INTO foo(id, name) VALUES(11, "fiona")`); err == nil {
		t.Fatal("duplicated record inserted OK")
	}
	if err.Error() != "UNIQUE constraint failed: foo.id" {
		t.Fatal("unexpected error returned")
	}

	if err = db.Execute("SELECT * FROM bar"); err == nil {
		t.Fatal("no error when querying non-existant table")
	}
	if err.Error() != "no such table: bar" {
		t.Fatal("unexpected error returned")
	}

	if err = db.Execute("utter nonsense"); err == nil {
		t.Fatal("no error when issuing nonsense query")
	}
	if err.Error() != `near "utter": syntax error` {
		t.Fatal("unexpected error returned")
	}
}

func Test_SimpleTransactions(t *testing.T) {
	db, path := mustCreateDatabase()
	defer db.Close()
	defer os.Remove(path)

	if err := db.Execute("create table foo (id integer not null primary key, name text)"); err != nil {
		t.Fatalf("failed to create table: %s", err.Error())
	}

	if err := db.StartTransaction(); err != nil {
		t.Fatalf("failed to start transaction: %s", err.Error())
	}
	for i := 0; i < 10; i++ {
		_ = db.Execute(`INSERT INTO foo(name) VALUES("philip")`)
	}
	if err := db.CommitTransaction(); err != nil {
		t.Fatalf("failed to commit transaction: %s", err.Error())
	}

	r, err := db.Query("SELECT name FROM foo")
	if err != nil {
		t.Fatalf("failed to query after commited transaction: %s", err.Error())
	}
	if len(r) != 10 {
		t.Fatalf("incorrect number of results returned: %d", len(r))
	}

	if err := db.StartTransaction(); err != nil {
		t.Fatalf("failed to start transaction: %s", err.Error())
	}
	for i := 0; i < 10; i++ {
		_ = db.Execute(`INSERT INTO foo(name) VALUES("philip")`)
	}
	if err := db.RollbackTransaction(); err != nil {
		t.Fatalf("failed to rollback transaction: %s", err.Error())
	}

	r, err = db.Query("SELECT name FROM foo")
	if err != nil {
		t.Fatalf("failed to query after commited transaction: %s", err.Error())
	}
	if len(r) != 10 {
		t.Fatalf("incorrect number of results returned: %d", len(r))
	}
}

func Test_TransactionsConstraintViolation(t *testing.T) {
	db, path := mustCreateDatabase()
	defer db.Close()
	defer os.Remove(path)
	var err error

	if err = db.Execute("create table foo (id integer not null primary key, name text)"); err != nil {
		t.Fatalf("failed to create table: %s", err.Error())
	}

	if err = db.StartTransaction(); err != nil {
		t.Fatalf("failed to start transaction: %s", err.Error())
	}
	if err = db.Execute(`INSERT INTO foo(id, name) VALUES(11, "fiona")`); err != nil {
		t.Fatalf("failed to insert record: %s", err.Error())
	}
	if err = db.Execute(`INSERT INTO foo(id, name) VALUES(11, "fiona")`); err == nil {
		t.Fatal("duplicated record inserted OK")
	}
	if err.Error() != "UNIQUE constraint failed: foo.id" {
		t.Fatal("unexpected error returned")
	}
	if err := db.RollbackTransaction(); err != nil {
		t.Fatalf("failed to rollback transaction: %s", err.Error())
	}
	r, err := db.Query("SELECT name FROM foo")
	if err != nil {
		t.Fatalf("failed to query after commited transaction: %s", err.Error())
	}
	if len(r) != 0 {
		t.Fatalf("incorrect number of results returned: %d", len(r))
	}
}

func Test_TransactionsHardFail(t *testing.T) {
	db, path := mustCreateDatabase()
	defer db.Close()
	defer os.Remove(path)
	var err error

	if err = db.Execute("create table foo (id integer not null primary key, name text)"); err != nil {
		t.Fatalf("failed to create table: %s", err.Error())
	}
	if err = db.Execute(`INSERT INTO foo(id, name) VALUES(1, "fiona")`); err != nil {
		t.Fatalf("failed to insert record: %s", err.Error())
	}

	if err = db.StartTransaction(); err != nil {
		t.Fatalf("failed to start transaction: %s", err.Error())
	}
	if err = db.Execute(`INSERT INTO foo(id, name) VALUES(2, "fiona")`); err != nil {
		t.Fatalf("failed to insert record: %s", err.Error())
	}
	if err = db.Close(); err != nil {
		t.Fatalf("failed to close database: %s", err.Error())
	}

	db, err = Open(path)
	if err != nil {
		t.Fatalf("failed to re-open database: %s", err.Error())
	}
	r, err := db.Query("SELECT * FROM foo")
	if err != nil {
		t.Fatalf("failed to query after hard close: %s", err.Error())
	}
	if len(r) != 1 {
		t.Fatalf("incorrect number of results returned: %d", len(r))
	}
}

func mustCreateDatabase() (*DB, string) {
	var err error
	f, err := ioutil.TempFile("", "rqlilte-test-")
	if err != nil {
		panic("failed to create temp file")
	}
	f.Close()

	db, err := Open(f.Name())
	if err != nil {
		panic("failed to open database")
	}

	return db, f.Name()
}

func asJson(v interface{}) string {
	b, err := json.Marshal(v)
	if err != nil {
		panic("failed to JSON marshal value")
	}
	return string(b)
}
<|endoftext|>


<commit_before>package gridt

import (
	"bytes"
	"strings"
)

// Dimensions contains the dimensions of the grid and the possibility to format it.
type Dimensions struct {
	ws []uint
	l  uint
	g  Grid
}

// Widths represents the widths of each column in the grid.
func (d Dimensions) Widths() []uint {
	return d.ws
}

// Lines represents the quantity of lines the grid has.
func (d Dimensions) Lines() uint {
	return d.l
}

// Columns represents the quantity of columns the grid has.
func (d Dimensions) Columns() uint {
	return uint(len(d.ws))
}

// String formats the grid into a string.
func (d Dimensions) String() string {
	var buffer bytes.Buffer
	for i, cell := range d.g.v {
		switch d.g.d {
		case TopToBottom:
			i /= int(d.l)
		case LeftToRight:
			i %= len(d.ws)
		}
		buffer.WriteString(cell)
		buffer.WriteString(strings.Repeat(" ", int(d.ws[i])-len(cell)))
		buffer.WriteString(d.g.sep)
		if len(d.ws) == i+1 {
			buffer.WriteString("\n")
		}
	}
	return buffer.String()
}
<commit_msg>Fix Grid formatting.<commit_after>package gridt

import (
	"bytes"
	"strings"
)

// Dimensions contains the dimensions of the grid and the possibility to format it.
type Dimensions struct {
	ws []uint
	l  uint
	g  Grid
}

// Widths represents the widths of each column in the grid.
func (d Dimensions) Widths() []uint {
	return d.ws
}

// Lines represents the quantity of lines the grid has.
func (d Dimensions) Lines() uint {
	return d.l
}

// Columns represents the quantity of columns the grid has.
func (d Dimensions) Columns() uint {
	return uint(len(d.ws))
}

// String formats the grid into a string.
func (d Dimensions) String() string {
	var buf bytes.Buffer
	switch d.g.d {
	case TopToBottom:
		last, counter := 0, -1
		linesBuf := make([]bytes.Buffer, d.l)
		for i, cell := range d.g.v {
			i /= int(d.l)
			if i != last {
				last = i
				counter = 0
			} else {
				counter++
			}
			linesBuf[counter].WriteString(cell)
			linesBuf[counter].WriteString(strings.Repeat(" ", int(d.ws[i])-len(cell)))
			if len(d.ws) != i+1 {
				linesBuf[counter].WriteString(d.g.sep)
			}
		}
		if counter != int(d.l) {
			for counter++; counter < int(d.l); counter++ {
				linesBuf[counter].WriteString(strings.Repeat(" ", int(d.ws[len(d.ws)-1])))
			}
		}
		for i, b := range linesBuf {
			buf.WriteString(b.String())
			if i+1 != len(linesBuf) {
				buf.WriteRune('\n')
			}
		}
	case LeftToRight:
		var i int
		var cell string
		for i, cell = range d.g.v {
			col := i % len(d.ws)
			buf.WriteString(cell)
			buf.WriteString(strings.Repeat(" ", int(d.ws[col])-len(cell)))
			if i+1 != len(d.g.v) {
				if len(d.ws) == col+1 {
					buf.WriteRune('\n')
				} else {
					buf.WriteString(d.g.sep)
				}
			}
		}
		if rest := i % len(d.ws); rest != 0 {
			for rest++; rest < len(d.ws); rest++ {
				buf.WriteString(d.g.sep)
				buf.WriteString(strings.Repeat(" ", int(d.ws[rest])))
			}
		}
	}
	return buf.String()
}
<|endoftext|>


<commit_before>package stripe

import (
	"socialapi/workers/payment/paymenterrors"
	"socialapi/workers/payment/paymentmodels"

	stripe "github.com/stripe/stripe-go"
	stripeInvoice "github.com/stripe/stripe-go/invoice"
	stripeSub "github.com/stripe/stripe-go/sub"
)

func Subscribe(token, accId, email, planTitle, planInterval string) error {
	plan, err := FindPlanByTitleAndInterval(planTitle, planInterval)
	if err != nil {
		return err
	}

	customer, err := FindCustomerByOldId(accId)
	if err != nil && err != paymenterrors.ErrCustomerNotFound {
		return err
	}

	if customer == nil {
		if IsEmpty(token) {
			return paymenterrors.ErrTokenIsEmpty
		}

		customer, err = CreateCustomer(token, accId, email)
		if err != nil {
			return err
		}
	}

	resp, err := GetCreditCard(customer.OldId)
	if err != nil {
		return err
	}

	if IsEmpty(resp.LastFour) {
		if IsEmpty(token) {
			return paymenterrors.ErrTokenIsEmpty
		}

		err := UpdateCreditCard(customer.OldId, token)
		if err != nil {
			return err
		}
	}

	subscriptions, err := FindCustomerActiveSubscriptions(customer)
	if err != nil {
		return err
	}

	if IsNoSubscriptions(subscriptions) {
		_, err = CreateSubscription(customer, plan)
		return err
	}

	if IsOverSubscribed(subscriptions) {
		return paymenterrors.ErrCustomerHasTooManySubscriptions
	}

	var currentSubscription = subscriptions[0]

	if IsSubscribedToPlan(currentSubscription, plan) {
		return paymenterrors.ErrCustomerAlreadySubscribedToPlan
	}

	if !IsFreePlan(plan) {
		err = UpdateSubscriptionForCustomer(customer, subscriptions, plan)
		return err
	}

	err = DowngradeToFreePlan(customer, &currentSubscription)
	if err != nil {
		return err
	}

	return nil
}

func DowngradeToFreePlan(customer *paymentmodel.Customer, currentSubscription *paymentmodel.Subscription) error {
	err := CancelSubscription(customer, currentSubscription)
	if err != nil {
		return err
	}

	err = RemoveCreditCard(customer)
	if err != nil {
		return err
	}

	return nil
}

func UpdateSubscriptionForCustomer(customer *paymentmodel.Customer, subscriptions []paymentmodel.Subscription, plan *paymentmodel.Plan) error {
	subParams := &stripe.SubParams{
		Customer: customer.ProviderCustomerId,
		Plan:     plan.ProviderPlanId,
	}

	if IsNoSubscriptions(subscriptions) {
		return paymenterrors.ErrCustomerNotSubscribedToAnyPlans
	}

	currentSubscription := subscriptions[0]
	currentSubscriptionId := currentSubscription.ProviderSubscriptionId

	_, err := stripeSub.Update(currentSubscriptionId, subParams)
	if err != nil {
		return handleStripeError(err)
	}

	invoiceParams := &stripe.InvoiceParams{
		Customer: customer.ProviderCustomerId,
	}

	_, err = stripeInvoice.New(invoiceParams)
	if err != nil {
		stripeErr := handleStripeError(err)

		// customer probably has a coupon and therefore doesn't need to pay
		if paymenterrors.ErrNothingToInvoiceFn(stripeErr) {
			return nil
		}

		return stripeErr
	}

	err = currentSubscription.UpdatePlan(plan.Id, plan.AmountInCents)
	if err != nil {
		return err
	}

	return err
}
<commit_msg>payment: fix error in invoice error logic<commit_after>package stripe

import (
	"socialapi/workers/payment/paymenterrors"
	"socialapi/workers/payment/paymentmodels"

	stripe "github.com/stripe/stripe-go"
	stripeInvoice "github.com/stripe/stripe-go/invoice"
	stripeSub "github.com/stripe/stripe-go/sub"
)

func Subscribe(token, accId, email, planTitle, planInterval string) error {
	plan, err := FindPlanByTitleAndInterval(planTitle, planInterval)
	if err != nil {
		return err
	}

	customer, err := FindCustomerByOldId(accId)
	if err != nil && err != paymenterrors.ErrCustomerNotFound {
		return err
	}

	if customer == nil {
		if IsEmpty(token) {
			return paymenterrors.ErrTokenIsEmpty
		}

		customer, err = CreateCustomer(token, accId, email)
		if err != nil {
			return err
		}
	}

	resp, err := GetCreditCard(customer.OldId)
	if err != nil {
		return err
	}

	if IsEmpty(resp.LastFour) {
		if IsEmpty(token) {
			return paymenterrors.ErrTokenIsEmpty
		}

		err := UpdateCreditCard(customer.OldId, token)
		if err != nil {
			return err
		}
	}

	subscriptions, err := FindCustomerActiveSubscriptions(customer)
	if err != nil {
		return err
	}

	if IsNoSubscriptions(subscriptions) {
		_, err = CreateSubscription(customer, plan)
		return err
	}

	if IsOverSubscribed(subscriptions) {
		return paymenterrors.ErrCustomerHasTooManySubscriptions
	}

	var currentSubscription = subscriptions[0]

	if IsSubscribedToPlan(currentSubscription, plan) {
		return paymenterrors.ErrCustomerAlreadySubscribedToPlan
	}

	if !IsFreePlan(plan) {
		err = UpdateSubscriptionForCustomer(customer, subscriptions, plan)
		return err
	}

	err = DowngradeToFreePlan(customer, &currentSubscription)
	if err != nil {
		return err
	}

	return nil
}

func DowngradeToFreePlan(customer *paymentmodel.Customer, currentSubscription *paymentmodel.Subscription) error {
	err := CancelSubscription(customer, currentSubscription)
	if err != nil {
		return err
	}

	err = RemoveCreditCard(customer)
	if err != nil {
		return err
	}

	return nil
}

func UpdateSubscriptionForCustomer(customer *paymentmodel.Customer, subscriptions []paymentmodel.Subscription, plan *paymentmodel.Plan) error {
	subParams := &stripe.SubParams{
		Customer: customer.ProviderCustomerId,
		Plan:     plan.ProviderPlanId,
	}

	if IsNoSubscriptions(subscriptions) {
		return paymenterrors.ErrCustomerNotSubscribedToAnyPlans
	}

	currentSubscription := subscriptions[0]
	currentSubscriptionId := currentSubscription.ProviderSubscriptionId

	_, err := stripeSub.Update(currentSubscriptionId, subParams)
	if err != nil {
		return handleStripeError(err)
	}

	invoiceParams := &stripe.InvoiceParams{
		Customer: customer.ProviderCustomerId,
	}

	_, err = stripeInvoice.New(invoiceParams)
	if err != nil {
		stripeErr := handleStripeError(err)

		// customer probably has a coupon or credit in account and therefore
		// doesn't need to pay
		if !paymenterrors.ErrNothingToInvoiceFn(stripeErr) {
			return stripeErr
		}
	}

	err = currentSubscription.UpdatePlan(plan.Id, plan.AmountInCents)
	if err != nil {
		return err
	}

	return err
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Vitess Authors.

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 endtoend

import (
	"sync"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"

	"github.com/stretchr/testify/require"

	"vitess.io/vitess/go/sqltypes"
	querypb "vitess.io/vitess/go/vt/proto/query"
	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
	"vitess.io/vitess/go/vt/vterrors"
	"vitess.io/vitess/go/vt/vttablet/endtoend/framework"
	"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"
)

// compareIntDiff returns an error if end[tag] != start[tag]+diff.
func compareIntDiff(t *testing.T, end map[string]interface{}, tag string, start map[string]interface{}, diff int) {
	t.Helper()
	verifyIntValue(t, end, tag, framework.FetchInt(start, tag)+diff)
}

// verifyIntValue returns an error if values[tag] != want.
func verifyIntValue(t *testing.T, values map[string]interface{}, tag string, want int) {
	t.Helper()
	require.Equal(t, want, framework.FetchInt(values, tag), tag)
}

func TestPoolSize(t *testing.T) {
	defer framework.Server.SetPoolSize(framework.Server.PoolSize())
	framework.Server.SetPoolSize(1)

	vstart := framework.DebugVars()
	verifyIntValue(t, vstart, "ConnPoolCapacity", 1)

	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg.Done()
	}()
	// The queries have to be different so consolidator doesn't kick in.
	go func() {
		framework.NewClient().Execute("select sleep(0.49) from dual", nil)
		wg.Done()
	}()
	wg.Wait()

	// Parallel plan building can cause multiple conn pool waits.
	// Check that the wait count was at least incremented once so
	// we know it's working.
	tag := "ConnPoolWaitCount"
	got := framework.FetchInt(framework.DebugVars(), tag)
	want := framework.FetchInt(vstart, tag)
	assert.LessOrEqual(t, want, got)
}

func TestDisableConsolidator(t *testing.T) {
	totalConsolidationsTag := "Waits/Histograms/Consolidations/Count"
	initial := framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg.Done()
	}()
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg.Done()
	}()
	wg.Wait()
	afterOne := framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	assert.Equal(t, initial+1, afterOne, "expected one consolidation")

	framework.Server.SetConsolidatorMode(tabletenv.Disable)
	defer framework.Server.SetConsolidatorMode(tabletenv.Enable)
	var wg2 sync.WaitGroup
	wg2.Add(2)
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg2.Done()
	}()
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg2.Done()
	}()
	wg2.Wait()
	noNewConsolidations := framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	assert.Equal(t, afterOne, noNewConsolidations, "expected no new consolidations")
}

func TestConsolidatorReplicasOnly(t *testing.T) {
	totalConsolidationsTag := "Waits/Histograms/Consolidations/Count"
	initial := framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg.Done()
	}()
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg.Done()
	}()
	wg.Wait()
	afterOne := framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	assert.Equal(t, initial+1, afterOne, "expected one consolidation")

	framework.Server.SetConsolidatorMode(tabletenv.NotOnMaster)
	defer framework.Server.SetConsolidatorMode(tabletenv.Enable)

	// master should not do query consolidation
	var wg2 sync.WaitGroup
	wg2.Add(2)
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg2.Done()
	}()
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg2.Done()
	}()
	wg2.Wait()
	noNewConsolidations := framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	assert.Equal(t, afterOne, noNewConsolidations, "expected no new consolidations")

	// become a replica, where query consolidation should happen
	client := framework.NewClientWithTabletType(topodatapb.TabletType_REPLICA)

	err := client.SetServingType(topodatapb.TabletType_REPLICA)
	require.NoError(t, err)
	defer func() {
		err = client.SetServingType(topodatapb.TabletType_MASTER)
		require.NoError(t, err)
	}()

	initial = framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	var wg3 sync.WaitGroup
	wg3.Add(2)
	go func() {
		client.Execute("select sleep(0.5) from dual", nil)
		wg3.Done()
	}()
	go func() {
		client.Execute("select sleep(0.5) from dual", nil)
		wg3.Done()
	}()
	wg3.Wait()
	afterOne = framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	assert.Equal(t, initial+1, afterOne, "expected another consolidation")
}

func TestQueryPlanCache(t *testing.T) {
	//sleep to avoid race between SchemaChanged event clearing out the plans cache which breaks this test
	time.Sleep(1 * time.Second)

	defer framework.Server.SetQueryPlanCacheCap(framework.Server.QueryPlanCacheCap())
	framework.Server.SetQueryPlanCacheCap(1)

	bindVars := map[string]*querypb.BindVariable{
		"ival1": sqltypes.Int64BindVariable(1),
		"ival2": sqltypes.Int64BindVariable(1),
	}
	client := framework.NewClient()
	_, _ = client.Execute("select * from vitess_test where intval=:ival1", bindVars)
	_, _ = client.Execute("select * from vitess_test where intval=:ival2", bindVars)
	vend := framework.DebugVars()
	verifyIntValue(t, vend, "QueryCacheLength", 1)
	verifyIntValue(t, vend, "QueryCacheSize", 1)
	verifyIntValue(t, vend, "QueryCacheCapacity", 1)

	framework.Server.SetQueryPlanCacheCap(10)
	_, _ = client.Execute("select * from vitess_test where intval=:ival1", bindVars)
	vend = framework.DebugVars()
	verifyIntValue(t, vend, "QueryCacheLength", 2)
	verifyIntValue(t, vend, "QueryCacheSize", 2)
	_, _ = client.Execute("select * from vitess_test where intval=1", bindVars)
	vend = framework.DebugVars()
	verifyIntValue(t, vend, "QueryCacheLength", 3)
	verifyIntValue(t, vend, "QueryCacheSize", 3)
}

func TestMaxResultSize(t *testing.T) {
	defer framework.Server.SetMaxResultSize(framework.Server.MaxResultSize())
	framework.Server.SetMaxResultSize(2)

	client := framework.NewClient()
	query := "select * from vitess_test"
	_, err := client.Execute(query, nil)
	assert.Error(t, err)
	want := "Row count exceeded"
	assert.Contains(t, err.Error(), want, "Error: %v, must start with %s", err, want)
	verifyIntValue(t, framework.DebugVars(), "MaxResultSize", 2)
	framework.Server.SetMaxResultSize(10)
	_, err = client.Execute(query, nil)
	require.NoError(t, err)
}

func TestWarnResultSize(t *testing.T) {
	defer framework.Server.SetWarnResultSize(framework.Server.WarnResultSize())
	framework.Server.SetWarnResultSize(2)
	client := framework.NewClient()

	originalWarningsResultsExceededCount := framework.FetchInt(framework.DebugVars(), "Warnings/ResultsExceeded")
	query := "select * from vitess_test"
	_, _ = client.Execute(query, nil)
	newWarningsResultsExceededCount := framework.FetchInt(framework.DebugVars(), "Warnings/ResultsExceeded")
	exceededCountDiff := newWarningsResultsExceededCount - originalWarningsResultsExceededCount
	assert.Equal(t, 1, exceededCountDiff, "Warnings.ResultsExceeded counter should have increased by 1")

	verifyIntValue(t, framework.DebugVars(), "WarnResultSize", 2)
	framework.Server.SetWarnResultSize(10)
	_, _ = client.Execute(query, nil)
	newerWarningsResultsExceededCount := framework.FetchInt(framework.DebugVars(), "Warnings/ResultsExceeded")
	exceededCountDiff = newerWarningsResultsExceededCount - newWarningsResultsExceededCount
	assert.Equal(t, 0, exceededCountDiff, "Warnings.ResultsExceeded counter should not have increased")
}

func TestQueryTimeout(t *testing.T) {
	vstart := framework.DebugVars()
	defer framework.Server.QueryTimeout.Set(framework.Server.QueryTimeout.Get())
	framework.Server.QueryTimeout.Set(100 * time.Millisecond)

	client := framework.NewClient()
	err := client.Begin(false)
	require.NoError(t, err)
	_, err = client.Execute("select sleep(1) from vitess_test", nil)
	assert.Equal(t, vtrpcpb.Code_CANCELED, vterrors.Code(err))
	_, err = client.Execute("select 1 from dual", nil)
	assert.Equal(t, vtrpcpb.Code_ABORTED, vterrors.Code(err))
	vend := framework.DebugVars()
	verifyIntValue(t, vend, "QueryTimeout", int(100*time.Millisecond))
	compareIntDiff(t, vend, "Kills/Queries", vstart, 1)
}
<commit_msg>vttablet: debug/env test PoolSize<commit_after>/*
Copyright 2019 The Vitess Authors.

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 endtoend

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

	"github.com/stretchr/testify/assert"

	"github.com/stretchr/testify/require"

	"vitess.io/vitess/go/sqltypes"
	querypb "vitess.io/vitess/go/vt/proto/query"
	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
	"vitess.io/vitess/go/vt/vterrors"
	"vitess.io/vitess/go/vt/vttablet/endtoend/framework"
	"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"
)

func TestPoolSize(t *testing.T) {
	revert := changeVar(t, "PoolSize", "1")
	defer revert()

	vstart := framework.DebugVars()
	verifyIntValue(t, vstart, "ConnPoolCapacity", 1)

	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg.Done()
	}()
	// The queries have to be different so consolidator doesn't kick in.
	go func() {
		framework.NewClient().Execute("select sleep(0.49) from dual", nil)
		wg.Done()
	}()
	wg.Wait()

	// Parallel plan building can cause multiple conn pool waits.
	// Check that the wait count was at least incremented once so
	// we know it's working.
	tag := "ConnPoolWaitCount"
	got := framework.FetchInt(framework.DebugVars(), tag)
	want := framework.FetchInt(vstart, tag)
	assert.LessOrEqual(t, want, got)
}

func TestDisableConsolidator(t *testing.T) {
	totalConsolidationsTag := "Waits/Histograms/Consolidations/Count"
	initial := framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg.Done()
	}()
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg.Done()
	}()
	wg.Wait()
	afterOne := framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	assert.Equal(t, initial+1, afterOne, "expected one consolidation")

	framework.Server.SetConsolidatorMode(tabletenv.Disable)
	defer framework.Server.SetConsolidatorMode(tabletenv.Enable)
	var wg2 sync.WaitGroup
	wg2.Add(2)
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg2.Done()
	}()
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg2.Done()
	}()
	wg2.Wait()
	noNewConsolidations := framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	assert.Equal(t, afterOne, noNewConsolidations, "expected no new consolidations")
}

func TestConsolidatorReplicasOnly(t *testing.T) {
	totalConsolidationsTag := "Waits/Histograms/Consolidations/Count"
	initial := framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg.Done()
	}()
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg.Done()
	}()
	wg.Wait()
	afterOne := framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	assert.Equal(t, initial+1, afterOne, "expected one consolidation")

	framework.Server.SetConsolidatorMode(tabletenv.NotOnMaster)
	defer framework.Server.SetConsolidatorMode(tabletenv.Enable)

	// master should not do query consolidation
	var wg2 sync.WaitGroup
	wg2.Add(2)
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg2.Done()
	}()
	go func() {
		framework.NewClient().Execute("select sleep(0.5) from dual", nil)
		wg2.Done()
	}()
	wg2.Wait()
	noNewConsolidations := framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	assert.Equal(t, afterOne, noNewConsolidations, "expected no new consolidations")

	// become a replica, where query consolidation should happen
	client := framework.NewClientWithTabletType(topodatapb.TabletType_REPLICA)

	err := client.SetServingType(topodatapb.TabletType_REPLICA)
	require.NoError(t, err)
	defer func() {
		err = client.SetServingType(topodatapb.TabletType_MASTER)
		require.NoError(t, err)
	}()

	initial = framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	var wg3 sync.WaitGroup
	wg3.Add(2)
	go func() {
		client.Execute("select sleep(0.5) from dual", nil)
		wg3.Done()
	}()
	go func() {
		client.Execute("select sleep(0.5) from dual", nil)
		wg3.Done()
	}()
	wg3.Wait()
	afterOne = framework.FetchInt(framework.DebugVars(), totalConsolidationsTag)
	assert.Equal(t, initial+1, afterOne, "expected another consolidation")
}

func TestQueryPlanCache(t *testing.T) {
	//sleep to avoid race between SchemaChanged event clearing out the plans cache which breaks this test
	time.Sleep(1 * time.Second)

	defer framework.Server.SetQueryPlanCacheCap(framework.Server.QueryPlanCacheCap())
	framework.Server.SetQueryPlanCacheCap(1)

	bindVars := map[string]*querypb.BindVariable{
		"ival1": sqltypes.Int64BindVariable(1),
		"ival2": sqltypes.Int64BindVariable(1),
	}
	client := framework.NewClient()
	_, _ = client.Execute("select * from vitess_test where intval=:ival1", bindVars)
	_, _ = client.Execute("select * from vitess_test where intval=:ival2", bindVars)
	vend := framework.DebugVars()
	verifyIntValue(t, vend, "QueryCacheLength", 1)
	verifyIntValue(t, vend, "QueryCacheSize", 1)
	verifyIntValue(t, vend, "QueryCacheCapacity", 1)

	framework.Server.SetQueryPlanCacheCap(10)
	_, _ = client.Execute("select * from vitess_test where intval=:ival1", bindVars)
	vend = framework.DebugVars()
	verifyIntValue(t, vend, "QueryCacheLength", 2)
	verifyIntValue(t, vend, "QueryCacheSize", 2)
	_, _ = client.Execute("select * from vitess_test where intval=1", bindVars)
	vend = framework.DebugVars()
	verifyIntValue(t, vend, "QueryCacheLength", 3)
	verifyIntValue(t, vend, "QueryCacheSize", 3)
}

func TestMaxResultSize(t *testing.T) {
	defer framework.Server.SetMaxResultSize(framework.Server.MaxResultSize())
	framework.Server.SetMaxResultSize(2)

	client := framework.NewClient()
	query := "select * from vitess_test"
	_, err := client.Execute(query, nil)
	assert.Error(t, err)
	want := "Row count exceeded"
	assert.Contains(t, err.Error(), want, "Error: %v, must start with %s", err, want)
	verifyIntValue(t, framework.DebugVars(), "MaxResultSize", 2)
	framework.Server.SetMaxResultSize(10)
	_, err = client.Execute(query, nil)
	require.NoError(t, err)
}

func TestWarnResultSize(t *testing.T) {
	defer framework.Server.SetWarnResultSize(framework.Server.WarnResultSize())
	framework.Server.SetWarnResultSize(2)
	client := framework.NewClient()

	originalWarningsResultsExceededCount := framework.FetchInt(framework.DebugVars(), "Warnings/ResultsExceeded")
	query := "select * from vitess_test"
	_, _ = client.Execute(query, nil)
	newWarningsResultsExceededCount := framework.FetchInt(framework.DebugVars(), "Warnings/ResultsExceeded")
	exceededCountDiff := newWarningsResultsExceededCount - originalWarningsResultsExceededCount
	assert.Equal(t, 1, exceededCountDiff, "Warnings.ResultsExceeded counter should have increased by 1")

	verifyIntValue(t, framework.DebugVars(), "WarnResultSize", 2)
	framework.Server.SetWarnResultSize(10)
	_, _ = client.Execute(query, nil)
	newerWarningsResultsExceededCount := framework.FetchInt(framework.DebugVars(), "Warnings/ResultsExceeded")
	exceededCountDiff = newerWarningsResultsExceededCount - newWarningsResultsExceededCount
	assert.Equal(t, 0, exceededCountDiff, "Warnings.ResultsExceeded counter should not have increased")
}

func TestQueryTimeout(t *testing.T) {
	vstart := framework.DebugVars()
	defer framework.Server.QueryTimeout.Set(framework.Server.QueryTimeout.Get())
	framework.Server.QueryTimeout.Set(100 * time.Millisecond)

	client := framework.NewClient()
	err := client.Begin(false)
	require.NoError(t, err)
	_, err = client.Execute("select sleep(1) from vitess_test", nil)
	assert.Equal(t, vtrpcpb.Code_CANCELED, vterrors.Code(err))
	_, err = client.Execute("select 1 from dual", nil)
	assert.Equal(t, vtrpcpb.Code_ABORTED, vterrors.Code(err))
	vend := framework.DebugVars()
	verifyIntValue(t, vend, "QueryTimeout", int(100*time.Millisecond))
	compareIntDiff(t, vend, "Kills/Queries", vstart, 1)
}

func changeVar(t *testing.T, name, value string) (revert func()) {
	t.Helper()

	vals := framework.FetchJSON("/debug/env?format=json")
	initial, ok := vals[name]
	if !ok {
		t.Fatalf("%s not found in: %v", name, vals)
	}
	vals = framework.FetchJSON(fmt.Sprintf("/debug/env?format=json&varname=%s&value=%s", name, value))
	verifyMapValue(t, vals, name, value)
	return func() {
		vals := framework.FetchJSON(fmt.Sprintf("/debug/env?format=json&varname=%s&value=%s", name, initial))
		verifyMapValue(t, vals, name, initial)
	}
}

func verifyMapValue(t *testing.T, values map[string]interface{}, tag string, want interface{}) {
	t.Helper()
	val, ok := values[tag]
	if !ok {
		t.Fatalf("%s not found in: %v", tag, values)
	}
	assert.Equal(t, want, val)
}

func compareIntDiff(t *testing.T, end map[string]interface{}, tag string, start map[string]interface{}, diff int) {
	t.Helper()
	verifyIntValue(t, end, tag, framework.FetchInt(start, tag)+diff)
}

func verifyIntValue(t *testing.T, values map[string]interface{}, tag string, want int) {
	t.Helper()
	require.Equal(t, want, framework.FetchInt(values, tag), tag)
}
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either Version 3 of the License, or
// (at your option) any later Version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package version

import (
	"fmt"
	"sort"
	"strconv"
	"strings"
)

// CurrentGaugeVersion represents the current version of Gauge
var CurrentGaugeVersion = &Version{1, 0, 1}

// BuildMetadata represents build information of current release (e.g, nightly build information)
var BuildMetadata = ""
var CommitHash = ""

type Version struct {
	Major int
	Minor int
	Patch int
}

type VersionSupport struct {
	Minimum string
	Maximum string
}

func ParseVersion(versionText string) (*Version, error) {
	splits := strings.Split(versionText, ".")
	if len(splits) != 3 {
		return nil, fmt.Errorf("Incorrect Version format. Version should be in the form 1.5.7")
	}
	Major, err := strconv.Atoi(splits[0])
	if err != nil {
		return nil, VersionError("major", splits[0], err)
	}
	Minor, err := strconv.Atoi(splits[1])
	if err != nil {
		return nil, VersionError("minor", splits[1], err)
	}
	Patch, err := strconv.Atoi(splits[2])
	if err != nil {
		return nil, VersionError("patch", splits[2], err)
	}

	return &Version{Major, Minor, Patch}, nil
}

func VersionError(level, text string, err error) error {
	return fmt.Errorf("Error parsing %s Version %s to integer. %s", level, text, err.Error())
}

func (Version *Version) IsBetween(lower *Version, greater *Version) bool {
	return Version.IsGreaterThanEqualTo(lower) && Version.IsLesserThanEqualTo(greater)
}

func (Version *Version) IsLesserThan(version1 *Version) bool {
	return CompareVersions(Version, version1, LesserThanFunc)
}

func (Version *Version) IsGreaterThan(version1 *Version) bool {
	return CompareVersions(Version, version1, GreaterThanFunc)
}

func (Version *Version) IsLesserThanEqualTo(version1 *Version) bool {
	return Version.IsLesserThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsGreaterThanEqualTo(version1 *Version) bool {
	return Version.IsGreaterThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsEqualTo(version1 *Version) bool {
	return IsEqual(Version.Major, version1.Major) && IsEqual(Version.Minor, version1.Minor) && IsEqual(Version.Patch, version1.Patch)
}

func CompareVersions(first *Version, second *Version, compareFunc func(int, int) bool) bool {
	if compareFunc(first.Major, second.Major) {
		return true
	} else if IsEqual(first.Major, second.Major) {
		if compareFunc(first.Minor, second.Minor) {
			return true
		} else if IsEqual(first.Minor, second.Minor) {
			if compareFunc(first.Patch, second.Patch) {
				return true
			}
			return false
		}
	}
	return false
}

func LesserThanFunc(first, second int) bool {
	return first < second
}

func GreaterThanFunc(first, second int) bool {
	return first > second
}

func IsEqual(first, second int) bool {
	return first == second
}

func (Version *Version) String() string {
	return fmt.Sprintf("%d.%d.%d", Version.Major, Version.Minor, Version.Patch)
}

// FullVersion returns the CurrentGaugeVersion including build metadata.
func FullVersion() string {
	var metadata string
	if BuildMetadata != "" {
		metadata = fmt.Sprintf(".%s", BuildMetadata)
	}
	return fmt.Sprintf("%s%s", CurrentGaugeVersion.String(), metadata)
}

func GetCommitHash() string {
	var commitHash string
	if CommitHash != "" {
		commitHash = fmt.Sprintf("%s", CommitHash)
	}
	return fmt.Sprintf("%s", commitHash)
}

type byDecreasingVersion []*Version

func (a byDecreasingVersion) Len() int      { return len(a) }
func (a byDecreasingVersion) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byDecreasingVersion) Less(i, j int) bool {
	return a[i].IsGreaterThan(a[j])
}

func GetLatestVersion(versions []*Version) *Version {
	sort.Sort(byDecreasingVersion(versions))
	return versions[0]
}

func CheckCompatibility(currentVersion *Version, versionSupport *VersionSupport) error {
	minSupportVersion, err := ParseVersion(versionSupport.Minimum)
	if err != nil {
		return fmt.Errorf("Invalid minimum support version %s. : %s. ", versionSupport.Minimum, err.Error())
	}
	if versionSupport.Maximum != "" {
		maxSupportVersion, err := ParseVersion(versionSupport.Maximum)
		if err != nil {
			return fmt.Errorf("Invalid maximum support version %s. : %s. ", versionSupport.Maximum, err.Error())
		}
		if currentVersion.IsBetween(minSupportVersion, maxSupportVersion) {
			return nil
		}
		return fmt.Errorf("Version %s is not between %s and %s", currentVersion, minSupportVersion, maxSupportVersion)
	}

	if minSupportVersion.IsLesserThanEqualTo(currentVersion) {
		return nil
	}
	return fmt.Errorf("Incompatible version. Minimum support version %s is higher than current version %s", minSupportVersion, currentVersion)
}
<commit_msg>Bumping up version to 1.0.2<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either Version 3 of the License, or
// (at your option) any later Version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package version

import (
	"fmt"
	"sort"
	"strconv"
	"strings"
)

// CurrentGaugeVersion represents the current version of Gauge
var CurrentGaugeVersion = &Version{1, 0, 2}

// BuildMetadata represents build information of current release (e.g, nightly build information)
var BuildMetadata = ""
var CommitHash = ""

type Version struct {
	Major int
	Minor int
	Patch int
}

type VersionSupport struct {
	Minimum string
	Maximum string
}

func ParseVersion(versionText string) (*Version, error) {
	splits := strings.Split(versionText, ".")
	if len(splits) != 3 {
		return nil, fmt.Errorf("Incorrect Version format. Version should be in the form 1.5.7")
	}
	Major, err := strconv.Atoi(splits[0])
	if err != nil {
		return nil, VersionError("major", splits[0], err)
	}
	Minor, err := strconv.Atoi(splits[1])
	if err != nil {
		return nil, VersionError("minor", splits[1], err)
	}
	Patch, err := strconv.Atoi(splits[2])
	if err != nil {
		return nil, VersionError("patch", splits[2], err)
	}

	return &Version{Major, Minor, Patch}, nil
}

func VersionError(level, text string, err error) error {
	return fmt.Errorf("Error parsing %s Version %s to integer. %s", level, text, err.Error())
}

func (Version *Version) IsBetween(lower *Version, greater *Version) bool {
	return Version.IsGreaterThanEqualTo(lower) && Version.IsLesserThanEqualTo(greater)
}

func (Version *Version) IsLesserThan(version1 *Version) bool {
	return CompareVersions(Version, version1, LesserThanFunc)
}

func (Version *Version) IsGreaterThan(version1 *Version) bool {
	return CompareVersions(Version, version1, GreaterThanFunc)
}

func (Version *Version) IsLesserThanEqualTo(version1 *Version) bool {
	return Version.IsLesserThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsGreaterThanEqualTo(version1 *Version) bool {
	return Version.IsGreaterThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsEqualTo(version1 *Version) bool {
	return IsEqual(Version.Major, version1.Major) && IsEqual(Version.Minor, version1.Minor) && IsEqual(Version.Patch, version1.Patch)
}

func CompareVersions(first *Version, second *Version, compareFunc func(int, int) bool) bool {
	if compareFunc(first.Major, second.Major) {
		return true
	} else if IsEqual(first.Major, second.Major) {
		if compareFunc(first.Minor, second.Minor) {
			return true
		} else if IsEqual(first.Minor, second.Minor) {
			if compareFunc(first.Patch, second.Patch) {
				return true
			}
			return false
		}
	}
	return false
}

func LesserThanFunc(first, second int) bool {
	return first < second
}

func GreaterThanFunc(first, second int) bool {
	return first > second
}

func IsEqual(first, second int) bool {
	return first == second
}

func (Version *Version) String() string {
	return fmt.Sprintf("%d.%d.%d", Version.Major, Version.Minor, Version.Patch)
}

// FullVersion returns the CurrentGaugeVersion including build metadata.
func FullVersion() string {
	var metadata string
	if BuildMetadata != "" {
		metadata = fmt.Sprintf(".%s", BuildMetadata)
	}
	return fmt.Sprintf("%s%s", CurrentGaugeVersion.String(), metadata)
}

func GetCommitHash() string {
	var commitHash string
	if CommitHash != "" {
		commitHash = fmt.Sprintf("%s", CommitHash)
	}
	return fmt.Sprintf("%s", commitHash)
}

type byDecreasingVersion []*Version

func (a byDecreasingVersion) Len() int      { return len(a) }
func (a byDecreasingVersion) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byDecreasingVersion) Less(i, j int) bool {
	return a[i].IsGreaterThan(a[j])
}

func GetLatestVersion(versions []*Version) *Version {
	sort.Sort(byDecreasingVersion(versions))
	return versions[0]
}

func CheckCompatibility(currentVersion *Version, versionSupport *VersionSupport) error {
	minSupportVersion, err := ParseVersion(versionSupport.Minimum)
	if err != nil {
		return fmt.Errorf("Invalid minimum support version %s. : %s. ", versionSupport.Minimum, err.Error())
	}
	if versionSupport.Maximum != "" {
		maxSupportVersion, err := ParseVersion(versionSupport.Maximum)
		if err != nil {
			return fmt.Errorf("Invalid maximum support version %s. : %s. ", versionSupport.Maximum, err.Error())
		}
		if currentVersion.IsBetween(minSupportVersion, maxSupportVersion) {
			return nil
		}
		return fmt.Errorf("Version %s is not between %s and %s", currentVersion, minSupportVersion, maxSupportVersion)
	}

	if minSupportVersion.IsLesserThanEqualTo(currentVersion) {
		return nil
	}
	return fmt.Errorf("Incompatible version. Minimum support version %s is higher than current version %s", minSupportVersion, currentVersion)
}
<|endoftext|>


<commit_before><commit_msg>GetExportedName() try Conatins<commit_after><|endoftext|>


<commit_before>package ingress

import (
	"github.com/deckarep/golang-set"
	"github.com/docker/infrakit/pkg/controller/ingress/types"
	"github.com/docker/infrakit/pkg/spi/instance"
	"github.com/docker/infrakit/pkg/spi/loadbalancer"
	"github.com/docker/infrakit/pkg/template"
)

func (c *managed) syncRoutesL4() error {
	// to avoid multiple updates when ELBs have aliases need to agregate all of them by elb than just hostname
	// since different hostnames can point to the same ELB.
	targets := map[loadbalancer.L4][]loadbalancer.Route{}
	routesByVhost, err := c.routes()
	if err != nil {
		return err
	}

	// Need to process for each ELB known because it's possible that we'd have to remove all listeners in an ELB.
	// when there are no listeners to be created from all the services.
	elbs, err := c.l4s()
	if err != nil {
		return err
	}
	for vhost, elb := range elbs {
		// If a given elb does not have any vhosts and thus routes associated with it, it will have
		// an entry in the targets map, but with no routes.  Then the empty routes slice will be sent
		// to the elb to effectively remove the routes/ listeners.
		targets[elb] = append(targets[elb], routesByVhost[vhost]...)
	}

	log.Debug("expose l4", "targets", len(targets), "targets", targets, "meta", c.spec.Metadata)

	for elb, routes := range targets {
		log.Debug("Configuring", "name", elb.Name(), "routes", routes)
		err := configureL4(elb, routes, c.options)
		if err != nil {
			log.Warn("Cannot configure L4", "name", elb.Name(), "routes", routes, "meta", c.spec.Metadata)
			continue
		}
	}
	return nil
}

func (c *managed) getSourceKeySelectorTemplate() (*template.Template, error) {
	c.lock.Lock()
	defer c.lock.Unlock()

	if c.options.SourceKeySelector != "" {
		if c.sourceKeySelectorTemplate == nil {
			t, err := types.TemplateFrom([]byte(c.options.SourceKeySelector))
			if err != nil {
				return nil, err
			}
			c.sourceKeySelectorTemplate = t
		}
	}

	return c.sourceKeySelectorTemplate, nil
}

func (c *managed) syncBackends() error {
	groupsByVhost, err := c.groups()
	log.Debug("Groups by vhost", "groups", groupsByVhost, "meta", c.spec.Metadata, "fsm", c.stateMachine.ID())

	if err != nil {
		return err
	}

	loadbalancersByVhost, err := c.l4s()
	log.Debug("L4s by vhost", "l4s", loadbalancersByVhost)
	if err != nil {
		return err
	}

	// process by vhost and loadbalancer and keep a list of unresolved vhosts
	// for which we do not have any backends

	unresolved := []types.Vhost{}
	for vhost, l4 := range loadbalancersByVhost {

		groups, has := groupsByVhost[vhost]
		if !has {
			unresolved = append(unresolved, vhost)
			continue
		}

		// we have backends and loadbalancers
		registered := mapset.NewSet()
		if backends, err := l4.Backends(); err != nil {
			log.Warn("error getting backends", "err", err, "meta", c.spec.Metadata)
			continue
		} else {
			for _, b := range backends {
				registered.Add(b)
			}
		}
		log.Debug("Registered backends", "backends", registered, "meta", c.spec.Metadata)

		// all the nodes from all the groups and nodes
		nodes := mapset.NewSet()

		instanceIDs, _ := c.instanceIDs()
		for _, id := range instanceIDs[vhost] {
			nodes.Add(id)
		}

		log.Debug("backend groups", "groups", groups, "meta", c.spec.Metadata)
		for _, g := range groups {

			gid := g.ID()
			groupPlugin, err := c.groupPlugin(g)
			if err != nil {
				return err
			}

			desc, err := groupPlugin.DescribeGroup(gid)
			if err != nil {
				log.Warn("error describing group", "id", gid, "err", err, "meta", c.spec.Metadata)
				continue
			}

			log.Debug("found backends", "groupID", gid, "desc", desc, "vhost", vhost, "L4", l4.Name(), "meta", c.spec.Metadata)

			for _, inst := range desc.Instances {
				t, err := c.getSourceKeySelectorTemplate()
				if err != nil {
					return err
				}
				if t == nil {
					nodes.Add(inst.ID)
				} else {
					view, err := t.Render(inst)
					if err != nil {
						log.Error("cannot index entry", "instance.Description", inst, "err", err, "meta", c.spec.Metadata)
						continue
					}
					nodes.Add(instance.ID(view))
				}
			}
		}

		log.Debug("Group data", "nodes", nodes)

		// compute the difference between registered and nodes
		toRemove := []instance.ID{}
		for n := range registered.Difference(nodes).Iter() {
			toRemove = append(toRemove, n.(instance.ID))
		}

		// Use Info logging only when making deltas
		logFn := log.Debug
		if len(toRemove) > 0 {
			logFn = log.Info
		}
		logFn("De-register backends", "instances", toRemove, "vhost", vhost, "L4", l4.Name(), "meta", c.spec.Metadata)

		if result, err := l4.DeregisterBackends(toRemove); err != nil {
			log.Warn("error deregistering backends", "toRemove", toRemove, "err", err, "meta", c.spec.Metadata)
		} else {
			logFn("deregistered backends", "vhost", vhost, "result", result, "meta", c.spec.Metadata)
		}

		toAdd := []instance.ID{}
		for n := range nodes.Difference(registered).Iter() {
			toAdd = append(toAdd, n.(instance.ID))
		}

		logFn = log.Debug
		if len(toAdd) > 0 {
			logFn = log.Info
		}

		logFn("Register backends", "instances", toAdd, "vhost", vhost, "L4", l4.Name(), "meta", c.spec.Metadata)
		if result, err := l4.RegisterBackends(toAdd); err != nil {
			log.Warn("error registering backends", "toAdd", toAdd, "err", err, "meta", c.spec.Metadata)
		} else {
			logFn("registered backends", "vhost", vhost, "result", result, "meta", c.spec.Metadata)
		}

	}

	return nil

}

func (c *managed) syncHealthChecks() error {
	targets := map[loadbalancer.L4][]loadbalancer.HealthCheck{}
	healthChecksByVhost, err := c.healthChecks()
	if err != nil {
		return err
	}

	// Need to process for each ELB known because it's possible that we'd have to remove all listeners in an ELB.
	// when there are no listeners to be created from all the services.
	elbs, err := c.l4s()
	if err != nil {
		return err
	}
	for vhost, elb := range elbs {
		targets[elb] = append(targets[elb], healthChecksByVhost[vhost]...)
	}

	log.Debug("configure healthchecks", "targets", targets, "meta", c.spec.Metadata)

	for elb, healthChecks := range targets {
		log.Debug("Configuring healthcheck", "name", elb.Name(), "meta", c.spec.Metadata)
		for _, healthCheck := range healthChecks {
			if healthCheck.BackendPort > 0 {
				log.Info("HEALTH CHECK - Configuring the health check to ping", "port", healthCheck.BackendPort, "meta", c.spec.Metadata)
				_, err := elb.ConfigureHealthCheck(healthCheck)

				if err != nil {
					log.Warn("err config health check", "err", err)
					return err
				}
				log.Info("HEALTH CHECK CONFIGURED", "port", healthCheck.BackendPort, "config", healthCheck, "meta", c.spec.Metadata)
			}
		}
	}
	return nil
}
<commit_msg>Do not modify ingress membership when group describe fails (#800)<commit_after>package ingress

import (
	"github.com/deckarep/golang-set"
	"github.com/docker/infrakit/pkg/controller/ingress/types"
	"github.com/docker/infrakit/pkg/spi/instance"
	"github.com/docker/infrakit/pkg/spi/loadbalancer"
	"github.com/docker/infrakit/pkg/template"
)

func (c *managed) syncRoutesL4() error {
	// to avoid multiple updates when ELBs have aliases need to agregate all of them by elb than just hostname
	// since different hostnames can point to the same ELB.
	targets := map[loadbalancer.L4][]loadbalancer.Route{}
	routesByVhost, err := c.routes()
	if err != nil {
		return err
	}

	// Need to process for each ELB known because it's possible that we'd have to remove all listeners in an ELB.
	// when there are no listeners to be created from all the services.
	elbs, err := c.l4s()
	if err != nil {
		return err
	}
	for vhost, elb := range elbs {
		// If a given elb does not have any vhosts and thus routes associated with it, it will have
		// an entry in the targets map, but with no routes.  Then the empty routes slice will be sent
		// to the elb to effectively remove the routes/ listeners.
		targets[elb] = append(targets[elb], routesByVhost[vhost]...)
	}

	log.Debug("expose l4", "targets", len(targets), "targets", targets, "meta", c.spec.Metadata)

	for elb, routes := range targets {
		log.Debug("Configuring", "name", elb.Name(), "routes", routes)
		err := configureL4(elb, routes, c.options)
		if err != nil {
			log.Warn("Cannot configure L4", "name", elb.Name(), "routes", routes, "meta", c.spec.Metadata)
			continue
		}
	}
	return nil
}

func (c *managed) getSourceKeySelectorTemplate() (*template.Template, error) {
	c.lock.Lock()
	defer c.lock.Unlock()

	if c.options.SourceKeySelector != "" {
		if c.sourceKeySelectorTemplate == nil {
			t, err := types.TemplateFrom([]byte(c.options.SourceKeySelector))
			if err != nil {
				return nil, err
			}
			c.sourceKeySelectorTemplate = t
		}
	}

	return c.sourceKeySelectorTemplate, nil
}

func (c *managed) syncBackends() error {
	groupsByVhost, err := c.groups()
	log.Debug("Groups by vhost", "groups", groupsByVhost, "meta", c.spec.Metadata, "fsm", c.stateMachine.ID())

	if err != nil {
		return err
	}

	loadbalancersByVhost, err := c.l4s()
	log.Debug("L4s by vhost", "l4s", loadbalancersByVhost)
	if err != nil {
		return err
	}

	// process by vhost and loadbalancer and keep a list of unresolved vhosts
	// for which we do not have any backends

	unresolved := []types.Vhost{}
	for vhost, l4 := range loadbalancersByVhost {

		groups, has := groupsByVhost[vhost]
		if !has {
			unresolved = append(unresolved, vhost)
			continue
		}

		// we have backends and loadbalancers
		registered := mapset.NewSet()
		if backends, err := l4.Backends(); err != nil {
			log.Warn("error getting backends", "err", err, "meta", c.spec.Metadata)
			continue
		} else {
			for _, b := range backends {
				registered.Add(b)
			}
		}
		log.Debug("Registered backends", "backends", registered, "meta", c.spec.Metadata)

		// all the nodes from all the groups and nodes
		nodes := mapset.NewSet()

		instanceIDs, _ := c.instanceIDs()
		for _, id := range instanceIDs[vhost] {
			nodes.Add(id)
		}

		log.Debug("backend groups", "groups", groups, "meta", c.spec.Metadata)
		for _, g := range groups {

			gid := g.ID()
			groupPlugin, err := c.groupPlugin(g)
			if err != nil {
				return err
			}

			desc, err := groupPlugin.DescribeGroup(gid)
			if err != nil {
				// Failed to describe the group, since we do not know the members we do not want to proceed
				log.Warn("error describing group, not syncing backends", "id", gid, "err", err, "meta", c.spec.Metadata)
				return err
			}

			log.Debug("found backends", "groupID", gid, "desc", desc, "vhost", vhost, "L4", l4.Name(), "meta", c.spec.Metadata)

			for _, inst := range desc.Instances {
				t, err := c.getSourceKeySelectorTemplate()
				if err != nil {
					return err
				}
				if t == nil {
					nodes.Add(inst.ID)
				} else {
					view, err := t.Render(inst)
					if err != nil {
						log.Error("cannot index entry", "instance.Description", inst, "err", err, "meta", c.spec.Metadata)
						continue
					}
					nodes.Add(instance.ID(view))
				}
			}
		}

		log.Debug("Group data", "nodes", nodes)

		// compute the difference between registered and nodes
		toRemove := []instance.ID{}
		for n := range registered.Difference(nodes).Iter() {
			toRemove = append(toRemove, n.(instance.ID))
		}

		// Use Info logging only when making deltas
		logFn := log.Debug
		if len(toRemove) > 0 {
			logFn = log.Info
		}
		logFn("De-register backends", "instances", toRemove, "vhost", vhost, "L4", l4.Name(), "meta", c.spec.Metadata)

		if result, err := l4.DeregisterBackends(toRemove); err != nil {
			log.Warn("error deregistering backends", "toRemove", toRemove, "err", err, "meta", c.spec.Metadata)
		} else {
			logFn("deregistered backends", "vhost", vhost, "result", result, "meta", c.spec.Metadata)
		}

		toAdd := []instance.ID{}
		for n := range nodes.Difference(registered).Iter() {
			toAdd = append(toAdd, n.(instance.ID))
		}

		logFn = log.Debug
		if len(toAdd) > 0 {
			logFn = log.Info
		}

		logFn("Register backends", "instances", toAdd, "vhost", vhost, "L4", l4.Name(), "meta", c.spec.Metadata)
		if result, err := l4.RegisterBackends(toAdd); err != nil {
			log.Warn("error registering backends", "toAdd", toAdd, "err", err, "meta", c.spec.Metadata)
		} else {
			logFn("registered backends", "vhost", vhost, "result", result, "meta", c.spec.Metadata)
		}

	}

	return nil

}

func (c *managed) syncHealthChecks() error {
	targets := map[loadbalancer.L4][]loadbalancer.HealthCheck{}
	healthChecksByVhost, err := c.healthChecks()
	if err != nil {
		return err
	}

	// Need to process for each ELB known because it's possible that we'd have to remove all listeners in an ELB.
	// when there are no listeners to be created from all the services.
	elbs, err := c.l4s()
	if err != nil {
		return err
	}
	for vhost, elb := range elbs {
		targets[elb] = append(targets[elb], healthChecksByVhost[vhost]...)
	}

	log.Debug("configure healthchecks", "targets", targets, "meta", c.spec.Metadata)

	for elb, healthChecks := range targets {
		log.Debug("Configuring healthcheck", "name", elb.Name(), "meta", c.spec.Metadata)
		for _, healthCheck := range healthChecks {
			if healthCheck.BackendPort > 0 {
				log.Info("HEALTH CHECK - Configuring the health check to ping", "port", healthCheck.BackendPort, "meta", c.spec.Metadata)
				_, err := elb.ConfigureHealthCheck(healthCheck)

				if err != nil {
					log.Warn("err config health check", "err", err)
					return err
				}
				log.Info("HEALTH CHECK CONFIGURED", "port", healthCheck.BackendPort, "config", healthCheck, "meta", c.spec.Metadata)
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package bitsgo

import (
	"bytes"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/petergtz/bitsgo/logger"
	"github.com/pkg/errors"
)

type MetricsService interface {
	SendTimingMetric(name string, duration time.Duration)
}

type StateForbiddenError struct {
	error
}

func NewStateForbiddenError() *StateForbiddenError {
	return &StateForbiddenError{fmt.Errorf("StateForbiddenError")}
}

type Updater interface {
	NotifyProcessingUpload(guid string) error
	NotifyUploadSucceeded(guid string, sha1 string, sha2 string) error
	NotifyUploadFailed(guid string, e error) error
}

type NullUpdater struct{}

func (u *NullUpdater) NotifyProcessingUpload(guid string) error                          { return nil }
func (u *NullUpdater) NotifyUploadSucceeded(guid string, sha1 string, sha2 string) error { return nil }
func (u *NullUpdater) NotifyUploadFailed(guid string, e error) error                     { return nil }

type ResourceHandler struct {
	blobstore        Blobstore
	resourceType     string
	metricsService   MetricsService
	maxBodySizeLimit uint64
	updater          Updater
}

type responseBody struct {
	Guid      string    `json:"guid"`
	State     string    `json:"state"`
	Type      string    `json:"type"`
	CreatedAt time.Time `json:"created_at"`
}

func NewResourceHandler(blobstore Blobstore, resourceType string, metricsService MetricsService, maxBodySizeLimit uint64) *ResourceHandler {
	return &ResourceHandler{
		blobstore:        blobstore,
		resourceType:     resourceType,
		metricsService:   metricsService,
		maxBodySizeLimit: maxBodySizeLimit,
		updater:          &NullUpdater{},
	}
}

func NewResourceHandlerWithUpdater(blobstore Blobstore, updater Updater, resourceType string, metricsService MetricsService, maxBodySizeLimit uint64) *ResourceHandler {
	return &ResourceHandler{
		blobstore:        blobstore,
		resourceType:     resourceType,
		metricsService:   metricsService,
		maxBodySizeLimit: maxBodySizeLimit,
		updater:          updater,
	}
}

// TODO: instead of params, we could use `identifier string` to make the interface more type-safe.
//       Here and in the other methods.
func (handler *ResourceHandler) AddOrReplaceWithDigestInHeader(responseWriter http.ResponseWriter, request *http.Request, params map[string]string) {
	if !HandleBodySizeLimits(responseWriter, request, handler.maxBodySizeLimit) {
		return
	}
	logger.From(request).Debugw("Octet-Stream")

	digest := request.Header.Get("Digest")
	if digest == "" {
		badRequest(responseWriter, "No Digest header")
		return
	}
	parts := strings.Split(digest, "=")
	if len(parts) != 2 {
		badRequest(responseWriter, "Digest must have format sha256=value, but is "+digest)
		return
	}
	alg, value := strings.ToLower(parts[0]), parts[1]
	if alg != "sha256" {
		badRequest(responseWriter, "Digest must have format sha256=value, but is "+digest)
		return
	}
	if value == "" {
		badRequest(responseWriter, "Digest must have format sha256=value. Value cannot be empty")
		return
	}

	// TODO this can cause an out of memory panic. Should be smart about writing big files to disk instead.
	content, e := ioutil.ReadAll(request.Body)
	if e != nil {
		internalServerError(responseWriter, e)
		return
	}
	e = handler.blobstore.Put(params["identifier"]+"/"+value, bytes.NewReader(content))
	// TODO use Clock instead:
	writeResponseBasedOn("", e, responseWriter, http.StatusCreated, nil, &responseBody{Guid: params["identifier"], State: "READY", Type: "bits", CreatedAt: time.Now()}, "")
}

// TODO: instead of params, we could use `identifier string` to make the interface more type-safe.
//       Here and in the other methods.
func (handler *ResourceHandler) AddOrReplace(responseWriter http.ResponseWriter, request *http.Request, params map[string]string) {
	if !HandleBodySizeLimits(responseWriter, request, handler.maxBodySizeLimit) {
		return
	}
	file, _, e := request.FormFile(handler.resourceType)
	if e == http.ErrMissingFile {
		file, _, e = request.FormFile("bits")
	}
	if e == http.ErrMissingFile {
		badRequest(responseWriter, "Could not retrieve form parameter '%s' or 'bits", handler.resourceType)
		return
	}
	if e != nil {
		internalServerError(responseWriter, e)
		return
	}
	defer file.Close()

	tempFilename, e := CreateTempFileWithContent(file)
	if e != nil {
		internalServerError(responseWriter, e)
		return
	}

	e = handler.updater.NotifyProcessingUpload(params["identifier"])
	if handleNotificationError(e, responseWriter) {
		return
	}

	e = handler.uploadResource(tempFilename, request, params["identifier"])

	writeResponseBasedOn("", e, responseWriter, http.StatusCreated, nil, &responseBody{Guid: params["identifier"], State: "READY", Type: "bits", CreatedAt: time.Now()}, "")
}

func CreateTempFileWithContent(reader io.Reader) (string, error) {
	uploadedFile, e := ioutil.TempFile("", "bits")
	if e != nil {
		return "", errors.WithStack(e)
	}
	_, e = io.Copy(uploadedFile, reader)
	if e != nil {
		uploadedFile.Close()
		return "", errors.WithStack(e)
	}
	uploadedFile.Close()

	return uploadedFile.Name(), nil
}

func (handler *ResourceHandler) uploadResource(tempFilename string, request *http.Request, identifier string) error {
	defer os.Remove(tempFilename)

	tempFile, e := os.Open(tempFilename)
	if e != nil {
		return errors.Wrapf(e, "Could not open temporary file '%v'", tempFilename)
	}
	defer tempFile.Close()

	startTime := time.Now()
	e = handler.blobstore.Put(identifier, tempFile)
	handler.metricsService.SendTimingMetric(handler.resourceType+"-cp_to_blobstore-time", time.Since(startTime))

	if e != nil {
		handler.notifyUploadFailed(identifier, e, request)
		if _, noSpaceLeft := e.(*NoSpaceLeftError); noSpaceLeft {
			return e
		}
		return errors.Wrapf(e, "Could not upload temporary file to blobstore")
	}
	sha1, sha256, e := ShaSums(tempFilename)
	if e != nil {
		handler.notifyUploadFailed(identifier, e, request)
		return errors.Wrapf(e, "Could not build sha sums of temporary file '%v'", tempFilename)
	}
	e = handler.updater.NotifyUploadSucceeded(identifier, hex.EncodeToString(sha1), hex.EncodeToString(sha256))
	if e != nil {
		return errors.Wrapf(e, "Could not notify Cloud Controller about successful upload")
	}
	return nil
}

func (handler *ResourceHandler) notifyUploadFailed(identifier string, e error, request *http.Request) {
	notifyErr := handler.updater.NotifyUploadFailed(identifier, e)
	if notifyErr != nil {
		logger.From(request).Errorw("Failed to notifying CC about failed upload.", "error", notifyErr)
	}
}

func ShaSums(filename string) (sha1Sum []byte, sha256Sum []byte, e error) {
	file, e := os.Open(filename)
	if e != nil {
		return nil, nil, errors.WithStack(e)
	}
	defer file.Close()
	sha1Hash := sha1.New()
	sha256Hash := sha256.New()
	_, e = io.Copy(io.MultiWriter(sha1Hash, sha256Hash), file)
	if e != nil {
		return nil, nil, errors.WithStack(e)
	}
	return sha1Hash.Sum(nil), sha256Hash.Sum(nil), nil
}

func handleNotificationError(e error, responseWriter http.ResponseWriter) (wasError bool) {
	switch e.(type) {
	case *StateForbiddenError:
		responseWriter.WriteHeader(http.StatusBadRequest)
		fprintDescriptionAndCodeAsJSON(responseWriter, "290008", "Cannot update an existing package.")
		return true
	case *NotFoundError:
		responseWriter.WriteHeader(http.StatusNotFound)
		fprintDescriptionAndCodeAsJSON(responseWriter, "10010", e.Error())
		return true
	case error:
		internalServerError(responseWriter, e)
		return true
	}
	return false
}

func (handler *ResourceHandler) CopySourceGuid(responseWriter http.ResponseWriter, request *http.Request, params map[string]string) {
	if !HandleBodySizeLimits(responseWriter, request, handler.maxBodySizeLimit) {
		return
	}
	sourceGuid := sourceGuidFrom(request.Body, responseWriter)
	if sourceGuid == "" {
		return // response is already handled in sourceGuidFrom
	}
	e := handler.blobstore.Copy(sourceGuid, params["identifier"])
	// TODO use Clock instead:
	writeResponseBasedOn("", e, responseWriter, http.StatusCreated, nil, &responseBody{Guid: params["identifier"], State: "READY", Type: "bits", CreatedAt: time.Now()}, "")
}

func sourceGuidFrom(body io.ReadCloser, responseWriter http.ResponseWriter) string {
	content, e := ioutil.ReadAll(body)
	if e != nil {
		internalServerError(responseWriter, e)
		return ""
	}
	var payload struct {
		SourceGuid string `json:"source_guid"`
	}
	e = json.Unmarshal(content, &payload)
	if e != nil {
		badRequest(responseWriter, "Body must be valid JSON when request is not multipart/form-data. %+v", e)
		return ""
	}
	return payload.SourceGuid
}

func (handler *ResourceHandler) HeadOrRedirectAsGet(responseWriter http.ResponseWriter, request *http.Request, params map[string]string) {
	redirectLocation, e := handler.blobstore.HeadOrRedirectAsGet(params["identifier"])
	writeResponseBasedOn(redirectLocation, e, responseWriter, http.StatusOK, nil, nil, "")
}

func (handler *ResourceHandler) Get(responseWriter http.ResponseWriter, request *http.Request, params map[string]string) {
	body, redirectLocation, e := handler.blobstore.GetOrRedirect(params["identifier"])
	writeResponseBasedOn(redirectLocation, e, responseWriter, http.StatusOK, body, nil, request.Header.Get("If-None-Modify"))
}

func (handler *ResourceHandler) Delete(responseWriter http.ResponseWriter, request *http.Request, params map[string]string) {
	// TODO nothing should be S3 specific here
	// this check is needed, because S3 does not return a NotFound on a Delete request:
	exists, e := handler.blobstore.Exists(params["identifier"])
	if e != nil {
		internalServerError(responseWriter, e)
		return
	}
	if !exists {
		responseWriter.WriteHeader(http.StatusNotFound)
		return
	}
	e = handler.blobstore.Delete(params["identifier"])
	writeResponseBasedOn("", e, responseWriter, http.StatusNoContent, nil, nil, "")
}

func (handler *ResourceHandler) DeleteDir(responseWriter http.ResponseWriter, request *http.Request, params map[string]string) {
	e := handler.blobstore.DeleteDir(params["identifier"])
	switch e.(type) {
	case *NotFoundError:
		responseWriter.WriteHeader(http.StatusNoContent)
		return
	}
	writeResponseBasedOn("", e, responseWriter, http.StatusNoContent, nil, nil, "")
}

var emptyReader = ioutil.NopCloser(bytes.NewReader(nil))

func writeResponseBasedOn(redirectLocation string, e error, responseWriter http.ResponseWriter, statusCode int, body io.ReadCloser, jsonBody *responseBody, ifNoneModify string) {
	switch e.(type) {
	case *NotFoundError:
		responseWriter.WriteHeader(http.StatusNotFound)
		return
	case *NoSpaceLeftError:
		http.Error(responseWriter, descriptionAndCodeAsJSON("500000", "Request Entity Too Large"), http.StatusInsufficientStorage)
		return
	case error:
		internalServerError(responseWriter, e)
		return
	}
	if redirectLocation != "" {
		redirect(responseWriter, redirectLocation)
		return
	}
	if body != nil {
		defer body.Close()
		var buffer bytes.Buffer
		sha := sha1.New()
		_, e := io.Copy(io.MultiWriter(&buffer, sha), body)
		if e != nil {
			internalServerError(responseWriter, e)
			return
		}
		eTag := hex.EncodeToString(sha.Sum(nil))
		logger.Log.Debugw("Cache check", "if-none-modify", ifNoneModify, "etag", eTag)
		responseWriter.Header().Set("ETag", eTag)
		if ifNoneModify == eTag {
			responseWriter.WriteHeader(http.StatusNotModified)
			return
		}
		responseWriter.WriteHeader(statusCode)
		io.Copy(responseWriter, &buffer)
		return
	}
	if jsonBody != nil {
		respBody, marshallingErr := json.Marshal(jsonBody)
		if marshallingErr != nil {
			internalServerError(responseWriter, marshallingErr)
			return
		}
		responseWriter.WriteHeader(statusCode)
		responseWriter.Write(respBody)
		return
	}
	responseWriter.WriteHeader(statusCode)
}

func redirect(responseWriter http.ResponseWriter, redirectLocation string) {
	responseWriter.Header().Set("Location", redirectLocation)
	responseWriter.WriteHeader(http.StatusFound)
}

func internalServerError(responseWriter http.ResponseWriter, e error) {
	logger.Log.Errorw("Internal Server Error.", "error", fmt.Sprintf("%+v", e))
	responseWriter.WriteHeader(http.StatusInternalServerError)
}

func badRequest(responseWriter http.ResponseWriter, message string, args ...interface{}) {
	responseBody := fmt.Sprintf(message, args...)
	logger.Log.Infow("Bad request", "body", responseBody)
	responseWriter.WriteHeader(http.StatusBadRequest)
	fprintDescriptionAndCodeAsJSON(responseWriter, "290003", message, args...)
}

func fprintDescriptionAndCodeAsJSON(responseWriter http.ResponseWriter, code string, description string, a ...interface{}) {
	fmt.Fprintf(responseWriter, descriptionAndCodeAsJSON(code, description, a...))
}

func descriptionAndCodeAsJSON(code string, description string, a ...interface{}) string {
	return fmt.Sprintf(`{"description":"%v","code":%v}`, fmt.Sprintf(description, a...), code)
}
<commit_msg>Add missing handler.notifyUploadFailed<commit_after>package bitsgo

import (
	"bytes"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/petergtz/bitsgo/logger"
	"github.com/pkg/errors"
)

type MetricsService interface {
	SendTimingMetric(name string, duration time.Duration)
}

type StateForbiddenError struct {
	error
}

func NewStateForbiddenError() *StateForbiddenError {
	return &StateForbiddenError{fmt.Errorf("StateForbiddenError")}
}

type Updater interface {
	NotifyProcessingUpload(guid string) error
	NotifyUploadSucceeded(guid string, sha1 string, sha2 string) error
	NotifyUploadFailed(guid string, e error) error
}

type NullUpdater struct{}

func (u *NullUpdater) NotifyProcessingUpload(guid string) error                          { return nil }
func (u *NullUpdater) NotifyUploadSucceeded(guid string, sha1 string, sha2 string) error { return nil }
func (u *NullUpdater) NotifyUploadFailed(guid string, e error) error                     { return nil }

type ResourceHandler struct {
	blobstore        Blobstore
	resourceType     string
	metricsService   MetricsService
	maxBodySizeLimit uint64
	updater          Updater
}

type responseBody struct {
	Guid      string    `json:"guid"`
	State     string    `json:"state"`
	Type      string    `json:"type"`
	CreatedAt time.Time `json:"created_at"`
}

func NewResourceHandler(blobstore Blobstore, resourceType string, metricsService MetricsService, maxBodySizeLimit uint64) *ResourceHandler {
	return &ResourceHandler{
		blobstore:        blobstore,
		resourceType:     resourceType,
		metricsService:   metricsService,
		maxBodySizeLimit: maxBodySizeLimit,
		updater:          &NullUpdater{},
	}
}

func NewResourceHandlerWithUpdater(blobstore Blobstore, updater Updater, resourceType string, metricsService MetricsService, maxBodySizeLimit uint64) *ResourceHandler {
	return &ResourceHandler{
		blobstore:        blobstore,
		resourceType:     resourceType,
		metricsService:   metricsService,
		maxBodySizeLimit: maxBodySizeLimit,
		updater:          updater,
	}
}

// TODO: instead of params, we could use `identifier string` to make the interface more type-safe.
//       Here and in the other methods.
func (handler *ResourceHandler) AddOrReplaceWithDigestInHeader(responseWriter http.ResponseWriter, request *http.Request, params map[string]string) {
	if !HandleBodySizeLimits(responseWriter, request, handler.maxBodySizeLimit) {
		return
	}
	logger.From(request).Debugw("Octet-Stream")

	digest := request.Header.Get("Digest")
	if digest == "" {
		badRequest(responseWriter, "No Digest header")
		return
	}
	parts := strings.Split(digest, "=")
	if len(parts) != 2 {
		badRequest(responseWriter, "Digest must have format sha256=value, but is "+digest)
		return
	}
	alg, value := strings.ToLower(parts[0]), parts[1]
	if alg != "sha256" {
		badRequest(responseWriter, "Digest must have format sha256=value, but is "+digest)
		return
	}
	if value == "" {
		badRequest(responseWriter, "Digest must have format sha256=value. Value cannot be empty")
		return
	}

	// TODO this can cause an out of memory panic. Should be smart about writing big files to disk instead.
	content, e := ioutil.ReadAll(request.Body)
	if e != nil {
		internalServerError(responseWriter, e)
		return
	}
	e = handler.blobstore.Put(params["identifier"]+"/"+value, bytes.NewReader(content))
	// TODO use Clock instead:
	writeResponseBasedOn("", e, responseWriter, http.StatusCreated, nil, &responseBody{Guid: params["identifier"], State: "READY", Type: "bits", CreatedAt: time.Now()}, "")
}

// TODO: instead of params, we could use `identifier string` to make the interface more type-safe.
//       Here and in the other methods.
func (handler *ResourceHandler) AddOrReplace(responseWriter http.ResponseWriter, request *http.Request, params map[string]string) {
	if !HandleBodySizeLimits(responseWriter, request, handler.maxBodySizeLimit) {
		return
	}
	file, _, e := request.FormFile(handler.resourceType)
	if e == http.ErrMissingFile {
		file, _, e = request.FormFile("bits")
	}
	if e == http.ErrMissingFile {
		badRequest(responseWriter, "Could not retrieve form parameter '%s' or 'bits", handler.resourceType)
		return
	}
	if e != nil {
		internalServerError(responseWriter, e)
		return
	}
	defer file.Close()

	tempFilename, e := CreateTempFileWithContent(file)
	if e != nil {
		internalServerError(responseWriter, e)
		return
	}

	e = handler.updater.NotifyProcessingUpload(params["identifier"])
	if handleNotificationError(e, responseWriter) {
		return
	}

	e = handler.uploadResource(tempFilename, request, params["identifier"])

	writeResponseBasedOn("", e, responseWriter, http.StatusCreated, nil, &responseBody{Guid: params["identifier"], State: "READY", Type: "bits", CreatedAt: time.Now()}, "")
}

func CreateTempFileWithContent(reader io.Reader) (string, error) {
	uploadedFile, e := ioutil.TempFile("", "bits")
	if e != nil {
		return "", errors.WithStack(e)
	}
	_, e = io.Copy(uploadedFile, reader)
	if e != nil {
		uploadedFile.Close()
		return "", errors.WithStack(e)
	}
	uploadedFile.Close()

	return uploadedFile.Name(), nil
}

func (handler *ResourceHandler) uploadResource(tempFilename string, request *http.Request, identifier string) error {
	defer os.Remove(tempFilename)

	tempFile, e := os.Open(tempFilename)
	if e != nil {
		handler.notifyUploadFailed(identifier, e, request)
		return errors.Wrapf(e, "Could not open temporary file '%v'", tempFilename)
	}
	defer tempFile.Close()

	startTime := time.Now()
	e = handler.blobstore.Put(identifier, tempFile)
	handler.metricsService.SendTimingMetric(handler.resourceType+"-cp_to_blobstore-time", time.Since(startTime))

	if e != nil {
		handler.notifyUploadFailed(identifier, e, request)
		if _, noSpaceLeft := e.(*NoSpaceLeftError); noSpaceLeft {
			return e
		}
		return errors.Wrapf(e, "Could not upload temporary file to blobstore")
	}
	sha1, sha256, e := ShaSums(tempFilename)
	if e != nil {
		handler.notifyUploadFailed(identifier, e, request)
		return errors.Wrapf(e, "Could not build sha sums of temporary file '%v'", tempFilename)
	}
	e = handler.updater.NotifyUploadSucceeded(identifier, hex.EncodeToString(sha1), hex.EncodeToString(sha256))
	if e != nil {
		return errors.Wrapf(e, "Could not notify Cloud Controller about successful upload")
	}
	return nil
}

func (handler *ResourceHandler) notifyUploadFailed(identifier string, e error, request *http.Request) {
	notifyErr := handler.updater.NotifyUploadFailed(identifier, e)
	if notifyErr != nil {
		logger.From(request).Errorw("Failed to notifying CC about failed upload.", "error", notifyErr)
	}
}

func ShaSums(filename string) (sha1Sum []byte, sha256Sum []byte, e error) {
	file, e := os.Open(filename)
	if e != nil {
		return nil, nil, errors.WithStack(e)
	}
	defer file.Close()
	sha1Hash := sha1.New()
	sha256Hash := sha256.New()
	_, e = io.Copy(io.MultiWriter(sha1Hash, sha256Hash), file)
	if e != nil {
		return nil, nil, errors.WithStack(e)
	}
	return sha1Hash.Sum(nil), sha256Hash.Sum(nil), nil
}

func handleNotificationError(e error, responseWriter http.ResponseWriter) (wasError bool) {
	switch e.(type) {
	case *StateForbiddenError:
		responseWriter.WriteHeader(http.StatusBadRequest)
		fprintDescriptionAndCodeAsJSON(responseWriter, "290008", "Cannot update an existing package.")
		return true
	case *NotFoundError:
		responseWriter.WriteHeader(http.StatusNotFound)
		fprintDescriptionAndCodeAsJSON(responseWriter, "10010", e.Error())
		return true
	case error:
		internalServerError(responseWriter, e)
		return true
	}
	return false
}

func (handler *ResourceHandler) CopySourceGuid(responseWriter http.ResponseWriter, request *http.Request, params map[string]string) {
	if !HandleBodySizeLimits(responseWriter, request, handler.maxBodySizeLimit) {
		return
	}
	sourceGuid := sourceGuidFrom(request.Body, responseWriter)
	if sourceGuid == "" {
		return // response is already handled in sourceGuidFrom
	}
	e := handler.blobstore.Copy(sourceGuid, params["identifier"])
	// TODO use Clock instead:
	writeResponseBasedOn("", e, responseWriter, http.StatusCreated, nil, &responseBody{Guid: params["identifier"], State: "READY", Type: "bits", CreatedAt: time.Now()}, "")
}

func sourceGuidFrom(body io.ReadCloser, responseWriter http.ResponseWriter) string {
	content, e := ioutil.ReadAll(body)
	if e != nil {
		internalServerError(responseWriter, e)
		return ""
	}
	var payload struct {
		SourceGuid string `json:"source_guid"`
	}
	e = json.Unmarshal(content, &payload)
	if e != nil {
		badRequest(responseWriter, "Body must be valid JSON when request is not multipart/form-data. %+v", e)
		return ""
	}
	return payload.SourceGuid
}

func (handler *ResourceHandler) HeadOrRedirectAsGet(responseWriter http.ResponseWriter, request *http.Request, params map[string]string) {
	redirectLocation, e := handler.blobstore.HeadOrRedirectAsGet(params["identifier"])
	writeResponseBasedOn(redirectLocation, e, responseWriter, http.StatusOK, nil, nil, "")
}

func (handler *ResourceHandler) Get(responseWriter http.ResponseWriter, request *http.Request, params map[string]string) {
	body, redirectLocation, e := handler.blobstore.GetOrRedirect(params["identifier"])
	writeResponseBasedOn(redirectLocation, e, responseWriter, http.StatusOK, body, nil, request.Header.Get("If-None-Modify"))
}

func (handler *ResourceHandler) Delete(responseWriter http.ResponseWriter, request *http.Request, params map[string]string) {
	// TODO nothing should be S3 specific here
	// this check is needed, because S3 does not return a NotFound on a Delete request:
	exists, e := handler.blobstore.Exists(params["identifier"])
	if e != nil {
		internalServerError(responseWriter, e)
		return
	}
	if !exists {
		responseWriter.WriteHeader(http.StatusNotFound)
		return
	}
	e = handler.blobstore.Delete(params["identifier"])
	writeResponseBasedOn("", e, responseWriter, http.StatusNoContent, nil, nil, "")
}

func (handler *ResourceHandler) DeleteDir(responseWriter http.ResponseWriter, request *http.Request, params map[string]string) {
	e := handler.blobstore.DeleteDir(params["identifier"])
	switch e.(type) {
	case *NotFoundError:
		responseWriter.WriteHeader(http.StatusNoContent)
		return
	}
	writeResponseBasedOn("", e, responseWriter, http.StatusNoContent, nil, nil, "")
}

var emptyReader = ioutil.NopCloser(bytes.NewReader(nil))

func writeResponseBasedOn(redirectLocation string, e error, responseWriter http.ResponseWriter, statusCode int, body io.ReadCloser, jsonBody *responseBody, ifNoneModify string) {
	switch e.(type) {
	case *NotFoundError:
		responseWriter.WriteHeader(http.StatusNotFound)
		return
	case *NoSpaceLeftError:
		http.Error(responseWriter, descriptionAndCodeAsJSON("500000", "Request Entity Too Large"), http.StatusInsufficientStorage)
		return
	case error:
		internalServerError(responseWriter, e)
		return
	}
	if redirectLocation != "" {
		redirect(responseWriter, redirectLocation)
		return
	}
	if body != nil {
		defer body.Close()
		var buffer bytes.Buffer
		sha := sha1.New()
		_, e := io.Copy(io.MultiWriter(&buffer, sha), body)
		if e != nil {
			internalServerError(responseWriter, e)
			return
		}
		eTag := hex.EncodeToString(sha.Sum(nil))
		logger.Log.Debugw("Cache check", "if-none-modify", ifNoneModify, "etag", eTag)
		responseWriter.Header().Set("ETag", eTag)
		if ifNoneModify == eTag {
			responseWriter.WriteHeader(http.StatusNotModified)
			return
		}
		responseWriter.WriteHeader(statusCode)
		io.Copy(responseWriter, &buffer)
		return
	}
	if jsonBody != nil {
		respBody, marshallingErr := json.Marshal(jsonBody)
		if marshallingErr != nil {
			internalServerError(responseWriter, marshallingErr)
			return
		}
		responseWriter.WriteHeader(statusCode)
		responseWriter.Write(respBody)
		return
	}
	responseWriter.WriteHeader(statusCode)
}

func redirect(responseWriter http.ResponseWriter, redirectLocation string) {
	responseWriter.Header().Set("Location", redirectLocation)
	responseWriter.WriteHeader(http.StatusFound)
}

func internalServerError(responseWriter http.ResponseWriter, e error) {
	logger.Log.Errorw("Internal Server Error.", "error", fmt.Sprintf("%+v", e))
	responseWriter.WriteHeader(http.StatusInternalServerError)
}

func badRequest(responseWriter http.ResponseWriter, message string, args ...interface{}) {
	responseBody := fmt.Sprintf(message, args...)
	logger.Log.Infow("Bad request", "body", responseBody)
	responseWriter.WriteHeader(http.StatusBadRequest)
	fprintDescriptionAndCodeAsJSON(responseWriter, "290003", message, args...)
}

func fprintDescriptionAndCodeAsJSON(responseWriter http.ResponseWriter, code string, description string, a ...interface{}) {
	fmt.Fprintf(responseWriter, descriptionAndCodeAsJSON(code, description, a...))
}

func descriptionAndCodeAsJSON(code string, description string, a ...interface{}) string {
	return fmt.Sprintf(`{"description":"%v","code":%v}`, fmt.Sprintf(description, a...), code)
}
<|endoftext|>


<commit_before>package opts

import (
	"encoding/base64"
	"encoding/hex"
	"fmt"

	base58 "github.com/jbenet/go-base58"
	mh "github.com/multiformats/go-multihash"
)

func Decode(encoding, digest string) (mh.Multihash, error) {
	switch encoding {
	case "raw":
		return mh.Cast([]byte(digest))
	case "hex":
		return hex.DecodeString(digest)
	case "base58":
		return base58.Decode(digest), nil
	case "base64":
		return base64.StdEncoding.DecodeString(digest)
	default:
		return nil, fmt.Errorf("unknown encoding: %s", encoding)
	}
}

func Encode(encoding string, hash mh.Multihash) (string, error) {
	switch encoding {
	case "raw":
		return string(hash), nil
	case "hex":
		return hex.EncodeToString(hash), nil
	case "base58":
		return base58.Encode(hash), nil
	case "base64":
		return base64.StdEncoding.EncodeToString(hash), nil
	default:
		return "", fmt.Errorf("unknown encoding: %s", encoding)
	}
}
<commit_msg>completely switch to new b58 library<commit_after>package opts

import (
	"encoding/base64"
	"encoding/hex"
	"fmt"

	base58 "github.com/mr-tron/base58/base58"
	mh "github.com/multiformats/go-multihash"
)

func Decode(encoding, digest string) (mh.Multihash, error) {
	switch encoding {
	case "raw":
		return mh.Cast([]byte(digest))
	case "hex":
		return hex.DecodeString(digest)
	case "base58":
		return base58.Decode(digest)
	case "base64":
		return base64.StdEncoding.DecodeString(digest)
	default:
		return nil, fmt.Errorf("unknown encoding: %s", encoding)
	}
}

func Encode(encoding string, hash mh.Multihash) (string, error) {
	switch encoding {
	case "raw":
		return string(hash), nil
	case "hex":
		return hex.EncodeToString(hash), nil
	case "base58":
		return base58.Encode(hash), nil
	case "base64":
		return base64.StdEncoding.EncodeToString(hash), nil
	default:
		return "", fmt.Errorf("unknown encoding: %s", encoding)
	}
}
<|endoftext|>