<commit_before>package models

import (
	"errors"
	"fmt"
	"testing"

	"github.com/taironas/gonawin/helpers"

	"appengine/aetest"
)

type testUser struct {
	email    string
	username string
	name     string
	alias    string
	isAdmin  bool
	auth     string
}

// TestCreateUser tests that you can create a user.
//
func TestCreateUser(t *testing.T) {
	var c aetest.Context
	var err error
	options := aetest.Options{StronglyConsistentDatastore: true}

	if c, err = aetest.NewContext(&options); err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	tests := []struct {
		title string
		user  testUser
	}{
		{"can create user", testUser{"foo@bar.com", "john.snow", "john snow", "crow", false, ""}},
	}

	for i, test := range tests {
		t.Log(test.title)
		var got *User
		if got, err = CreateUser(c, test.user.email, test.user.username, test.user.name, test.user.alias, test.user.isAdmin, test.user.auth); err != nil {
			t.Errorf("test %v - Error: %v", i, err)
		}
		if err = checkUser(got, test.user); err != nil {
			t.Errorf("test %v - Error: %v", i, err)
		}
		if err = checkUserInvertedIndex(t, c, got); err != nil {
			t.Errorf("test %v - Error: %v", i, err)
		}
	}
}

// TestUserById tests that you can get a user by its ID.
//
func TestUserById(t *testing.T) {
	var c aetest.Context
	var err error
	options := aetest.Options{StronglyConsistentDatastore: true}

	if c, err = aetest.NewContext(&options); err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	var createdUser *User
	if createdUser, err = CreateUser(c, "foo@bar.com", "john.snow", "john snow", "crow", false, ""); err != nil {
		t.Errorf("Error: %v", err)
	}

	tests := []struct {
		title  string
		userID int64
		user   testUser
		err    string
	}{
		{"can get user by ID", createdUser.Id, testUser{"foo@bar.com", "john.snow", "john snow", "crow", false, ""}, ""},
		{"non existing user for given ID", createdUser.Id + 50, testUser{}, "datastore: no such entity"},
	}

	for _, test := range tests {
		t.Log(test.title)

		var u *User

		u, err = UserById(c, test.userID)

		if errorStringRepresentation(err) != test.err {
			t.Errorf("Error: want err: %s, got: %q", test.err, err)
		} else if test.err == "" && u == nil {
			t.Errorf("Error: an user should have been found")
		} else if test.err == "" && u != nil {
			if err = checkUser(u, test.user); err != nil {
				t.Errorf("Error: want user: %v, got: %v", test.user, u)
			}
		}
	}
}

// TestUsersByIds tests that you can get a list of users by their IDs.
//
func TestUsersByIds(t *testing.T) {
	var c aetest.Context
	var err error
	options := aetest.Options{StronglyConsistentDatastore: true}

	if c, err = aetest.NewContext(&options); err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	/*Test data: good user ID*/
	testUsers := []testUser{
		{"foo@bar.com", "john.snow", "john snow", "crow", false, ""},
		{"foo@bar.com", "robb.stark", "robb stark", "king in the north", false, ""},
		{"foo@bar.com", "jamie.lannister", "jamie lannister", "kingslayer", false, ""},
	}

	var gotIDs []int64

	for _, testUser := range testUsers {
		var got *User
		if got, err = CreateUser(c, testUser.email, testUser.username, testUser.name, testUser.alias, testUser.isAdmin, testUser.auth); err != nil {
			t.Errorf("Error: %v", err)
		}

		gotIDs = append(gotIDs, got.Id)
	}

	/*Test data: only one bad user ID*/
	userIDsWithOneBadID := make([]int64, len(gotIDs))
	copy(userIDsWithOneBadID, gotIDs)
	userIDsWithOneBadID[0] = userIDsWithOneBadID[0] + 50

	/*Test data: bad user IDs*/
	userIDsWithBadIDs := make([]int64, len(gotIDs))
	copy(userIDsWithBadIDs, gotIDs)
	userIDsWithBadIDs[0] = userIDsWithBadIDs[0] + 50
	userIDsWithBadIDs[1] = userIDsWithBadIDs[1] + 50
	userIDsWithBadIDs[2] = userIDsWithBadIDs[2] + 50

	tests := []struct {
		title   string
		userIDs []int64
		users   []testUser
		err     string
	}{
		{
			"can get users by IDs",
			gotIDs,
			[]testUser{
				{"foo@bar.com", "john.snow", "john snow", "crow", false, ""},
				{"foo@bar.com", "robb.stark", "robb stark", "king in the north", false, ""},
				{"foo@bar.com", "jamie.lannister", "jamie lannister", "kingslayer", false, ""},
			},
			"",
		},
		{
			"can get all users by IDs except one",
			userIDsWithOneBadID,
			[]testUser{
				{"foo@bar.com", "robb.stark", "robb stark", "king in the north", false, ""},
				{"foo@bar.com", "jamie.lannister", "jamie lannister", "kingslayer", false, ""},
			},
			"",
		},
		{
			"non existing users for given IDs",
			userIDsWithBadIDs,
			[]testUser{},
			"",
		},
	}

	for _, test := range tests {
		t.Log(test.title)

		var users []*User

		users, err = UsersByIds(c, test.userIDs)

		if errorStringRepresentation(err) != test.err {
			t.Errorf("Error: want err: %s, got: %q", test.err, err)
		} else if test.err == "" && users != nil {
			for i, user := range test.users {
				if err = checkUser(users[i], user); err != nil {
					t.Errorf("Error: want user: %v, got: %v", user, users[i])
				}
			}
		}
	}
}

// TestDestroyUser tests that you can destroy a user.
//
func TestDestroyUser(t *testing.T) {
	var c aetest.Context
	var err error
	options := aetest.Options{StronglyConsistentDatastore: true}

	if c, err = aetest.NewContext(&options); err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	test := struct {
		title string
		user  testUser
	}{
		"can destroy user", testUser{"foo@bar.com", "john.snow", "john snow", "crow", false, ""},
	}

	t.Log(test.title)
	var got *User
	if got, err = CreateUser(c, test.user.email, test.user.username, test.user.name, test.user.alias, test.user.isAdmin, test.user.auth); err != nil {
		t.Errorf("Error: %v", err)
	}

	if err = got.Destroy(c); err != nil {
		t.Errorf("Error: %v", err)
	}

	var u *User
	if u, err = UserById(c, got.Id); u != nil {
		t.Errorf("Error: user found, not properly destroyed")
	}
	if err = checkUserInvertedIndex(t, c, got); err == nil {
		t.Errorf("Error: user found in database")
	}
}

// TestFindUser tests that you can find a user.
//
func TestFindUser(t *testing.T) {
	var c aetest.Context
	var err error
	options := aetest.Options{StronglyConsistentDatastore: true}

	if c, err = aetest.NewContext(&options); err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	test := struct {
		title string
		user  testUser
	}{
		"can find user", testUser{"foo@bar.com", "john.snow", "john snow", "crow", false, ""},
	}

	t.Log(test.title)

	if _, err = CreateUser(c, test.user.email, test.user.username, test.user.name, test.user.alias, test.user.isAdmin, test.user.auth); err != nil {
		t.Errorf("Error: %v", err)
	}

	var got *User
	if got = FindUser(c, "Username", "john.snow"); got == nil {
		t.Errorf("Error: user not found by Username")
	}

	if got = FindUser(c, "Name", "john snow"); got == nil {
		t.Errorf("Error: user not found by Name")
	}

	if got = FindUser(c, "Alias", "crow"); got == nil {
		t.Errorf("Error: user not found by Alias")
	}
}

// TestFindAllUsers tests that you can find all the users.
//
func TestFindAllUsers(t *testing.T) {
	var c aetest.Context
	var err error
	options := aetest.Options{StronglyConsistentDatastore: true}

	if c, err = aetest.NewContext(&options); err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	test := struct {
		title string
		users []testUser
	}{
		"can find users",
		[]testUser{
			{"foo@bar.com", "john.snow", "john snow", "crow", false, ""},
			{"foo@bar.com", "robb.stark", "robb stark", "king in the north", false, ""},
			{"foo@bar.com", "jamie.lannister", "jamie lannister", "kingslayer", false, ""},
		},
	}

	t.Log(test.title)

	for _, user := range test.users {
		if _, err = CreateUser(c, user.email, user.username, user.name, user.alias, user.isAdmin, user.auth); err != nil {
			t.Errorf("Error: %v", err)
		}
	}

	var got []*User
	if got = FindAllUsers(c); got == nil {
		t.Errorf("Error: users not found")
	}

	if len(got) != len(test.users) {
		t.Errorf("Error: want users count == %d, got %d", len(test.users), len(got))
	}

	for i, user := range test.users {
		if err = checkUser(got[i], user); err != nil {
			t.Errorf("test %v - Error: %v", i, err)
		}
	}
}

func checkUser(got *User, want testUser) error {
	var s string
	if got.Email != want.email {
		s = fmt.Sprintf("want Email == %s, got %s", want.email, got.Email)
	} else if got.Username != want.username {
		s = fmt.Sprintf("want Username == %s, got %s", want.username, got.Username)
	} else if got.Name != want.name {
		s = fmt.Sprintf("want Name == %s, got %s", want.name, got.Name)
	} else if got.Alias != want.alias {
		s = fmt.Sprintf("want Name == %s, got %s", want.alias, got.Alias)
	} else if got.IsAdmin != want.isAdmin {
		s = fmt.Sprintf("want isAdmin == %t, got %t", want.isAdmin, got.IsAdmin)
	} else if got.Auth != want.auth {
		s = fmt.Sprintf("want auth == %s, got %s", want.auth, got.Auth)
	} else {
		return nil
	}
	return errors.New(s)
}

func checkUserInvertedIndex(t *testing.T, c aetest.Context, got *User) error {

	var ids []int64
	var err error
	words := helpers.SetOfStrings("john")
	if ids, err = GetUserInvertedIndexes(c, words); err != nil {
		s := fmt.Sprintf("failed calling GetUserInvertedIndexes %v", err)
		return errors.New(s)
	}
	for _, id := range ids {
		if id == got.Id {
			return nil
		}
	}

	return errors.New("user not found")

}

// errorStringRepresentation returns the string representation of an error.
func errorStringRepresentation(err error) string {
	if err != nil {
		return err.Error()
	}
	return ""
}
<commit_msg>rename createdUser to u & found user to got<commit_after>package models

import (
	"errors"
	"fmt"
	"testing"

	"github.com/taironas/gonawin/helpers"

	"appengine/aetest"
)

type testUser struct {
	email    string
	username string
	name     string
	alias    string
	isAdmin  bool
	auth     string
}

// TestCreateUser tests that you can create a user.
//
func TestCreateUser(t *testing.T) {
	var c aetest.Context
	var err error
	options := aetest.Options{StronglyConsistentDatastore: true}

	if c, err = aetest.NewContext(&options); err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	tests := []struct {
		title string
		user  testUser
	}{
		{"can create user", testUser{"foo@bar.com", "john.snow", "john snow", "crow", false, ""}},
	}

	for i, test := range tests {
		t.Log(test.title)
		var got *User
		if got, err = CreateUser(c, test.user.email, test.user.username, test.user.name, test.user.alias, test.user.isAdmin, test.user.auth); err != nil {
			t.Errorf("test %v - Error: %v", i, err)
		}
		if err = checkUser(got, test.user); err != nil {
			t.Errorf("test %v - Error: %v", i, err)
		}
		if err = checkUserInvertedIndex(t, c, got); err != nil {
			t.Errorf("test %v - Error: %v", i, err)
		}
	}
}

// TestUserById tests that you can get a user by its ID.
//
func TestUserById(t *testing.T) {
	var c aetest.Context
	var err error
	options := aetest.Options{StronglyConsistentDatastore: true}

	if c, err = aetest.NewContext(&options); err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	var u *User
	if u, err = CreateUser(c, "foo@bar.com", "john.snow", "john snow", "crow", false, ""); err != nil {
		t.Errorf("Error: %v", err)
	}

	tests := []struct {
		title  string
		userID int64
		user   testUser
		err    string
	}{
		{"can get user by ID", u.Id, testUser{"foo@bar.com", "john.snow", "john snow", "crow", false, ""}, ""},
		{"non existing user for given ID", u.Id + 50, testUser{}, "datastore: no such entity"},
	}

	for _, test := range tests {
		t.Log(test.title)

		var u *User

		got, err = UserById(c, test.userID)

		if errorStringRepresentation(err) != test.err {
			t.Errorf("Error: want err: %s, got: %q", test.err, err)
		} else if test.err == "" && got == nil {
			t.Errorf("Error: an user should have been found")
		} else if test.err == "" && got != nil {
			if err = checkUser(got, test.user); err != nil {
				t.Errorf("Error: want user: %v, got: %v", test.user, got)
			}
		}
	}
}

// TestUsersByIds tests that you can get a list of users by their IDs.
//
func TestUsersByIds(t *testing.T) {
	var c aetest.Context
	var err error
	options := aetest.Options{StronglyConsistentDatastore: true}

	if c, err = aetest.NewContext(&options); err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	/*Test data: good user ID*/
	testUsers := []testUser{
		{"foo@bar.com", "john.snow", "john snow", "crow", false, ""},
		{"foo@bar.com", "robb.stark", "robb stark", "king in the north", false, ""},
		{"foo@bar.com", "jamie.lannister", "jamie lannister", "kingslayer", false, ""},
	}

	var gotIDs []int64

	for _, testUser := range testUsers {
		var got *User
		if got, err = CreateUser(c, testUser.email, testUser.username, testUser.name, testUser.alias, testUser.isAdmin, testUser.auth); err != nil {
			t.Errorf("Error: %v", err)
		}

		gotIDs = append(gotIDs, got.Id)
	}

	/*Test data: only one bad user ID*/
	userIDsWithOneBadID := make([]int64, len(gotIDs))
	copy(userIDsWithOneBadID, gotIDs)
	userIDsWithOneBadID[0] = userIDsWithOneBadID[0] + 50

	/*Test data: bad user IDs*/
	userIDsWithBadIDs := make([]int64, len(gotIDs))
	copy(userIDsWithBadIDs, gotIDs)
	userIDsWithBadIDs[0] = userIDsWithBadIDs[0] + 50
	userIDsWithBadIDs[1] = userIDsWithBadIDs[1] + 50
	userIDsWithBadIDs[2] = userIDsWithBadIDs[2] + 50

	tests := []struct {
		title   string
		userIDs []int64
		users   []testUser
		err     string
	}{
		{
			"can get users by IDs",
			gotIDs,
			[]testUser{
				{"foo@bar.com", "john.snow", "john snow", "crow", false, ""},
				{"foo@bar.com", "robb.stark", "robb stark", "king in the north", false, ""},
				{"foo@bar.com", "jamie.lannister", "jamie lannister", "kingslayer", false, ""},
			},
			"",
		},
		{
			"can get all users by IDs except one",
			userIDsWithOneBadID,
			[]testUser{
				{"foo@bar.com", "robb.stark", "robb stark", "king in the north", false, ""},
				{"foo@bar.com", "jamie.lannister", "jamie lannister", "kingslayer", false, ""},
			},
			"",
		},
		{
			"non existing users for given IDs",
			userIDsWithBadIDs,
			[]testUser{},
			"",
		},
	}

	for _, test := range tests {
		t.Log(test.title)

		var users []*User

		users, err = UsersByIds(c, test.userIDs)

		if errorStringRepresentation(err) != test.err {
			t.Errorf("Error: want err: %s, got: %q", test.err, err)
		} else if test.err == "" && users != nil {
			for i, user := range test.users {
				if err = checkUser(users[i], user); err != nil {
					t.Errorf("Error: want user: %v, got: %v", user, users[i])
				}
			}
		}
	}
}

// TestDestroyUser tests that you can destroy a user.
//
func TestDestroyUser(t *testing.T) {
	var c aetest.Context
	var err error
	options := aetest.Options{StronglyConsistentDatastore: true}

	if c, err = aetest.NewContext(&options); err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	test := struct {
		title string
		user  testUser
	}{
		"can destroy user", testUser{"foo@bar.com", "john.snow", "john snow", "crow", false, ""},
	}

	t.Log(test.title)
	var got *User
	if got, err = CreateUser(c, test.user.email, test.user.username, test.user.name, test.user.alias, test.user.isAdmin, test.user.auth); err != nil {
		t.Errorf("Error: %v", err)
	}

	if err = got.Destroy(c); err != nil {
		t.Errorf("Error: %v", err)
	}

	var u *User
	if u, err = UserById(c, got.Id); u != nil {
		t.Errorf("Error: user found, not properly destroyed")
	}
	if err = checkUserInvertedIndex(t, c, got); err == nil {
		t.Errorf("Error: user found in database")
	}
}

// TestFindUser tests that you can find a user.
//
func TestFindUser(t *testing.T) {
	var c aetest.Context
	var err error
	options := aetest.Options{StronglyConsistentDatastore: true}

	if c, err = aetest.NewContext(&options); err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	test := struct {
		title string
		user  testUser
	}{
		"can find user", testUser{"foo@bar.com", "john.snow", "john snow", "crow", false, ""},
	}

	t.Log(test.title)

	if _, err = CreateUser(c, test.user.email, test.user.username, test.user.name, test.user.alias, test.user.isAdmin, test.user.auth); err != nil {
		t.Errorf("Error: %v", err)
	}

	var got *User
	if got = FindUser(c, "Username", "john.snow"); got == nil {
		t.Errorf("Error: user not found by Username")
	}

	if got = FindUser(c, "Name", "john snow"); got == nil {
		t.Errorf("Error: user not found by Name")
	}

	if got = FindUser(c, "Alias", "crow"); got == nil {
		t.Errorf("Error: user not found by Alias")
	}
}

// TestFindAllUsers tests that you can find all the users.
//
func TestFindAllUsers(t *testing.T) {
	var c aetest.Context
	var err error
	options := aetest.Options{StronglyConsistentDatastore: true}

	if c, err = aetest.NewContext(&options); err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	test := struct {
		title string
		users []testUser
	}{
		"can find users",
		[]testUser{
			{"foo@bar.com", "john.snow", "john snow", "crow", false, ""},
			{"foo@bar.com", "robb.stark", "robb stark", "king in the north", false, ""},
			{"foo@bar.com", "jamie.lannister", "jamie lannister", "kingslayer", false, ""},
		},
	}

	t.Log(test.title)

	for _, user := range test.users {
		if _, err = CreateUser(c, user.email, user.username, user.name, user.alias, user.isAdmin, user.auth); err != nil {
			t.Errorf("Error: %v", err)
		}
	}

	var got []*User
	if got = FindAllUsers(c); got == nil {
		t.Errorf("Error: users not found")
	}

	if len(got) != len(test.users) {
		t.Errorf("Error: want users count == %d, got %d", len(test.users), len(got))
	}

	for i, user := range test.users {
		if err = checkUser(got[i], user); err != nil {
			t.Errorf("test %v - Error: %v", i, err)
		}
	}
}

func checkUser(got *User, want testUser) error {
	var s string
	if got.Email != want.email {
		s = fmt.Sprintf("want Email == %s, got %s", want.email, got.Email)
	} else if got.Username != want.username {
		s = fmt.Sprintf("want Username == %s, got %s", want.username, got.Username)
	} else if got.Name != want.name {
		s = fmt.Sprintf("want Name == %s, got %s", want.name, got.Name)
	} else if got.Alias != want.alias {
		s = fmt.Sprintf("want Name == %s, got %s", want.alias, got.Alias)
	} else if got.IsAdmin != want.isAdmin {
		s = fmt.Sprintf("want isAdmin == %t, got %t", want.isAdmin, got.IsAdmin)
	} else if got.Auth != want.auth {
		s = fmt.Sprintf("want auth == %s, got %s", want.auth, got.Auth)
	} else {
		return nil
	}
	return errors.New(s)
}

func checkUserInvertedIndex(t *testing.T, c aetest.Context, got *User) error {

	var ids []int64
	var err error
	words := helpers.SetOfStrings("john")
	if ids, err = GetUserInvertedIndexes(c, words); err != nil {
		s := fmt.Sprintf("failed calling GetUserInvertedIndexes %v", err)
		return errors.New(s)
	}
	for _, id := range ids {
		if id == got.Id {
			return nil
		}
	}

	return errors.New("user not found")

}

// errorStringRepresentation returns the string representation of an error.
func errorStringRepresentation(err error) string {
	if err != nil {
		return err.Error()
	}
	return ""
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"strings"
)

// A string array option capable of being appended to.
type stringsOpt []string

func (strs *stringsOpt) String() string {
	return strings.Join(*strs, ",")
}

func (strs *stringsOpt) Set(value string) error {
	*strs = append(*strs, strings.Split(value, ",")...)
	return nil
}

type Options struct {
	Config    string
	Exec      []string
	Etcd      []string
	LogTarget string
	LogLevel  string
}

// Parse commandline options. Exit on failure.
func ParseOptionsOrExit(args []string) *Options {
	var config string
	var exec stringsOpt
	var etcd stringsOpt
	var logTarget string
	var logLevel string

	flags := flag.NewFlagSet(args[0], flag.ExitOnError)
	flags.StringVar(&config, "config", "config.yml", "YAML configuration file.")
	flags.Var(&exec, "exec", "Execute a watcher and exit. May be provided multiple times.")
	flags.Var(&etcd, "etcd", "The URI of etcd. May be provided multiple times.")
	flags.StringVar(&logTarget, "log-target", "stderr", "The target to log to.")
	flags.StringVar(&logLevel, "log-level", "info", "The level of logs to log.")
	flags.Parse(args[1:])

	return &Options{
		Config:    config,
		Exec:      []string(exec),
		Etcd:      []string(etcd),
		LogTarget: logTarget,
		LogLevel:  logLevel,
	}
}
<commit_msg>Add prefix to cli options.<commit_after>package main

import (
	"flag"
	"strings"
)

// A string array option capable of being appended to.
type stringsOpt []string

func (strs *stringsOpt) String() string {
	return strings.Join(*strs, ",")
}

func (strs *stringsOpt) Set(value string) error {
	*strs = append(*strs, strings.Split(value, ",")...)
	return nil
}

// Store values retrieved from the cli.
type Options struct {
	Config    string
	Exec      []string
	Etcd      []string
	Prefix    string
	LogTarget string
	LogLevel  string
}

// Parse cli options. Exit on failure.
func ParseOptionsOrExit(args []string) *Options {
	var config string
	var exec stringsOpt
	var etcd stringsOpt
	var prefix string
	var logTarget string
	var logLevel string

	flags := flag.NewFlagSet(args[0], flag.ExitOnError)
	flags.StringVar(&config, "config", "config.yml", "YAML configuration file.")
	flags.Var(&exec, "exec", "Execute a watcher and exit. May be provided multiple times.")
	flags.Var(&etcd, "etcd", "The URI of etcd. May be provided multiple times.")
	flags.StringVar(&prefix, "prefix", "", "A prefix to prepend to all key paths.")
	flags.StringVar(&logTarget, "log-target", "stderr", "The target to log to.")
	flags.StringVar(&logLevel, "log-level", "info", "The level of logs to log.")
	flags.Parse(args[1:])

	return &Options{
		Config:    config,
		Exec:      []string(exec),
		Etcd:      []string(etcd),
		LogTarget: logTarget,
		LogLevel:  logLevel,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

var cmdPullRequest = &Command{
	Run:   pullRequest,
	Usage: "pull-request [-f] [TITLE|-i ISSUE] [-b BASE] [-h HEAD]",
	Short: "Open a pull request on GitHub",
	Long: `Opens a pull request on GitHub for the project that the "origin" remote
points to. The default head of the pull request is the current branch.
Both base and head of the pull request can be explicitly given in one of
the following formats: "branch", "owner:branch", "owner/repo:branch".
This command will abort operation if it detects that the current topic
branch has local commits that are not yet pushed to its upstream branch
on the remote. To skip this check, use -f.

If TITLE is omitted, a text editor will open in which title and body of
the pull request can be entered in the same manner as git commit message.

If instead of normal TITLE an issue number is given with -i, the pull
request will be attached to an existing GitHub issue. Alternatively, instead
of title you can paste a full URL to an issue on GitHub.
`,
}

var flagPullRequestBase, flagPullRequestHead string

func init() {
	// TODO: delay calculation of owner and current branch until being used
	cmdPullRequest.Flag.StringVar(&flagPullRequestBase, "b", git.Owner()+":master", "BASE")
	cmdPullRequest.Flag.StringVar(&flagPullRequestHead, "h", git.Owner()+":"+git.CurrentBranch(), "HEAD")
}

func pullRequest(cmd *Command, args []string) {
	messageFile := filepath.Join(git.Dir(), "PULLREQ_EDITMSG")

	writePullRequestChanges(messageFile, flagPullRequestBase, flagPullRequestHead)

	editCmd := buildEditCommand(messageFile)
	err := execCmd(editCmd)
	if err != nil {
		log.Fatal(err)
	}

	title, body, err := readTitleAndBodyFromFile(messageFile)
	if err != nil {
		log.Fatal(err)
	}
	if len(title) == 0 {
		log.Fatal("Aborting due to empty pull request title")
	}

	params := PullRequestParams{title, body, flagPullRequestBase, flagPullRequestHead}
	err = gh.CreatePullRequest(git.Owner(), git.Repo(), params)
	if err != nil {
		log.Fatal(err)
	}
}

func writePullRequestChanges(messageFile, base, head string) {
	message := `
# Requesting a pull to %s from %s
#
# Write a message for this pull reuqest. The first block
# of the text is the title and the rest is description.
#
# Changes:
#
%s
`
	startRegexp := regexp.MustCompilePOSIX("^")
	endRegexp := regexp.MustCompilePOSIX(" +$")

	commitLogs := git.CommitLogs("master", "pull_request")
	commitLogs = strings.TrimSpace(commitLogs)
	commitLogs = startRegexp.ReplaceAllString(commitLogs, "# ")
	commitLogs = endRegexp.ReplaceAllString(commitLogs, "")

	message = fmt.Sprintf(message, base, head, commitLogs)
	err := ioutil.WriteFile(messageFile, []byte(message), 0644)
	if err != nil {
		log.Fatal(err)
	}
}

func buildEditCommand(messageFile string) []string {
	editCmd := make([]string, 0)
	gitEditor := git.Editor()
	editCmd = append(editCmd, gitEditor)
	r := regexp.MustCompile("^[mg]?vim$")
	if r.MatchString(gitEditor) {
		editCmd = append(editCmd, "-c")
		editCmd = append(editCmd, "set ft=gitcommit")
	}
	editCmd = append(editCmd, messageFile)

	return editCmd
}

func execCmd(command []string) error {
	cmd := exec.Command(command[0], command[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	err := cmd.Run()
	return err
}

func readTitleAndBodyFromFile(messageFile string) (title, body string, err error) {
	f, err := os.Open(messageFile)
	defer f.Close()
	if err != nil {
		return "", "", err
	}

	reader := bufio.NewReader(f)
	return readTitleAndBody(reader)
}

func readTitleAndBody(reader *bufio.Reader) (title, body string, err error) {
	r := regexp.MustCompile("\\S")
	var titleParts, bodyParts []string

	line, err := readln(reader)
	for err == nil {
		if strings.HasPrefix(line, "#") {
			break
		}
		if len(bodyParts) == 0 && r.MatchString(line) {
			titleParts = append(titleParts, line)
		} else {
			bodyParts = append(bodyParts, line)
		}
		line, err = readln(reader)
	}

	title = strings.Join(titleParts, " ")
	title = strings.TrimSpace(title)

	body = strings.Join(bodyParts, "\n")
	body = strings.TrimSpace(body)

	return title, body, nil
}

func readln(r *bufio.Reader) (string, error) {
	var (
		isPrefix bool  = true
		err      error = nil
		line, ln []byte
	)
	for isPrefix && err == nil {
		line, isPrefix, err = r.ReadLine()
		ln = append(ln, line...)
	}
	return string(ln), err
}
<commit_msg>Use pass-in base and head<commit_after>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

var cmdPullRequest = &Command{
	Run:   pullRequest,
	Usage: "pull-request [-f] [TITLE|-i ISSUE] [-b BASE] [-h HEAD]",
	Short: "Open a pull request on GitHub",
	Long: `Opens a pull request on GitHub for the project that the "origin" remote
points to. The default head of the pull request is the current branch.
Both base and head of the pull request can be explicitly given in one of
the following formats: "branch", "owner:branch", "owner/repo:branch".
This command will abort operation if it detects that the current topic
branch has local commits that are not yet pushed to its upstream branch
on the remote. To skip this check, use -f.

If TITLE is omitted, a text editor will open in which title and body of
the pull request can be entered in the same manner as git commit message.

If instead of normal TITLE an issue number is given with -i, the pull
request will be attached to an existing GitHub issue. Alternatively, instead
of title you can paste a full URL to an issue on GitHub.
`,
}

var flagPullRequestBase, flagPullRequestHead string

func init() {
	// TODO: delay calculation of owner and current branch until being used
	cmdPullRequest.Flag.StringVar(&flagPullRequestBase, "b", git.Owner()+":master", "BASE")
	cmdPullRequest.Flag.StringVar(&flagPullRequestHead, "h", git.Owner()+":"+git.CurrentBranch(), "HEAD")
}

func pullRequest(cmd *Command, args []string) {
	messageFile := filepath.Join(git.Dir(), "PULLREQ_EDITMSG")

	err := writePullRequestChanges(messageFile, flagPullRequestBase, flagPullRequestHead)
	if err != nil {
		log.Fatal(err)
	}

	editCmd := buildEditCommand(messageFile)
	err = execCmd(editCmd)
	if err != nil {
		log.Fatal(err)
	}

	title, body, err := readTitleAndBodyFromFile(messageFile)
	if err != nil {
		log.Fatal(err)
	}
	if len(title) == 0 {
		log.Fatal("Aborting due to empty pull request title")
	}

	params := PullRequestParams{title, body, flagPullRequestBase, flagPullRequestHead}
	err = gh.CreatePullRequest(git.Owner(), git.Repo(), params)
	if err != nil {
		log.Fatal(err)
	}
}

func writePullRequestChanges(messageFile, base, head string) error {
	message := `
# Requesting a pull to %s from %s
#
# Write a message for this pull reuqest. The first block
# of the text is the title and the rest is description.
#
# Changes:
#
%s
`
	startRegexp := regexp.MustCompilePOSIX("^")
	endRegexp := regexp.MustCompilePOSIX(" +$")

	commitLogs := git.CommitLogs(getLocalBranch(base), getLocalBranch(head))
	commitLogs = strings.TrimSpace(commitLogs)
	commitLogs = startRegexp.ReplaceAllString(commitLogs, "# ")
	commitLogs = endRegexp.ReplaceAllString(commitLogs, "")

	message = fmt.Sprintf(message, base, head, commitLogs)

	return ioutil.WriteFile(messageFile, []byte(message), 0644)
}

func getLocalBranch(branchName string) string {
	result := strings.Split(branchName, ":")
	return result[len(result)-1]
}

func buildEditCommand(messageFile string) []string {
	editCmd := make([]string, 0)
	gitEditor := git.Editor()
	editCmd = append(editCmd, gitEditor)
	r := regexp.MustCompile("^[mg]?vim$")
	if r.MatchString(gitEditor) {
		editCmd = append(editCmd, "-c")
		editCmd = append(editCmd, "set ft=gitcommit")
	}
	editCmd = append(editCmd, messageFile)

	return editCmd
}

func execCmd(command []string) error {
	cmd := exec.Command(command[0], command[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	err := cmd.Run()
	return err
}

func readTitleAndBodyFromFile(messageFile string) (title, body string, err error) {
	f, err := os.Open(messageFile)
	defer f.Close()
	if err != nil {
		return "", "", err
	}

	reader := bufio.NewReader(f)
	return readTitleAndBody(reader)
}

func readTitleAndBody(reader *bufio.Reader) (title, body string, err error) {
	r := regexp.MustCompile("\\S")
	var titleParts, bodyParts []string

	line, err := readln(reader)
	for err == nil {
		if strings.HasPrefix(line, "#") {
			break
		}
		if len(bodyParts) == 0 && r.MatchString(line) {
			titleParts = append(titleParts, line)
		} else {
			bodyParts = append(bodyParts, line)
		}
		line, err = readln(reader)
	}

	title = strings.Join(titleParts, " ")
	title = strings.TrimSpace(title)

	body = strings.Join(bodyParts, "\n")
	body = strings.TrimSpace(body)

	return title, body, nil
}

func readln(r *bufio.Reader) (string, error) {
	var (
		isPrefix bool  = true
		err      error = nil
		line, ln []byte
	)
	for isPrefix && err == nil {
		line, isPrefix, err = r.ReadLine()
		ln = append(ln, line...)
	}
	return string(ln), err
}
<|endoftext|>


<commit_before>// Exception objects

package py

import (
	"fmt"
	"io"
)

// A python Exception object
type Exception struct {
	Base            *Type
	Args            Object
	Traceback       Object
	Context         Object
	Cause           Object
	SuppressContext bool
	Other           StringDict // anything else that we want to stuff in
}

// A python exception info block
type ExceptionInfo struct {
	Type      *Type
	Value     Object
	Traceback *Traceback
}

// Make Exception info statisfy the error interface

var (
	// Exception heirachy
	BaseException             = ObjectType.NewTypeFlags("BaseException", "Common base class for all exceptions", ExceptionNew, nil, ObjectType.Flags|TPFLAGS_BASE_EXC_SUBCLASS)
	SystemExit                = BaseException.NewType("SystemExit", "Request to exit from the interpreter.", nil, nil)
	KeyboardInterrupt         = BaseException.NewType("KeyboardInterrupt", "Program interrupted by user.", nil, nil)
	GeneratorExit             = BaseException.NewType("GeneratorExit", "Request that a generator exit.", nil, nil)
	ExceptionType             = BaseException.NewType("Exception", "Common base class for all non-exit exceptions.", nil, nil)
	StopIteration             = ExceptionType.NewType("StopIteration", "Signal the end from iterator.__next__().", nil, nil)
	ArithmeticError           = ExceptionType.NewType("ArithmeticError", "Base class for arithmetic errors.", nil, nil)
	FloatingPointError        = ArithmeticError.NewType("FloatingPointError", "Floating point operation failed.", nil, nil)
	OverflowError             = ArithmeticError.NewType("OverflowError", "Result too large to be represented.", nil, nil)
	ZeroDivisionError         = ArithmeticError.NewType("ZeroDivisionError", "Second argument to a division or modulo operation was zero.", nil, nil)
	AssertionError            = ExceptionType.NewType("AssertionError", "Assertion failed.", nil, nil)
	AttributeError            = ExceptionType.NewType("AttributeError", "Attribute not found.", nil, nil)
	BufferError               = ExceptionType.NewType("BufferError", "Buffer error.", nil, nil)
	EOFError                  = ExceptionType.NewType("EOFError", "Read beyond end of file.", nil, nil)
	ImportError               = ExceptionType.NewType("ImportError", "Import can't find module, or can't find name in module.", nil, nil)
	LookupError               = ExceptionType.NewType("LookupError", "Base class for lookup errors.", nil, nil)
	IndexError                = LookupError.NewType("IndexError", "Sequence index out of range.", nil, nil)
	KeyError                  = LookupError.NewType("KeyError", "Mapping key not found.", nil, nil)
	MemoryError               = ExceptionType.NewType("MemoryError", "Out of memory.", nil, nil)
	NameError                 = ExceptionType.NewType("NameError", "Name not found globally.", nil, nil)
	UnboundLocalError         = NameError.NewType("UnboundLocalError", "Local name referenced but not bound to a value.", nil, nil)
	OSError                   = ExceptionType.NewType("OSError", "Base class for I/O related errors.", nil, nil)
	BlockingIOError           = OSError.NewType("BlockingIOError", "I/O operation would block.", nil, nil)
	ChildProcessError         = OSError.NewType("ChildProcessError", "Child process error.", nil, nil)
	ConnectionError           = OSError.NewType("ConnectionError", "Connection error.", nil, nil)
	BrokenPipeError           = ConnectionError.NewType("BrokenPipeError", "Broken pipe.", nil, nil)
	ConnectionAbortedError    = ConnectionError.NewType("ConnectionAbortedError", "Connection aborted.", nil, nil)
	ConnectionRefusedError    = ConnectionError.NewType("ConnectionRefusedError", "Connection refused.", nil, nil)
	ConnectionResetError      = ConnectionError.NewType("ConnectionResetError", "Connection reset.", nil, nil)
	FileExistsError           = OSError.NewType("FileExistsError", "File already exists.", nil, nil)
	FileNotFoundError         = OSError.NewType("FileNotFoundError", "File not found.", nil, nil)
	InterruptedError          = OSError.NewType("InterruptedError", "Interrupted by signal.", nil, nil)
	IsADirectoryError         = OSError.NewType("IsADirectoryError", "Operation doesn't work on directories.", nil, nil)
	NotADirectoryError        = OSError.NewType("NotADirectoryError", "Operation only works on directories.", nil, nil)
	PermissionError           = OSError.NewType("PermissionError", "Not enough permissions.", nil, nil)
	ProcessLookupError        = OSError.NewType("ProcessLookupError", "Process not found.", nil, nil)
	TimeoutError              = OSError.NewType("TimeoutError", "Timeout expired.", nil, nil)
	ReferenceError            = ExceptionType.NewType("ReferenceError", "Weak ref proxy used after referent went away.", nil, nil)
	RuntimeError              = ExceptionType.NewType("RuntimeError", "Unspecified run-time error.", nil, nil)
	NotImplementedError       = RuntimeError.NewType("NotImplementedError", "Method or function hasn't been implemented yet.", nil, nil)
	SyntaxError               = ExceptionType.NewType("SyntaxError", "Invalid syntax.", nil, nil)
	IndentationError          = SyntaxError.NewType("IndentationError", "Improper indentation.", nil, nil)
	TabError                  = IndentationError.NewType("TabError", "Improper mixture of spaces and tabs.", nil, nil)
	SystemError               = ExceptionType.NewType("SystemError", "Internal error in the Gpython interpreter.\n\nPlease report this to the Gpython maintainer, along with the traceback,\nthe Gpython version, and the hardware/OS platform and version.", nil, nil)
	TypeError                 = ExceptionType.NewType("TypeError", "Inappropriate argument type.", nil, nil)
	ValueError                = ExceptionType.NewType("ValueError", "Inappropriate argument value (of correct type).", nil, nil)
	UnicodeError              = ValueError.NewType("UnicodeError", "Unicode related error.", nil, nil)
	UnicodeDecodeError        = UnicodeError.NewType("UnicodeDecodeError", "Unicode decoding error.", nil, nil)
	UnicodeEncodeError        = UnicodeError.NewType("UnicodeEncodeError", "Unicode encoding error.", nil, nil)
	UnicodeTranslateError     = UnicodeError.NewType("UnicodeTranslateError", "Unicode translation error.", nil, nil)
	Warning                   = ExceptionType.NewType("Warning", "Base class for warning categories.", nil, nil)
	DeprecationWarning        = Warning.NewType("DeprecationWarning", "Base class for warnings about deprecated features.", nil, nil)
	PendingDeprecationWarning = Warning.NewType("PendingDeprecationWarning", "Base class for warnings about features which will be deprecated\nin the future.", nil, nil)
	RuntimeWarning            = Warning.NewType("RuntimeWarning", "Base class for warnings about dubious runtime behavior.", nil, nil)
	SyntaxWarning             = Warning.NewType("SyntaxWarning", "Base class for warnings about dubious syntax.", nil, nil)
	UserWarning               = Warning.NewType("UserWarning", "Base class for warnings generated by user code.", nil, nil)
	FutureWarning             = Warning.NewType("FutureWarning", "Base class for warnings about constructs that will change semantically\nin the future.", nil, nil)
	ImportWarning             = Warning.NewType("ImportWarning", "Base class for warnings about probable mistakes in module imports", nil, nil)
	UnicodeWarning            = Warning.NewType("UnicodeWarning", "Base class for warnings about Unicode related problems, mostly\nrelated to conversion problems.", nil, nil)
	BytesWarning              = Warning.NewType("BytesWarning", "Base class for warnings about bytes and buffer related problems, mostly\nrelated to conversion from str or comparing to str.", nil, nil)
	ResourceWarning           = Warning.NewType("ResourceWarning", "Base class for warnings about resource usage.", nil, nil)
	// Singleton exceptions
	NotImplemented = ExceptionNew(NotImplementedError, nil, nil)
)

// Type of this object
func (e *Exception) Type() *Type {
	return e.Base
}

// Go error interface
func (e *Exception) Error() string {
	return fmt.Sprintf("%s: %v", e.Base.Name, e.Args)
}

// Go error interface
func (e ExceptionInfo) Error() string {
	if exception, ok := e.Value.(*Exception); ok {
		return exception.Error()
	}
	return e.Value.Type().Name
}

// Dump a traceback for exc to w
func (exc *ExceptionInfo) TracebackDump(w io.Writer) {
	fmt.Fprintf(w, "Traceback (most recent call last):\n")
	exc.Traceback.TracebackDump(w)
	fmt.Fprintf(w, "%v: %v\n", exc.Type.Name, exc.Value)
}

// Test for being set
func (exc *ExceptionInfo) IsSet() bool {
	return exc.Type != nil
}

// ExceptionNew
func ExceptionNew(metatype *Type, args Tuple, kwargs StringDict) Object {
	if len(kwargs) != 0 {
		// FIXME this causes an initialization loop
		//panic(ExceptionNewf(TypeError, "%s does not take keyword arguments", metatype.Name))
		panic(fmt.Sprintf("TypeError: %s does not take keyword arguments", metatype.Name))
	}
	return &Exception{
		Base: metatype,
		Args: args.Copy(),
	}
}

// ExceptionNewf - make a new exception with fmt parameters
func ExceptionNewf(metatype *Type, format string, a ...interface{}) *Exception {
	message := fmt.Sprintf(format, a...)
	return &Exception{
		Base: metatype,
		Args: Tuple{String(message)},
	}
}

/*
	if py.ExceptionClassCheck(exc) {
		t = exc.(*py.Type)
		value = py.Call(exc, nil, nil)
		if value == nil {
			return exitException
		}
		if !py.ExceptionInstanceCheck(value) {
			PyErr_Format(PyExc_TypeError, "calling %s should have returned an instance of BaseException, not %s", t.Name, value.Type().Name)
			return exitException
		}
	} else if t = py.ExceptionInstanceCheck(exc); t != nil {
		value = exc
	} else {
		// Not something you can raise.  You get an exception
		// anyway, just not what you specified :-)
		PyErr_SetString(PyExc_TypeError, "exceptions must derive from BaseException")
		return exitException
	}
*/

// Coerce an object into an exception instance one way or another
func MakeException(r interface{}) *Exception {
	switch x := r.(type) {
	case *Exception:
		return x
	case *Type:
		if x.Flags&TPFLAGS_BASE_EXC_SUBCLASS != 0 {
			return ExceptionNew(x, nil, nil).(*Exception)
		} else {
			return ExceptionNewf(TypeError, "exceptions must derive from BaseException")
		}
	case error:
		return ExceptionNew(SystemError, Tuple{String(x.Error())}, nil).(*Exception)
	case string:
		return ExceptionNew(SystemError, Tuple{String(x)}, nil).(*Exception)
	default:
		return ExceptionNew(SystemError, Tuple{String(fmt.Sprintf("Unknown error %#v", r))}, nil).(*Exception)
	}
}

/*
#define PyType_HasFeature(t,f)  (((t)->tp_flags & (f)) != 0)

#define PyType_FastSubclass(t,f)  PyType_HasFeature(t,f)

#define PyType_Check(op) \
    PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TYPE_SUBCLASS)

#define PyType_CheckExact(op) (Py_TYPE(op) == &PyType_Type)

#define PyExceptionClass_Check(x)                                       \
    (PyType_Check((x)) &&                                               \
     PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS))

#define PyExceptionInstance_Check(x)                    \
    PyType_FastSubclass((x)->ob_type, Py_TPFLAGS_BASE_EXC_SUBCLASS)

#define PyExceptionClass_Name(x) \
     ((char *)(((PyTypeObject*)(x))->tp_name))

#define PyExceptionInstance_Class(x) ((PyObject*)((x)->ob_type))
*/

// Checks that the object passed in is a class and is an exception
func ExceptionClassCheck(err Object) bool {
	if t, ok := err.(*Type); ok {
		// FIXME not telling instances and classes apart
		// properly! This could be an instance of something
		// here
		return t.Flags&TPFLAGS_BASE_EXC_SUBCLASS != 0
	}
	return false
}

// Check to see if err matches exc
//
// exc can be a tuple
//
// Used in except statements
func ExceptionGivenMatches(err, exc Object) bool {
	if err == nil || exc == nil {
		// maybe caused by "import exceptions" that failed early on
		return false
	}

	// Test the tuple case recursively
	if excTuple, ok := exc.(Tuple); ok {
		for i := range excTuple {
			if ExceptionGivenMatches(err, excTuple[i]) {
				return true
			}
		}
		return false
	}

	// err might be an instance, so check its class.
	if exception, ok := err.(*Exception); ok {
		err = exception.Type()
	}

	if ExceptionClassCheck(err) && ExceptionClassCheck(exc) {
		res := false
		// PyObject *exception, *value, *tb;
		// PyErr_Fetch(&exception, &value, &tb);

		// PyObject_IsSubclass() can recurse and therefore is
		// not safe (see test_bad_getattr in test.pickletester).
		res = err.(*Type).IsSubtype(exc.(*Type))
		// This function must not fail, so print the error here
		// if (res == -1) {
		// 	PyErr_WriteUnraisable(err);
		// 	res = false
		// }
		// PyErr_Restore(exception, value, tb);
		return res
	}

	return err == exc
}

// IsException matches the result of recover to an exception
//
// For use to catch a single python exception from go code
//
// It can be an instance or the class itself
func IsException(exception *Type, r interface{}) bool {
	var t *Type
	switch ex := r.(type) {
	case *Exception:
		t = ex.Type()
	case *Type:
		t = ex
	default:
		return false
	}
	// Exact instance or subclass match
	if t == exception {
		return true
	}
	// Can't be a subclass of exception
	if t.Flags&TPFLAGS_BASE_EXC_SUBCLASS == 0 {
		return false
	}
	// Now the full match
	return t.IsSubtype(exception)
}

// Check Interfaces
var _ error = (*Exception)(nil)
var _ error = (*ExceptionInfo)(nil)
<commit_msg>py: ExceptionInfo - check for nil<commit_after>// Exception objects

package py

import (
	"fmt"
	"io"
)

// A python Exception object
type Exception struct {
	Base            *Type
	Args            Object
	Traceback       Object
	Context         Object
	Cause           Object
	SuppressContext bool
	Other           StringDict // anything else that we want to stuff in
}

// A python exception info block
type ExceptionInfo struct {
	Type      *Type
	Value     Object
	Traceback *Traceback
}

// Make Exception info statisfy the error interface

var (
	// Exception heirachy
	BaseException             = ObjectType.NewTypeFlags("BaseException", "Common base class for all exceptions", ExceptionNew, nil, ObjectType.Flags|TPFLAGS_BASE_EXC_SUBCLASS)
	SystemExit                = BaseException.NewType("SystemExit", "Request to exit from the interpreter.", nil, nil)
	KeyboardInterrupt         = BaseException.NewType("KeyboardInterrupt", "Program interrupted by user.", nil, nil)
	GeneratorExit             = BaseException.NewType("GeneratorExit", "Request that a generator exit.", nil, nil)
	ExceptionType             = BaseException.NewType("Exception", "Common base class for all non-exit exceptions.", nil, nil)
	StopIteration             = ExceptionType.NewType("StopIteration", "Signal the end from iterator.__next__().", nil, nil)
	ArithmeticError           = ExceptionType.NewType("ArithmeticError", "Base class for arithmetic errors.", nil, nil)
	FloatingPointError        = ArithmeticError.NewType("FloatingPointError", "Floating point operation failed.", nil, nil)
	OverflowError             = ArithmeticError.NewType("OverflowError", "Result too large to be represented.", nil, nil)
	ZeroDivisionError         = ArithmeticError.NewType("ZeroDivisionError", "Second argument to a division or modulo operation was zero.", nil, nil)
	AssertionError            = ExceptionType.NewType("AssertionError", "Assertion failed.", nil, nil)
	AttributeError            = ExceptionType.NewType("AttributeError", "Attribute not found.", nil, nil)
	BufferError               = ExceptionType.NewType("BufferError", "Buffer error.", nil, nil)
	EOFError                  = ExceptionType.NewType("EOFError", "Read beyond end of file.", nil, nil)
	ImportError               = ExceptionType.NewType("ImportError", "Import can't find module, or can't find name in module.", nil, nil)
	LookupError               = ExceptionType.NewType("LookupError", "Base class for lookup errors.", nil, nil)
	IndexError                = LookupError.NewType("IndexError", "Sequence index out of range.", nil, nil)
	KeyError                  = LookupError.NewType("KeyError", "Mapping key not found.", nil, nil)
	MemoryError               = ExceptionType.NewType("MemoryError", "Out of memory.", nil, nil)
	NameError                 = ExceptionType.NewType("NameError", "Name not found globally.", nil, nil)
	UnboundLocalError         = NameError.NewType("UnboundLocalError", "Local name referenced but not bound to a value.", nil, nil)
	OSError                   = ExceptionType.NewType("OSError", "Base class for I/O related errors.", nil, nil)
	BlockingIOError           = OSError.NewType("BlockingIOError", "I/O operation would block.", nil, nil)
	ChildProcessError         = OSError.NewType("ChildProcessError", "Child process error.", nil, nil)
	ConnectionError           = OSError.NewType("ConnectionError", "Connection error.", nil, nil)
	BrokenPipeError           = ConnectionError.NewType("BrokenPipeError", "Broken pipe.", nil, nil)
	ConnectionAbortedError    = ConnectionError.NewType("ConnectionAbortedError", "Connection aborted.", nil, nil)
	ConnectionRefusedError    = ConnectionError.NewType("ConnectionRefusedError", "Connection refused.", nil, nil)
	ConnectionResetError      = ConnectionError.NewType("ConnectionResetError", "Connection reset.", nil, nil)
	FileExistsError           = OSError.NewType("FileExistsError", "File already exists.", nil, nil)
	FileNotFoundError         = OSError.NewType("FileNotFoundError", "File not found.", nil, nil)
	InterruptedError          = OSError.NewType("InterruptedError", "Interrupted by signal.", nil, nil)
	IsADirectoryError         = OSError.NewType("IsADirectoryError", "Operation doesn't work on directories.", nil, nil)
	NotADirectoryError        = OSError.NewType("NotADirectoryError", "Operation only works on directories.", nil, nil)
	PermissionError           = OSError.NewType("PermissionError", "Not enough permissions.", nil, nil)
	ProcessLookupError        = OSError.NewType("ProcessLookupError", "Process not found.", nil, nil)
	TimeoutError              = OSError.NewType("TimeoutError", "Timeout expired.", nil, nil)
	ReferenceError            = ExceptionType.NewType("ReferenceError", "Weak ref proxy used after referent went away.", nil, nil)
	RuntimeError              = ExceptionType.NewType("RuntimeError", "Unspecified run-time error.", nil, nil)
	NotImplementedError       = RuntimeError.NewType("NotImplementedError", "Method or function hasn't been implemented yet.", nil, nil)
	SyntaxError               = ExceptionType.NewType("SyntaxError", "Invalid syntax.", nil, nil)
	IndentationError          = SyntaxError.NewType("IndentationError", "Improper indentation.", nil, nil)
	TabError                  = IndentationError.NewType("TabError", "Improper mixture of spaces and tabs.", nil, nil)
	SystemError               = ExceptionType.NewType("SystemError", "Internal error in the Gpython interpreter.\n\nPlease report this to the Gpython maintainer, along with the traceback,\nthe Gpython version, and the hardware/OS platform and version.", nil, nil)
	TypeError                 = ExceptionType.NewType("TypeError", "Inappropriate argument type.", nil, nil)
	ValueError                = ExceptionType.NewType("ValueError", "Inappropriate argument value (of correct type).", nil, nil)
	UnicodeError              = ValueError.NewType("UnicodeError", "Unicode related error.", nil, nil)
	UnicodeDecodeError        = UnicodeError.NewType("UnicodeDecodeError", "Unicode decoding error.", nil, nil)
	UnicodeEncodeError        = UnicodeError.NewType("UnicodeEncodeError", "Unicode encoding error.", nil, nil)
	UnicodeTranslateError     = UnicodeError.NewType("UnicodeTranslateError", "Unicode translation error.", nil, nil)
	Warning                   = ExceptionType.NewType("Warning", "Base class for warning categories.", nil, nil)
	DeprecationWarning        = Warning.NewType("DeprecationWarning", "Base class for warnings about deprecated features.", nil, nil)
	PendingDeprecationWarning = Warning.NewType("PendingDeprecationWarning", "Base class for warnings about features which will be deprecated\nin the future.", nil, nil)
	RuntimeWarning            = Warning.NewType("RuntimeWarning", "Base class for warnings about dubious runtime behavior.", nil, nil)
	SyntaxWarning             = Warning.NewType("SyntaxWarning", "Base class for warnings about dubious syntax.", nil, nil)
	UserWarning               = Warning.NewType("UserWarning", "Base class for warnings generated by user code.", nil, nil)
	FutureWarning             = Warning.NewType("FutureWarning", "Base class for warnings about constructs that will change semantically\nin the future.", nil, nil)
	ImportWarning             = Warning.NewType("ImportWarning", "Base class for warnings about probable mistakes in module imports", nil, nil)
	UnicodeWarning            = Warning.NewType("UnicodeWarning", "Base class for warnings about Unicode related problems, mostly\nrelated to conversion problems.", nil, nil)
	BytesWarning              = Warning.NewType("BytesWarning", "Base class for warnings about bytes and buffer related problems, mostly\nrelated to conversion from str or comparing to str.", nil, nil)
	ResourceWarning           = Warning.NewType("ResourceWarning", "Base class for warnings about resource usage.", nil, nil)
	// Singleton exceptions
	NotImplemented = ExceptionNew(NotImplementedError, nil, nil)
)

// Type of this object
func (e *Exception) Type() *Type {
	return e.Base
}

// Go error interface
func (e *Exception) Error() string {
	return fmt.Sprintf("%s: %v", e.Base.Name, e.Args)
}

// Go error interface
func (e ExceptionInfo) Error() string {
	if e.Value == nil {
		return "ExceptionInfo{<nil>}"
	}
	if exception, ok := e.Value.(*Exception); ok {
		return exception.Error()
	}
	return e.Value.Type().Name
}

// Dump a traceback for exc to w
func (exc *ExceptionInfo) TracebackDump(w io.Writer) {
	if exc == nil {
		fmt.Fprintf(w, "Traceback <nil>\n")
		return
	}
	fmt.Fprintf(w, "Traceback (most recent call last):\n")
	exc.Traceback.TracebackDump(w)
	name := "<nil>"
	if exc.Type != nil {
		name = exc.Type.Name
	}
	fmt.Fprintf(w, "%v: %v\n", name, exc.Value)
}

// Test for being set
func (exc *ExceptionInfo) IsSet() bool {
	return exc.Type != nil
}

// ExceptionNew
func ExceptionNew(metatype *Type, args Tuple, kwargs StringDict) Object {
	if len(kwargs) != 0 {
		// FIXME this causes an initialization loop
		//panic(ExceptionNewf(TypeError, "%s does not take keyword arguments", metatype.Name))
		panic(fmt.Sprintf("TypeError: %s does not take keyword arguments", metatype.Name))
	}
	return &Exception{
		Base: metatype,
		Args: args.Copy(),
	}
}

// ExceptionNewf - make a new exception with fmt parameters
func ExceptionNewf(metatype *Type, format string, a ...interface{}) *Exception {
	message := fmt.Sprintf(format, a...)
	return &Exception{
		Base: metatype,
		Args: Tuple{String(message)},
	}
}

/*
	if py.ExceptionClassCheck(exc) {
		t = exc.(*py.Type)
		value = py.Call(exc, nil, nil)
		if value == nil {
			return exitException
		}
		if !py.ExceptionInstanceCheck(value) {
			PyErr_Format(PyExc_TypeError, "calling %s should have returned an instance of BaseException, not %s", t.Name, value.Type().Name)
			return exitException
		}
	} else if t = py.ExceptionInstanceCheck(exc); t != nil {
		value = exc
	} else {
		// Not something you can raise.  You get an exception
		// anyway, just not what you specified :-)
		PyErr_SetString(PyExc_TypeError, "exceptions must derive from BaseException")
		return exitException
	}
*/

// Coerce an object into an exception instance one way or another
func MakeException(r interface{}) *Exception {
	switch x := r.(type) {
	case *Exception:
		return x
	case *Type:
		if x.Flags&TPFLAGS_BASE_EXC_SUBCLASS != 0 {
			return ExceptionNew(x, nil, nil).(*Exception)
		} else {
			return ExceptionNewf(TypeError, "exceptions must derive from BaseException")
		}
	case error:
		return ExceptionNew(SystemError, Tuple{String(x.Error())}, nil).(*Exception)
	case string:
		return ExceptionNew(SystemError, Tuple{String(x)}, nil).(*Exception)
	default:
		return ExceptionNew(SystemError, Tuple{String(fmt.Sprintf("Unknown error %#v", r))}, nil).(*Exception)
	}
}

/*
#define PyType_HasFeature(t,f)  (((t)->tp_flags & (f)) != 0)

#define PyType_FastSubclass(t,f)  PyType_HasFeature(t,f)

#define PyType_Check(op) \
    PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TYPE_SUBCLASS)

#define PyType_CheckExact(op) (Py_TYPE(op) == &PyType_Type)

#define PyExceptionClass_Check(x)                                       \
    (PyType_Check((x)) &&                                               \
     PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS))

#define PyExceptionInstance_Check(x)                    \
    PyType_FastSubclass((x)->ob_type, Py_TPFLAGS_BASE_EXC_SUBCLASS)

#define PyExceptionClass_Name(x) \
     ((char *)(((PyTypeObject*)(x))->tp_name))

#define PyExceptionInstance_Class(x) ((PyObject*)((x)->ob_type))
*/

// Checks that the object passed in is a class and is an exception
func ExceptionClassCheck(err Object) bool {
	if t, ok := err.(*Type); ok {
		// FIXME not telling instances and classes apart
		// properly! This could be an instance of something
		// here
		return t.Flags&TPFLAGS_BASE_EXC_SUBCLASS != 0
	}
	return false
}

// Check to see if err matches exc
//
// exc can be a tuple
//
// Used in except statements
func ExceptionGivenMatches(err, exc Object) bool {
	if err == nil || exc == nil {
		// maybe caused by "import exceptions" that failed early on
		return false
	}

	// Test the tuple case recursively
	if excTuple, ok := exc.(Tuple); ok {
		for i := range excTuple {
			if ExceptionGivenMatches(err, excTuple[i]) {
				return true
			}
		}
		return false
	}

	// err might be an instance, so check its class.
	if exception, ok := err.(*Exception); ok {
		err = exception.Type()
	}

	if ExceptionClassCheck(err) && ExceptionClassCheck(exc) {
		res := false
		// PyObject *exception, *value, *tb;
		// PyErr_Fetch(&exception, &value, &tb);

		// PyObject_IsSubclass() can recurse and therefore is
		// not safe (see test_bad_getattr in test.pickletester).
		res = err.(*Type).IsSubtype(exc.(*Type))
		// This function must not fail, so print the error here
		// if (res == -1) {
		// 	PyErr_WriteUnraisable(err);
		// 	res = false
		// }
		// PyErr_Restore(exception, value, tb);
		return res
	}

	return err == exc
}

// IsException matches the result of recover to an exception
//
// For use to catch a single python exception from go code
//
// It can be an instance or the class itself
func IsException(exception *Type, r interface{}) bool {
	var t *Type
	switch ex := r.(type) {
	case *Exception:
		t = ex.Type()
	case *Type:
		t = ex
	default:
		return false
	}
	// Exact instance or subclass match
	if t == exception {
		return true
	}
	// Can't be a subclass of exception
	if t.Flags&TPFLAGS_BASE_EXC_SUBCLASS == 0 {
		return false
	}
	// Now the full match
	return t.IsSubtype(exception)
}

// Check Interfaces
var _ error = (*Exception)(nil)
var _ error = (*ExceptionInfo)(nil)
<|endoftext|>


<commit_before>package system

import (
	"os"
	"os/exec"
	"syscall"

	"fmt"

	"github.com/cloudfoundry/gunk/command_runner"
)

type NamespacingExecer struct {
	CommandRunner    command_runner.CommandRunner
	ExtraFiles       []*os.File
	Privileged       bool
	UidMappingOffset int
}

func (e *NamespacingExecer) Exec(binPath string, args ...string) (int, error) {
	cmd := exec.Command(binPath, args...)
	cmd.SysProcAttr = &syscall.SysProcAttr{}

	flags := syscall.CLONE_NEWIPC
	flags = flags | syscall.CLONE_NEWNET
	flags = flags | syscall.CLONE_NEWNS
	flags = flags | syscall.CLONE_NEWUTS
	flags = flags | syscall.CLONE_NEWPID

	if !e.Privileged {
		flags = flags | syscall.CLONE_NEWUSER

		cmd.SysProcAttr.UidMappings = []syscall.SysProcIDMap{
			{
				ContainerID: 0,
				HostID:      e.UidMappingOffset,
				Size:        65534,
			},
		}
		cmd.SysProcAttr.GidMappings = []syscall.SysProcIDMap{
			{
				ContainerID: 0,
				HostID:      e.UidMappingOffset,
				Size:        65545,
			},
		}

		cmd.SysProcAttr.Credential = &syscall.Credential{
			Uid: 0,
			Gid: 0,
		}
	}

	cmd.SysProcAttr.Cloneflags = uintptr(flags)
	cmd.ExtraFiles = e.ExtraFiles

	if err := e.CommandRunner.Start(cmd); err != nil {
		return 0, fmt.Errorf("system: failed to start the supplied command: %s", err)
	}

	return cmd.Process.Pid, nil
}
<commit_msg>Re-instate run argument of initd.<commit_after>package system

import (
	"fmt"
	"os"
	"os/exec"
	"syscall"

	"github.com/cloudfoundry/gunk/command_runner"
)

type NamespacingExecer struct {
	CommandRunner    command_runner.CommandRunner
	ExtraFiles       []*os.File
	Privileged       bool
	UidMappingOffset int
}

func (e *NamespacingExecer) Exec(binPath string, args ...string) (int, error) {
	cmd := exec.Command(binPath, args...)
	cmd.SysProcAttr = &syscall.SysProcAttr{}

	flags := syscall.CLONE_NEWIPC
	flags = flags | syscall.CLONE_NEWNET
	flags = flags | syscall.CLONE_NEWNS
	flags = flags | syscall.CLONE_NEWUTS
	flags = flags | syscall.CLONE_NEWPID

	if !e.Privileged {
		flags = flags | syscall.CLONE_NEWUSER

		cmd.SysProcAttr.UidMappings = []syscall.SysProcIDMap{
			{
				ContainerID: 0,
				HostID:      e.UidMappingOffset,
				Size:        65534,
			},
		}
		cmd.SysProcAttr.GidMappings = []syscall.SysProcIDMap{
			{
				ContainerID: 0,
				HostID:      e.UidMappingOffset,
				Size:        65545,
			},
		}

		cmd.SysProcAttr.Credential = &syscall.Credential{
			Uid: 0,
			Gid: 0,
		}
	}

	cmd.SysProcAttr.Cloneflags = uintptr(flags)
	cmd.ExtraFiles = e.ExtraFiles

	if err := e.CommandRunner.Start(cmd); err != nil {
		return 0, fmt.Errorf("system: failed to start the supplied command: %s", err)
	}

	return cmd.Process.Pid, nil
}
<|endoftext|>


<commit_before>package handlers_test

import (
	"bytes"
	"encoding/json"
	"errors"
	"net/http"
	"net/http/httptest"
	"net/url"

	"github.com/cloudfoundry-incubator/bbs/fake_bbs"
	"github.com/cloudfoundry-incubator/bbs/models"
	"github.com/cloudfoundry-incubator/runtime-schema/cc_messages"
	"github.com/cloudfoundry-incubator/stager/backend"
	"github.com/cloudfoundry-incubator/stager/backend/fake_backend"
	"github.com/cloudfoundry-incubator/stager/cc_client/fakes"
	"github.com/cloudfoundry-incubator/stager/handlers"
	fake_metric_sender "github.com/cloudfoundry/dropsonde/metric_sender/fake"
	"github.com/cloudfoundry/dropsonde/metrics"
	"github.com/pivotal-golang/lager"
	"github.com/pivotal-golang/lager/lagertest"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("StagingHandler", func() {

	var (
		fakeMetricSender *fake_metric_sender.FakeMetricSender

		logger          lager.Logger
		fakeDiegoClient *fake_bbs.FakeClient
		fakeCcClient    *fakes.FakeCcClient
		fakeBackend     *fake_backend.FakeBackend

		responseRecorder *httptest.ResponseRecorder
		handler          handlers.StagingHandler
	)

	BeforeEach(func() {
		logger = lagertest.NewTestLogger("test")

		fakeMetricSender = fake_metric_sender.NewFakeMetricSender()
		metrics.Initialize(fakeMetricSender, nil)

		fakeCcClient = &fakes.FakeCcClient{}

		fakeBackend = &fake_backend.FakeBackend{}
		fakeBackend.BuildRecipeReturns(&models.TaskDefinition{}, "", "", nil)

		fakeDiegoClient = &fake_bbs.FakeClient{}

		responseRecorder = httptest.NewRecorder()
		handler = handlers.NewStagingHandler(logger, map[string]backend.Backend{"fake-backend": fakeBackend}, fakeCcClient, fakeDiegoClient)
	})

	Describe("Stage", func() {
		var (
			stagingRequestJson []byte
		)

		JustBeforeEach(func() {
			req, err := http.NewRequest("PUT", "/v1/staging/a-staging-guid", bytes.NewReader(stagingRequestJson))
			Expect(err).NotTo(HaveOccurred())

			req.Form = url.Values{":staging_guid": {"a-staging-guid"}}

			handler.Stage(responseRecorder, req)
		})

		Context("when a staging request is received for a registered backend", func() {
			var stagingRequest cc_messages.StagingRequestFromCC

			BeforeEach(func() {
				stagingRequest = cc_messages.StagingRequestFromCC{
					AppId:     "myapp",
					Lifecycle: "fake-backend",
				}

				var err error
				stagingRequestJson, err = json.Marshal(stagingRequest)
				Expect(err).NotTo(HaveOccurred())
			})

			It("increments the counter to track arriving staging messages", func() {
				Expect(fakeMetricSender.GetCounter("StagingStartRequestsReceived")).To(Equal(uint64(1)))
			})

			It("returns an Accepted response", func() {
				Expect(responseRecorder.Code).To(Equal(http.StatusAccepted))
			})

			It("builds a staging recipe", func() {
				Expect(fakeBackend.BuildRecipeCallCount()).To(Equal(1))

				guid, request := fakeBackend.BuildRecipeArgsForCall(0)
				Expect(guid).To(Equal("a-staging-guid"))
				Expect(request).To(Equal(stagingRequest))
			})

			Context("when the recipe was built successfully", func() {
				var fakeTaskDef = &models.TaskDefinition{Annotation: "test annotation"}
				BeforeEach(func() {
					fakeBackend.BuildRecipeReturns(fakeTaskDef, "a-guid", "a-domain", nil)
				})

				It("does not send a staging complete message", func() {
					Expect(fakeCcClient.StagingCompleteCallCount()).To(Equal(0))
				})

				It("creates a task on Diego", func() {
					Expect(fakeDiegoClient.DesireTaskCallCount()).To(Equal(1))
					_, _, resultingTaskDef := fakeDiegoClient.DesireTaskArgsForCall(0)
					Expect(resultingTaskDef).To(Equal(fakeTaskDef))
				})

				Context("when creating the task succeeds", func() {
					It("does not send a staging failure response", func() {
						Expect(fakeCcClient.StagingCompleteCallCount()).To(Equal(0))
					})
				})

				Context("when the task has already been created", func() {
					BeforeEach(func() {
						fakeDiegoClient.DesireTaskReturns(&models.Error{
							Type:    models.ResourceExists,
							Message: "ok, this task already exists",
						})
					})

					It("does not log a failure", func() {
						Expect(logger).NotTo(gbytes.Say("staging-failed"))
					})
				})

				Context("create task fails for any other reason", func() {
					var desireError error

					BeforeEach(func() {
						desireError = errors.New("some task create error")
						fakeDiegoClient.DesireTaskReturns(desireError)
					})

					It("logs the failure", func() {
						Expect(logger).To(gbytes.Say("staging-failed"))
					})

					It("returns an internal service error status code", func() {
						Expect(responseRecorder.Code).To(Equal(http.StatusInternalServerError))
					})

					It("should not call staging complete", func() {
						Expect(fakeCcClient.StagingCompleteCallCount()).To(Equal(0))
					})

					Context("when the response builder succeeds", func() {
						var responseForCC cc_messages.StagingResponseForCC

						BeforeEach(func() {
							responseForCC = cc_messages.StagingResponseForCC{
								Error: backend.SanitizeErrorMessage(desireError.Error()),
							}
						})

						It("returns the cloud controller error response", func() {
							var response cc_messages.StagingResponseForCC
							decoder := json.NewDecoder(responseRecorder.Body)
							err := decoder.Decode(&response)
							Expect(err).NotTo(HaveOccurred())

							Expect(response).To(Equal(responseForCC))
						})
					})
				})
			})

			Context("when the recipe failed to be built", func() {
				var buildRecipeError error

				BeforeEach(func() {
					buildRecipeError = errors.New("some build recipe error")
					fakeBackend.BuildRecipeReturns(&models.TaskDefinition{}, "", "", buildRecipeError)
				})

				It("logs the failure", func() {
					Expect(logger).To(gbytes.Say("recipe-building-failed"))
				})

				It("returns an internal service error status code", func() {
					Expect(responseRecorder.Code).To(Equal(http.StatusInternalServerError))
				})

				It("should not call staging complete", func() {
					Expect(fakeCcClient.StagingCompleteCallCount()).To(Equal(0))
				})

				Context("when the response builder succeeds", func() {
					var responseForCC cc_messages.StagingResponseForCC

					BeforeEach(func() {
						responseForCC = cc_messages.StagingResponseForCC{
							Error: backend.SanitizeErrorMessage(buildRecipeError.Error()),
						}
					})

					It("returns the cloud controller error response", func() {
						var response cc_messages.StagingResponseForCC
						decoder := json.NewDecoder(responseRecorder.Body)
						err := decoder.Decode(&response)
						Expect(err).NotTo(HaveOccurred())

						Expect(response).To(Equal(responseForCC))
					})
				})
			})
		})

		Describe("bad requests", func() {
			Context("when the request fails to unmarshal", func() {
				BeforeEach(func() {
					stagingRequestJson = []byte(`bad-json`)
				})

				It("returns bad request", func() {
					Expect(responseRecorder.Code).To(Equal(http.StatusBadRequest))
				})

				It("does not send a staging complete message", func() {
					Expect(fakeCcClient.StagingCompleteCallCount()).To(Equal(0))
				})
			})

			Context("when a staging request is received for an unknown backend", func() {
				BeforeEach(func() {
					stagingRequest := cc_messages.StagingRequestFromCC{
						AppId:     "myapp",
						Lifecycle: "unknown-backend",
					}

					var err error
					stagingRequestJson, err = json.Marshal(stagingRequest)
					Expect(err).NotTo(HaveOccurred())
				})

				It("returns a Not Found response", func() {
					Expect(responseRecorder.Code).To(Equal(http.StatusNotFound))
				})
			})

			Context("when a malformed staging request is received", func() {
				BeforeEach(func() {
					stagingRequestJson = []byte(`bogus-request`)
				})

				It("returns a BadRequest error", func() {
					Expect(responseRecorder.Code).To(Equal(http.StatusBadRequest))
				})
			})
		})
	})

	Describe("StopStaging", func() {
		BeforeEach(func() {
			stagingTask := &models.Task{
				TaskGuid:       "a-staging-guid",
				TaskDefinition: &models.TaskDefinition{Annotation: `{"lifecycle": "fake-backend"}`},
			}

			fakeDiegoClient.TaskByGuidReturns(stagingTask, nil)
		})

		JustBeforeEach(func() {
			req, err := http.NewRequest("POST", "/v1/staging/a-staging-guid", nil)
			Expect(err).NotTo(HaveOccurred())

			req.Form = url.Values{":staging_guid": {"a-staging-guid"}}

			handler.StopStaging(responseRecorder, req)
		})

		Context("when receiving a stop staging request", func() {
			It("retrieves the current staging task by guid", func() {
				Expect(fakeDiegoClient.TaskByGuidCallCount()).To(Equal(1))
				Expect(fakeDiegoClient.TaskByGuidArgsForCall(0)).To(Equal("a-staging-guid"))
			})

			Context("when an in-flight staging task is not found", func() {
				BeforeEach(func() {
					fakeDiegoClient.TaskByGuidReturns(&models.Task{}, models.ErrResourceNotFound)
				})

				It("returns StatusNotFound", func() {
					Expect(responseRecorder.Code).To(Equal(http.StatusNotFound))
				})
			})

			Context("when retrieving the current task fails", func() {
				BeforeEach(func() {
					fakeDiegoClient.TaskByGuidReturns(&models.Task{}, errors.New("boom"))
				})

				It("returns StatusInternalServerError", func() {
					Expect(responseRecorder.Code).To(Equal(http.StatusInternalServerError))
				})
			})

			Context("when retrieving the current task is sucessful", func() {
				Context("when the task annotation fails to unmarshal", func() {
					BeforeEach(func() {
						stagingTask := &models.Task{
							TaskGuid:       "a-staging-guid",
							TaskDefinition: &models.TaskDefinition{Annotation: `"fake-backend"}`},
						}

						fakeDiegoClient.TaskByGuidReturns(stagingTask, nil)
					})

					It("returns StatusInternalServerError", func() {
						Expect(responseRecorder.Code).To(Equal(http.StatusInternalServerError))
					})
				})

				It("increments the counter to track arriving stop staging messages", func() {
					Expect(fakeMetricSender.GetCounter("StagingStopRequestsReceived")).To(Equal(uint64(1)))
				})

				It("cancels the Diego task", func() {
					Expect(fakeDiegoClient.CancelTaskCallCount()).To(Equal(1))
					Expect(fakeDiegoClient.CancelTaskArgsForCall(0)).To(Equal("a-staging-guid"))
				})

				It("returns an Accepted response", func() {
					Expect(responseRecorder.Code).To(Equal(http.StatusAccepted))
				})

			})
		})
	})
})
<commit_msg>Use NewError constructor instead of creating it manually<commit_after>package handlers_test

import (
	"bytes"
	"encoding/json"
	"errors"
	"net/http"
	"net/http/httptest"
	"net/url"

	"github.com/cloudfoundry-incubator/bbs/fake_bbs"
	"github.com/cloudfoundry-incubator/bbs/models"
	"github.com/cloudfoundry-incubator/runtime-schema/cc_messages"
	"github.com/cloudfoundry-incubator/stager/backend"
	"github.com/cloudfoundry-incubator/stager/backend/fake_backend"
	"github.com/cloudfoundry-incubator/stager/cc_client/fakes"
	"github.com/cloudfoundry-incubator/stager/handlers"
	fake_metric_sender "github.com/cloudfoundry/dropsonde/metric_sender/fake"
	"github.com/cloudfoundry/dropsonde/metrics"
	"github.com/pivotal-golang/lager"
	"github.com/pivotal-golang/lager/lagertest"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("StagingHandler", func() {

	var (
		fakeMetricSender *fake_metric_sender.FakeMetricSender

		logger          lager.Logger
		fakeDiegoClient *fake_bbs.FakeClient
		fakeCcClient    *fakes.FakeCcClient
		fakeBackend     *fake_backend.FakeBackend

		responseRecorder *httptest.ResponseRecorder
		handler          handlers.StagingHandler
	)

	BeforeEach(func() {
		logger = lagertest.NewTestLogger("test")

		fakeMetricSender = fake_metric_sender.NewFakeMetricSender()
		metrics.Initialize(fakeMetricSender, nil)

		fakeCcClient = &fakes.FakeCcClient{}

		fakeBackend = &fake_backend.FakeBackend{}
		fakeBackend.BuildRecipeReturns(&models.TaskDefinition{}, "", "", nil)

		fakeDiegoClient = &fake_bbs.FakeClient{}

		responseRecorder = httptest.NewRecorder()
		handler = handlers.NewStagingHandler(logger, map[string]backend.Backend{"fake-backend": fakeBackend}, fakeCcClient, fakeDiegoClient)
	})

	Describe("Stage", func() {
		var (
			stagingRequestJson []byte
		)

		JustBeforeEach(func() {
			req, err := http.NewRequest("PUT", "/v1/staging/a-staging-guid", bytes.NewReader(stagingRequestJson))
			Expect(err).NotTo(HaveOccurred())

			req.Form = url.Values{":staging_guid": {"a-staging-guid"}}

			handler.Stage(responseRecorder, req)
		})

		Context("when a staging request is received for a registered backend", func() {
			var stagingRequest cc_messages.StagingRequestFromCC

			BeforeEach(func() {
				stagingRequest = cc_messages.StagingRequestFromCC{
					AppId:     "myapp",
					Lifecycle: "fake-backend",
				}

				var err error
				stagingRequestJson, err = json.Marshal(stagingRequest)
				Expect(err).NotTo(HaveOccurred())
			})

			It("increments the counter to track arriving staging messages", func() {
				Expect(fakeMetricSender.GetCounter("StagingStartRequestsReceived")).To(Equal(uint64(1)))
			})

			It("returns an Accepted response", func() {
				Expect(responseRecorder.Code).To(Equal(http.StatusAccepted))
			})

			It("builds a staging recipe", func() {
				Expect(fakeBackend.BuildRecipeCallCount()).To(Equal(1))

				guid, request := fakeBackend.BuildRecipeArgsForCall(0)
				Expect(guid).To(Equal("a-staging-guid"))
				Expect(request).To(Equal(stagingRequest))
			})

			Context("when the recipe was built successfully", func() {
				var fakeTaskDef = &models.TaskDefinition{Annotation: "test annotation"}
				BeforeEach(func() {
					fakeBackend.BuildRecipeReturns(fakeTaskDef, "a-guid", "a-domain", nil)
				})

				It("does not send a staging complete message", func() {
					Expect(fakeCcClient.StagingCompleteCallCount()).To(Equal(0))
				})

				It("creates a task on Diego", func() {
					Expect(fakeDiegoClient.DesireTaskCallCount()).To(Equal(1))
					_, _, resultingTaskDef := fakeDiegoClient.DesireTaskArgsForCall(0)
					Expect(resultingTaskDef).To(Equal(fakeTaskDef))
				})

				Context("when creating the task succeeds", func() {
					It("does not send a staging failure response", func() {
						Expect(fakeCcClient.StagingCompleteCallCount()).To(Equal(0))
					})
				})

				Context("when the task has already been created", func() {
					BeforeEach(func() {
						fakeDiegoClient.DesireTaskReturns(models.NewError(models.Error_ResourceExists, "ok, this task already exists"))
					})

					It("does not log a failure", func() {
						Expect(logger).NotTo(gbytes.Say("staging-failed"))
					})
				})

				Context("create task fails for any other reason", func() {
					var desireError error

					BeforeEach(func() {
						desireError = errors.New("some task create error")
						fakeDiegoClient.DesireTaskReturns(desireError)
					})

					It("logs the failure", func() {
						Expect(logger).To(gbytes.Say("staging-failed"))
					})

					It("returns an internal service error status code", func() {
						Expect(responseRecorder.Code).To(Equal(http.StatusInternalServerError))
					})

					It("should not call staging complete", func() {
						Expect(fakeCcClient.StagingCompleteCallCount()).To(Equal(0))
					})

					Context("when the response builder succeeds", func() {
						var responseForCC cc_messages.StagingResponseForCC

						BeforeEach(func() {
							responseForCC = cc_messages.StagingResponseForCC{
								Error: backend.SanitizeErrorMessage(desireError.Error()),
							}
						})

						It("returns the cloud controller error response", func() {
							var response cc_messages.StagingResponseForCC
							decoder := json.NewDecoder(responseRecorder.Body)
							err := decoder.Decode(&response)
							Expect(err).NotTo(HaveOccurred())

							Expect(response).To(Equal(responseForCC))
						})
					})
				})
			})

			Context("when the recipe failed to be built", func() {
				var buildRecipeError error

				BeforeEach(func() {
					buildRecipeError = errors.New("some build recipe error")
					fakeBackend.BuildRecipeReturns(&models.TaskDefinition{}, "", "", buildRecipeError)
				})

				It("logs the failure", func() {
					Expect(logger).To(gbytes.Say("recipe-building-failed"))
				})

				It("returns an internal service error status code", func() {
					Expect(responseRecorder.Code).To(Equal(http.StatusInternalServerError))
				})

				It("should not call staging complete", func() {
					Expect(fakeCcClient.StagingCompleteCallCount()).To(Equal(0))
				})

				Context("when the response builder succeeds", func() {
					var responseForCC cc_messages.StagingResponseForCC

					BeforeEach(func() {
						responseForCC = cc_messages.StagingResponseForCC{
							Error: backend.SanitizeErrorMessage(buildRecipeError.Error()),
						}
					})

					It("returns the cloud controller error response", func() {
						var response cc_messages.StagingResponseForCC
						decoder := json.NewDecoder(responseRecorder.Body)
						err := decoder.Decode(&response)
						Expect(err).NotTo(HaveOccurred())

						Expect(response).To(Equal(responseForCC))
					})
				})
			})
		})

		Describe("bad requests", func() {
			Context("when the request fails to unmarshal", func() {
				BeforeEach(func() {
					stagingRequestJson = []byte(`bad-json`)
				})

				It("returns bad request", func() {
					Expect(responseRecorder.Code).To(Equal(http.StatusBadRequest))
				})

				It("does not send a staging complete message", func() {
					Expect(fakeCcClient.StagingCompleteCallCount()).To(Equal(0))
				})
			})

			Context("when a staging request is received for an unknown backend", func() {
				BeforeEach(func() {
					stagingRequest := cc_messages.StagingRequestFromCC{
						AppId:     "myapp",
						Lifecycle: "unknown-backend",
					}

					var err error
					stagingRequestJson, err = json.Marshal(stagingRequest)
					Expect(err).NotTo(HaveOccurred())
				})

				It("returns a Not Found response", func() {
					Expect(responseRecorder.Code).To(Equal(http.StatusNotFound))
				})
			})

			Context("when a malformed staging request is received", func() {
				BeforeEach(func() {
					stagingRequestJson = []byte(`bogus-request`)
				})

				It("returns a BadRequest error", func() {
					Expect(responseRecorder.Code).To(Equal(http.StatusBadRequest))
				})
			})
		})
	})

	Describe("StopStaging", func() {
		BeforeEach(func() {
			stagingTask := &models.Task{
				TaskGuid:       "a-staging-guid",
				TaskDefinition: &models.TaskDefinition{Annotation: `{"lifecycle": "fake-backend"}`},
			}

			fakeDiegoClient.TaskByGuidReturns(stagingTask, nil)
		})

		JustBeforeEach(func() {
			req, err := http.NewRequest("POST", "/v1/staging/a-staging-guid", nil)
			Expect(err).NotTo(HaveOccurred())

			req.Form = url.Values{":staging_guid": {"a-staging-guid"}}

			handler.StopStaging(responseRecorder, req)
		})

		Context("when receiving a stop staging request", func() {
			It("retrieves the current staging task by guid", func() {
				Expect(fakeDiegoClient.TaskByGuidCallCount()).To(Equal(1))
				Expect(fakeDiegoClient.TaskByGuidArgsForCall(0)).To(Equal("a-staging-guid"))
			})

			Context("when an in-flight staging task is not found", func() {
				BeforeEach(func() {
					fakeDiegoClient.TaskByGuidReturns(&models.Task{}, models.ErrResourceNotFound)
				})

				It("returns StatusNotFound", func() {
					Expect(responseRecorder.Code).To(Equal(http.StatusNotFound))
				})
			})

			Context("when retrieving the current task fails", func() {
				BeforeEach(func() {
					fakeDiegoClient.TaskByGuidReturns(&models.Task{}, errors.New("boom"))
				})

				It("returns StatusInternalServerError", func() {
					Expect(responseRecorder.Code).To(Equal(http.StatusInternalServerError))
				})
			})

			Context("when retrieving the current task is sucessful", func() {
				Context("when the task annotation fails to unmarshal", func() {
					BeforeEach(func() {
						stagingTask := &models.Task{
							TaskGuid:       "a-staging-guid",
							TaskDefinition: &models.TaskDefinition{Annotation: `"fake-backend"}`},
						}

						fakeDiegoClient.TaskByGuidReturns(stagingTask, nil)
					})

					It("returns StatusInternalServerError", func() {
						Expect(responseRecorder.Code).To(Equal(http.StatusInternalServerError))
					})
				})

				It("increments the counter to track arriving stop staging messages", func() {
					Expect(fakeMetricSender.GetCounter("StagingStopRequestsReceived")).To(Equal(uint64(1)))
				})

				It("cancels the Diego task", func() {
					Expect(fakeDiegoClient.CancelTaskCallCount()).To(Equal(1))
					Expect(fakeDiegoClient.CancelTaskArgsForCall(0)).To(Equal("a-staging-guid"))
				})

				It("returns an Accepted response", func() {
					Expect(responseRecorder.Code).To(Equal(http.StatusAccepted))
				})

			})
		})
	})
})
<|endoftext|>


<commit_before>package harvester_test

import (
	"errors"

	"github.com/cloudfoundry-incubator/executor"
	"github.com/cloudfoundry-incubator/executor/fakes"
	"github.com/cloudfoundry-incubator/rep"
	. "github.com/cloudfoundry-incubator/rep/harvester"
	"github.com/cloudfoundry-incubator/runtime-schema/bbs/fake_bbs"
	"github.com/pivotal-golang/archiver/extractor/test_helper"
	"github.com/pivotal-golang/lager/lagertest"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("Task Processor", func() {
	var (
		executorClient *fakes.FakeClient
		bbs            *fake_bbs.FakeRepBBS

		taskTags = executor.Tags{rep.LifecycleTag: rep.TaskLifecycle}

		processor Processor
	)

	BeforeEach(func() {
		executorClient = new(fakes.FakeClient)
		bbs = new(fake_bbs.FakeRepBBS)

		processor = NewTaskProcessor(
			lagertest.NewTestLogger("test"),
			bbs,
			executorClient,
		)
	})

	Context("when the container state is completed", func() {
		var container executor.Container

		BeforeEach(func() {
			container = executor.Container{
				Guid:  "completed-guid",
				State: executor.StateCompleted,
				Tags:  taskTags,
			}
		})

		JustBeforeEach(func() {
			processor.Process(container)
		})

		Context("when the container completed successfully", func() {
			BeforeEach(func() {
				container.RunResult = executor.ContainerRunResult{
					Failed: false,
				}
			})

			Context("when the completed container has a result file", func() {
				BeforeEach(func() {
					container.Tags = executor.Tags{
						rep.ResultFileTag: "some-result-file",
					}
				})

				Context("and getting the result from the container succeeds", func() {
					BeforeEach(func() {
						dest := gbytes.NewBuffer()

						test_helper.WriteTar(
							dest,
							[]test_helper.ArchiveFile{{
								Name: "some-file",
								Body: "something",
								Mode: 0600,
								Dir:  false,
							}},
						)

						executorClient.GetFilesReturns(dest, nil)
					})

					It("gets the result file described by the container's metadata", func() {
						Ω(executorClient.GetFilesCallCount()).Should(Equal(1))

						guid, path := executorClient.GetFilesArgsForCall(0)
						Ω(guid).Should(Equal("completed-guid"))
						Ω(path).Should(Equal("some-result-file"))
					})

					It("completes the task successfully with the result", func() {
						Ω(bbs.CompleteTaskCallCount()).Should(Equal(1))

						taskGuid, failed, failureReason, result := bbs.CompleteTaskArgsForCall(0)
						Ω(taskGuid).Should(Equal("completed-guid"))
						Ω(failed).Should(BeFalse())
						Ω(failureReason).Should(BeEmpty())
						Ω(result).Should(Equal("something"))
					})
				})

				Context("and getting the result from the container fails", func() {
					disaster := errors.New("oh no!")

					BeforeEach(func() {
						executorClient.GetFilesReturns(nil, disaster)
					})

					It("completes the task with failure", func() {
						Ω(bbs.CompleteTaskCallCount()).Should(Equal(1))

						taskGuid, failed, failureReason, result := bbs.CompleteTaskArgsForCall(0)
						Ω(taskGuid).Should(Equal("completed-guid"))
						Ω(failed).Should(BeTrue())
						Ω(failureReason).Should(Equal("failed to fetch result: oh no!"))
						Ω(result).Should(BeEmpty())
					})
				})
			})
		})

		Context("when the container completed with failure", func() {
			BeforeEach(func() {
				container.RunResult = executor.ContainerRunResult{
					Failed:        true,
					FailureReason: "shiitake mushrooms are happening",
				}
			})

			It("completes the task with failure", func() {
				Ω(bbs.CompleteTaskCallCount()).Should(Equal(1))

				taskGuid, failed, failureReason, result := bbs.CompleteTaskArgsForCall(0)
				Ω(taskGuid).Should(Equal("completed-guid"))
				Ω(failed).Should(BeTrue())
				Ω(failureReason).Should(Equal("shiitake mushrooms are happening"))
				Ω(result).Should(BeEmpty())
			})

			It("deletes the container", func() {
				Ω(executorClient.DeleteContainerCallCount()).Should(Equal(1))
				Ω(executorClient.DeleteContainerArgsForCall(0)).Should(Equal("completed-guid"))
			})

			Context("when the completed container has a result file", func() {
				BeforeEach(func() {
					container.Tags = executor.Tags{
						rep.ResultFileTag: "some-result-file",
					}
				})

				It("does not try to fetch the result", func() {
					Ω(executorClient.GetFilesCallCount()).Should(BeZero())
				})
			})
		})
	})

	Context("when the container is not in a completed state", func() {
		var states = []executor.State{
			executor.StateReserved,
			executor.StateInitializing,
			executor.StateCreated,
			executor.StateInvalid,
		}

		BeforeEach(func() {
			for _, state := range states {
				processor.Process(executor.Container{
					Guid:  "guid",
					State: state,
					Tags:  taskTags,
				})
			}
		})

		It("skips processing the container", func() {
			Consistently(bbs.CompleteTaskCallCount).Should(Equal(0))
		})
	})
})
<commit_msg>fix error message in test<commit_after>package harvester_test

import (
	"errors"

	"github.com/cloudfoundry-incubator/executor"
	"github.com/cloudfoundry-incubator/executor/fakes"
	"github.com/cloudfoundry-incubator/rep"
	. "github.com/cloudfoundry-incubator/rep/harvester"
	"github.com/cloudfoundry-incubator/runtime-schema/bbs/fake_bbs"
	"github.com/pivotal-golang/archiver/extractor/test_helper"
	"github.com/pivotal-golang/lager/lagertest"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("Task Processor", func() {
	var (
		executorClient *fakes.FakeClient
		bbs            *fake_bbs.FakeRepBBS

		taskTags = executor.Tags{rep.LifecycleTag: rep.TaskLifecycle}

		processor Processor
	)

	BeforeEach(func() {
		executorClient = new(fakes.FakeClient)
		bbs = new(fake_bbs.FakeRepBBS)

		processor = NewTaskProcessor(
			lagertest.NewTestLogger("test"),
			bbs,
			executorClient,
		)
	})

	Context("when the container state is completed", func() {
		var container executor.Container

		BeforeEach(func() {
			container = executor.Container{
				Guid:  "completed-guid",
				State: executor.StateCompleted,
				Tags:  taskTags,
			}
		})

		JustBeforeEach(func() {
			processor.Process(container)
		})

		Context("when the container completed successfully", func() {
			BeforeEach(func() {
				container.RunResult = executor.ContainerRunResult{
					Failed: false,
				}
			})

			Context("when the completed container has a result file", func() {
				BeforeEach(func() {
					container.Tags = executor.Tags{
						rep.ResultFileTag: "some-result-file",
					}
				})

				Context("and getting the result from the container succeeds", func() {
					BeforeEach(func() {
						dest := gbytes.NewBuffer()

						test_helper.WriteTar(
							dest,
							[]test_helper.ArchiveFile{{
								Name: "some-file",
								Body: "something",
								Mode: 0600,
								Dir:  false,
							}},
						)

						executorClient.GetFilesReturns(dest, nil)
					})

					It("gets the result file described by the container's metadata", func() {
						Ω(executorClient.GetFilesCallCount()).Should(Equal(1))

						guid, path := executorClient.GetFilesArgsForCall(0)
						Ω(guid).Should(Equal("completed-guid"))
						Ω(path).Should(Equal("some-result-file"))
					})

					It("completes the task successfully with the result", func() {
						Ω(bbs.CompleteTaskCallCount()).Should(Equal(1))

						taskGuid, failed, failureReason, result := bbs.CompleteTaskArgsForCall(0)
						Ω(taskGuid).Should(Equal("completed-guid"))
						Ω(failed).Should(BeFalse())
						Ω(failureReason).Should(BeEmpty())
						Ω(result).Should(Equal("something"))
					})
				})

				Context("and getting the result from the container fails", func() {
					disaster := errors.New("oh no!")

					BeforeEach(func() {
						executorClient.GetFilesReturns(nil, disaster)
					})

					It("completes the task with failure", func() {
						Ω(bbs.CompleteTaskCallCount()).Should(Equal(1))

						taskGuid, failed, failureReason, result := bbs.CompleteTaskArgsForCall(0)
						Ω(taskGuid).Should(Equal("completed-guid"))
						Ω(failed).Should(BeTrue())
						Ω(failureReason).Should(Equal("failed to fetch result"))
						Ω(result).Should(BeEmpty())
					})
				})
			})
		})

		Context("when the container completed with failure", func() {
			BeforeEach(func() {
				container.RunResult = executor.ContainerRunResult{
					Failed:        true,
					FailureReason: "shiitake mushrooms are happening",
				}
			})

			It("completes the task with failure", func() {
				Ω(bbs.CompleteTaskCallCount()).Should(Equal(1))

				taskGuid, failed, failureReason, result := bbs.CompleteTaskArgsForCall(0)
				Ω(taskGuid).Should(Equal("completed-guid"))
				Ω(failed).Should(BeTrue())
				Ω(failureReason).Should(Equal("shiitake mushrooms are happening"))
				Ω(result).Should(BeEmpty())
			})

			It("deletes the container", func() {
				Ω(executorClient.DeleteContainerCallCount()).Should(Equal(1))
				Ω(executorClient.DeleteContainerArgsForCall(0)).Should(Equal("completed-guid"))
			})

			Context("when the completed container has a result file", func() {
				BeforeEach(func() {
					container.Tags = executor.Tags{
						rep.ResultFileTag: "some-result-file",
					}
				})

				It("does not try to fetch the result", func() {
					Ω(executorClient.GetFilesCallCount()).Should(BeZero())
				})
			})
		})
	})

	Context("when the container is not in a completed state", func() {
		var states = []executor.State{
			executor.StateReserved,
			executor.StateInitializing,
			executor.StateCreated,
			executor.StateInvalid,
		}

		BeforeEach(func() {
			for _, state := range states {
				processor.Process(executor.Container{
					Guid:  "guid",
					State: state,
					Tags:  taskTags,
				})
			}
		})

		It("skips processing the container", func() {
			Consistently(bbs.CompleteTaskCallCount).Should(Equal(0))
		})
	})
})
<|endoftext|>