<commit_before>package systests

import (
	"strings"
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/client"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/client/go/teams"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
	"github.com/stretchr/testify/require"
)

func TestTeamCreate(t *testing.T) {
	tt := newTeamTester(t)
	defer tt.cleanup()

	tt.addUser("onr")
	tt.addUser("wtr")

	team := tt.users[0].createTeam()
	tt.users[0].addTeamMember(team, tt.users[1].username, keybase1.TeamRole_WRITER)
}

func TestTeamBustCache(t *testing.T) {
	tt := newTeamTester(t)
	defer tt.cleanup()

	tt.addUser("onr")
	tt.addUser("adm")
	tt.addUser("wtr")

	team := tt.users[0].createTeam()
	tt.users[0].addTeamMember(team, tt.users[1].username, keybase1.TeamRole_ADMIN)

	before, err := GetTeamForTestByStringName(context.TODO(), tt.users[0].tc.G, team)
	require.NoError(t, err)
	beforeSeqno := before.CurrentSeqno()
	tt.users[1].addTeamMember(team, tt.users[2].username, keybase1.TeamRole_WRITER)

	// Poll for an update, we should get it as soon as gregor tells us to bust our cache.
	backoff := 100 * time.Millisecond
	found := false
	for i := 0; i < 10; i++ {
		after, err := teams.Load(context.TODO(), tt.users[0].tc.G, keybase1.LoadTeamArg{
			Name:    team,
			StaleOK: true,
		})
		require.NoError(t, err)
		if after.CurrentSeqno() > beforeSeqno {
			t.Logf("Found new seqno %d at poll loop iter %d", after.CurrentSeqno(), i)
			found = true
			break
		}
		t.Logf("Still at old generation %d at poll loop iter %d", beforeSeqno, i)
		time.Sleep(backoff)
		backoff += backoff / 2
	}
	require.True(t, found)
}

func TestTeamRotateOnRevoke(t *testing.T) {
	tt := newTeamTester(t)
	defer tt.cleanup()

	tt.addUser("onr")
	tt.addUser("wtr")

	team := tt.users[0].createTeam()
	tt.users[0].addTeamMember(team, tt.users[1].username, keybase1.TeamRole_WRITER)

	// get the before state of the team
	before, err := GetTeamForTestByStringName(context.TODO(), tt.users[0].tc.G, team)
	if err != nil {
		t.Fatal(err)
	}
	if before.Generation() != 1 {
		t.Errorf("generation before rotate: %d, expected 1", before.Generation())
	}
	secretBefore := before.Data.PerTeamKeySeeds[before.Generation()].Seed.ToBytes()

	// User1 should get a gregor that the team he was just added to changed.
	tt.users[1].waitForTeamChangedGregor(team, keybase1.Seqno(2))
	// User0 should get a (redundant) gregor notification that
	// he just changed the team.
	tt.users[0].waitForTeamChangedGregor(team, keybase1.Seqno(2))

	tt.users[1].revokePaperKey()
	tt.users[0].waitForRotate(team, keybase1.Seqno(3))

	// check that key was rotated for team
	after, err := GetTeamForTestByStringName(context.TODO(), tt.users[0].tc.G, team)
	if err != nil {
		t.Fatal(err)
	}
	if after.Generation() != 2 {
		t.Errorf("generation after rotate: %d, expected 2", after.Generation())
	}
	secretAfter := after.Data.PerTeamKeySeeds[after.Generation()].Seed.ToBytes()
	if libkb.SecureByteArrayEq(secretAfter, secretBefore) {
		t.Fatal("team secret did not change when rotated")
	}
}

type teamTester struct {
	t     *testing.T
	users []*userPlusDevice
}

func newTeamTester(t *testing.T) *teamTester {
	return &teamTester{t: t}
}

func (tt *teamTester) addUser(pre string) {
	tctx := setupTest(tt.t, pre)
	var u userPlusDevice
	u.device = &deviceWrapper{tctx: tctx}
	u.device.start(0)

	userInfo := randomUser(pre)
	tc := u.device.tctx
	g := tc.G
	signupUI := signupUI{
		info:         userInfo,
		Contextified: libkb.NewContextified(g),
	}
	g.SetUI(&signupUI)
	signup := client.NewCmdSignupRunner(g)
	signup.SetTest()
	if err := signup.Run(); err != nil {
		tt.t.Fatal(err)
	}
	tt.t.Logf("signed up %s", userInfo.username)

	u.username = userInfo.username
	u.uid = libkb.UsernameToUID(u.username)
	u.tc = tc

	cli, xp, err := client.GetRPCClientWithContext(g)
	if err != nil {
		tt.t.Fatal(err)
	}
	u.deviceClient = keybase1.DeviceClient{Cli: cli}

	// register for notifications
	u.notifications = newTeamNotifyHandler()
	srv := rpc.NewServer(xp, nil)
	if err = srv.Register(keybase1.NotifyTeamProtocol(u.notifications)); err != nil {
		tt.t.Fatal(err)
	}
	ncli := keybase1.NotifyCtlClient{Cli: cli}
	if err = ncli.SetNotifications(context.TODO(), keybase1.NotificationChannels{
		Team: true,
	}); err != nil {
		tt.t.Fatal(err)
	}

	tt.users = append(tt.users, &u)
}

func (tt *teamTester) cleanup() {
	for _, u := range tt.users {
		u.device.tctx.Cleanup()
	}
}

type userPlusDevice struct {
	uid           keybase1.UID
	username      string
	device        *deviceWrapper
	tc            *libkb.TestContext
	deviceClient  keybase1.DeviceClient
	notifications *teamNotifyHandler
}

func (u *userPlusDevice) createTeam() string {
	create := client.NewCmdTeamCreateRunner(u.tc.G)
	nameStr, err := libkb.RandString("tt", 5)
	if err != nil {
		u.tc.T.Fatal(err)
	}
	name, err := keybase1.TeamNameFromString(strings.ToLower(nameStr))
	if err != nil {
		u.tc.T.Fatal(err)
	}
	create.TeamName = name
	if err := create.Run(); err != nil {
		u.tc.T.Fatal(err)
	}
	return create.TeamName.String()
}

func (u *userPlusDevice) addTeamMember(team, username string, role keybase1.TeamRole) {
	add := client.NewCmdTeamAddMemberRunner(u.tc.G)
	add.Team = team
	add.Username = username
	add.Role = role
	add.SkipChatNotification = true // kbfs client currently required to do this...
	if err := add.Run(); err != nil {
		u.tc.T.Fatal(err)
	}
}

func (u *userPlusDevice) addTeamMemberEmail(team, email string, role keybase1.TeamRole) {
	add := client.NewCmdTeamAddMemberRunner(u.tc.G)
	add.Team = team
	add.Email = email
	add.Role = role
	add.SkipChatNotification = true // kbfs client currently required to do this...
	if err := add.Run(); err != nil {
		u.tc.T.Fatal(err)
	}
}

func (u *userPlusDevice) readInviteEmails(email string) []string {
	arg := libkb.NewAPIArg("test/team/get_tokens")
	arg.Args = libkb.NewHTTPArgs()
	arg.Args.Add("email", libkb.S{Val: email})
	res, err := u.tc.G.API.Get(arg)
	if err != nil {
		u.tc.T.Fatal(err)
	}
	tokens := res.Body.AtKey("tokens")
	n, err := tokens.Len()
	if err != nil {
		u.tc.T.Fatal(err)
	}
	if n == 0 {
		u.tc.T.Fatalf("no invite tokens for %s", email)
	}

	exp := make([]string, n)
	for i := 0; i < n; i++ {
		token, err := tokens.AtIndex(i).GetString()
		if err != nil {
			u.tc.T.Fatal(err)
		}
		exp[i] = token
	}

	return exp
}

func (u *userPlusDevice) acceptEmailInvite(token string) {
	c := client.NewCmdTeamAcceptInviteRunner(u.tc.G)
	c.Token = token
	if err := c.Run(); err != nil {
		u.tc.T.Fatal(err)
	}
}

func (u *userPlusDevice) revokePaperKey() {
	id := u.paperKeyID()

	runner := client.NewCmdDeviceRemoveRunner(u.tc.G)
	runner.SetIDOrName(id.String())
	if err := runner.Run(); err != nil {
		u.tc.T.Fatal(err)
	}
}

func (u *userPlusDevice) devices() []keybase1.Device {
	d, err := u.deviceClient.DeviceList(context.TODO(), 0)
	if err != nil {
		u.tc.T.Fatal(err)
	}
	return d
}

func (u *userPlusDevice) paperKeyID() keybase1.DeviceID {
	for _, d := range u.devices() {
		if d.Type == libkb.DeviceTypePaper {
			return d.DeviceID
		}
	}
	u.tc.T.Fatal("no paper key found")
	return keybase1.DeviceID("")
}

func (u *userPlusDevice) waitForTeamChangedGregor(team string, toSeqno keybase1.Seqno) {
	// process 10 team rotations or 10s worth of time
	for i := 0; i < 10; i++ {
		select {
		case arg := <-u.notifications.rotateCh:
			u.tc.T.Logf("membership change received: %+v", arg)
			if arg.TeamName == team && arg.Changes.MembershipChanged && !arg.Changes.KeyRotated && !arg.Changes.Renamed && arg.LatestSeqno == toSeqno {
				u.tc.T.Logf("change matched!")
				return
			}
			u.tc.T.Logf("ignoring change message (expected team = %q, seqno = %d)", team, toSeqno)
		case <-time.After(1 * time.Second):
		}
	}
	u.tc.T.Fatalf("timed out waiting for team rotate %s", team)
}

func (u *userPlusDevice) waitForRotate(team string, toSeqno keybase1.Seqno) {
	// jump start the clkr queue processing loop
	u.kickTeamRekeyd()

	// process 10 team rotations or 10s worth of time
	for i := 0; i < 10; i++ {
		select {
		case arg := <-u.notifications.rotateCh:
			u.tc.T.Logf("rotate received: %+v", arg)
			if arg.TeamName == team && arg.Changes.KeyRotated && arg.LatestSeqno == toSeqno {
				u.tc.T.Logf("rotate matched!")
				return
			}
			u.tc.T.Logf("ignoring rotate message")
		case <-time.After(1 * time.Second):
		}
	}
	u.tc.T.Fatalf("timed out waiting for team rotate %s", team)
}

func (u *userPlusDevice) prooveRooter() {
	cmd := client.NewCmdProveRooterRunner(u.tc.G, u.username)
	if err := cmd.Run(); err != nil {
		u.tc.T.Fatal(err)
	}
}

func (u *userPlusDevice) kickTeamRekeyd() {
	kickTeamRekeyd(u.tc.G, u.tc.T)
}

func kickTeamRekeyd(g *libkb.GlobalContext, t testing.TB) {
	apiArg := libkb.APIArg{
		Endpoint: "test/accelerate_team_rekeyd",
		Args: libkb.HTTPArgs{
			"timeout": libkb.I{Val: 2000},
		},
		SessionType: libkb.APISessionTypeREQUIRED,
	}

	_, err := g.API.Post(apiArg)
	if err != nil {
		t.Fatalf("Failed to accelerate team rekeyd: %s", err)
	}
}

func GetTeamForTestByStringName(ctx context.Context, g *libkb.GlobalContext, name string) (*teams.Team, error) {
	return teams.Load(ctx, g, keybase1.LoadTeamArg{
		Name:        name,
		ForceRepoll: true,
	})
}

type teamNotifyHandler struct {
	rotateCh chan keybase1.TeamChangedArg
}

func newTeamNotifyHandler() *teamNotifyHandler {
	return &teamNotifyHandler{
		rotateCh: make(chan keybase1.TeamChangedArg, 1),
	}
}

func (n *teamNotifyHandler) TeamChanged(ctx context.Context, arg keybase1.TeamChangedArg) error {
	n.rotateCh <- arg
	return nil
}

func TestGetTeamRootID(t *testing.T) {
	tt := newTeamTester(t)
	defer tt.cleanup()

	tt.addUser("onr")

	t.Logf("create a team")
	parentName, err := keybase1.TeamNameFromString(tt.users[0].createTeam())
	require.NoError(t, err)

	parentID := parentName.ToTeamID()

	t.Logf("create a subteam")
	subteamID, err := teams.CreateSubteam(context.TODO(), tt.users[0].tc.G, "mysubteam", parentName)
	require.NoError(t, err)

	subteamName, err := parentName.Append("mysubteam")

	t.Logf("create a sub-subteam")
	subteamID2, err := teams.CreateSubteam(context.TODO(), tt.users[0].tc.G, "teamofsubs", subteamName)
	require.NoError(t, err)

	getAndCompare := func(id keybase1.TeamID) {
		retID, err := teams.GetRootID(context.TODO(), tt.users[0].tc.G, id)
		require.NoError(t, err)
		require.Equal(t, parentID, retID)
	}

	getAndCompare(*subteamID)
	getAndCompare(*subteamID2)
	getAndCompare(parentID)
}
<commit_msg>Teams test: remove SkipChatNotification, does not need KBFS anymore<commit_after>package systests

import (
	"strings"
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/client"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/client/go/teams"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
	"github.com/stretchr/testify/require"
)

func TestTeamCreate(t *testing.T) {
	tt := newTeamTester(t)
	defer tt.cleanup()

	tt.addUser("onr")
	tt.addUser("wtr")

	team := tt.users[0].createTeam()
	tt.users[0].addTeamMember(team, tt.users[1].username, keybase1.TeamRole_WRITER)
}

func TestTeamBustCache(t *testing.T) {
	tt := newTeamTester(t)
	defer tt.cleanup()

	tt.addUser("onr")
	tt.addUser("adm")
	tt.addUser("wtr")

	team := tt.users[0].createTeam()
	tt.users[0].addTeamMember(team, tt.users[1].username, keybase1.TeamRole_ADMIN)

	before, err := GetTeamForTestByStringName(context.TODO(), tt.users[0].tc.G, team)
	require.NoError(t, err)
	beforeSeqno := before.CurrentSeqno()
	tt.users[1].addTeamMember(team, tt.users[2].username, keybase1.TeamRole_WRITER)

	// Poll for an update, we should get it as soon as gregor tells us to bust our cache.
	backoff := 100 * time.Millisecond
	found := false
	for i := 0; i < 10; i++ {
		after, err := teams.Load(context.TODO(), tt.users[0].tc.G, keybase1.LoadTeamArg{
			Name:    team,
			StaleOK: true,
		})
		require.NoError(t, err)
		if after.CurrentSeqno() > beforeSeqno {
			t.Logf("Found new seqno %d at poll loop iter %d", after.CurrentSeqno(), i)
			found = true
			break
		}
		t.Logf("Still at old generation %d at poll loop iter %d", beforeSeqno, i)
		time.Sleep(backoff)
		backoff += backoff / 2
	}
	require.True(t, found)
}

func TestTeamRotateOnRevoke(t *testing.T) {
	tt := newTeamTester(t)
	defer tt.cleanup()

	tt.addUser("onr")
	tt.addUser("wtr")

	team := tt.users[0].createTeam()
	tt.users[0].addTeamMember(team, tt.users[1].username, keybase1.TeamRole_WRITER)

	// get the before state of the team
	before, err := GetTeamForTestByStringName(context.TODO(), tt.users[0].tc.G, team)
	if err != nil {
		t.Fatal(err)
	}
	if before.Generation() != 1 {
		t.Errorf("generation before rotate: %d, expected 1", before.Generation())
	}
	secretBefore := before.Data.PerTeamKeySeeds[before.Generation()].Seed.ToBytes()

	// User1 should get a gregor that the team he was just added to changed.
	tt.users[1].waitForTeamChangedGregor(team, keybase1.Seqno(2))
	// User0 should get a (redundant) gregor notification that
	// he just changed the team.
	tt.users[0].waitForTeamChangedGregor(team, keybase1.Seqno(2))

	tt.users[1].revokePaperKey()
	tt.users[0].waitForRotate(team, keybase1.Seqno(3))

	// check that key was rotated for team
	after, err := GetTeamForTestByStringName(context.TODO(), tt.users[0].tc.G, team)
	if err != nil {
		t.Fatal(err)
	}
	if after.Generation() != 2 {
		t.Errorf("generation after rotate: %d, expected 2", after.Generation())
	}
	secretAfter := after.Data.PerTeamKeySeeds[after.Generation()].Seed.ToBytes()
	if libkb.SecureByteArrayEq(secretAfter, secretBefore) {
		t.Fatal("team secret did not change when rotated")
	}
}

type teamTester struct {
	t     *testing.T
	users []*userPlusDevice
}

func newTeamTester(t *testing.T) *teamTester {
	return &teamTester{t: t}
}

func (tt *teamTester) addUser(pre string) {
	tctx := setupTest(tt.t, pre)
	var u userPlusDevice
	u.device = &deviceWrapper{tctx: tctx}
	u.device.start(0)

	userInfo := randomUser(pre)
	tc := u.device.tctx
	g := tc.G
	signupUI := signupUI{
		info:         userInfo,
		Contextified: libkb.NewContextified(g),
	}
	g.SetUI(&signupUI)
	signup := client.NewCmdSignupRunner(g)
	signup.SetTest()
	if err := signup.Run(); err != nil {
		tt.t.Fatal(err)
	}
	tt.t.Logf("signed up %s", userInfo.username)

	u.username = userInfo.username
	u.uid = libkb.UsernameToUID(u.username)
	u.tc = tc

	cli, xp, err := client.GetRPCClientWithContext(g)
	if err != nil {
		tt.t.Fatal(err)
	}
	u.deviceClient = keybase1.DeviceClient{Cli: cli}

	// register for notifications
	u.notifications = newTeamNotifyHandler()
	srv := rpc.NewServer(xp, nil)
	if err = srv.Register(keybase1.NotifyTeamProtocol(u.notifications)); err != nil {
		tt.t.Fatal(err)
	}
	ncli := keybase1.NotifyCtlClient{Cli: cli}
	if err = ncli.SetNotifications(context.TODO(), keybase1.NotificationChannels{
		Team: true,
	}); err != nil {
		tt.t.Fatal(err)
	}

	tt.users = append(tt.users, &u)
}

func (tt *teamTester) cleanup() {
	for _, u := range tt.users {
		u.device.tctx.Cleanup()
	}
}

type userPlusDevice struct {
	uid           keybase1.UID
	username      string
	device        *deviceWrapper
	tc            *libkb.TestContext
	deviceClient  keybase1.DeviceClient
	notifications *teamNotifyHandler
}

func (u *userPlusDevice) createTeam() string {
	create := client.NewCmdTeamCreateRunner(u.tc.G)
	nameStr, err := libkb.RandString("tt", 5)
	if err != nil {
		u.tc.T.Fatal(err)
	}
	name, err := keybase1.TeamNameFromString(strings.ToLower(nameStr))
	if err != nil {
		u.tc.T.Fatal(err)
	}
	create.TeamName = name
	if err := create.Run(); err != nil {
		u.tc.T.Fatal(err)
	}
	return create.TeamName.String()
}

func (u *userPlusDevice) addTeamMember(team, username string, role keybase1.TeamRole) {
	add := client.NewCmdTeamAddMemberRunner(u.tc.G)
	add.Team = team
	add.Username = username
	add.Role = role
	if err := add.Run(); err != nil {
		u.tc.T.Fatal(err)
	}
}

func (u *userPlusDevice) addTeamMemberEmail(team, email string, role keybase1.TeamRole) {
	add := client.NewCmdTeamAddMemberRunner(u.tc.G)
	add.Team = team
	add.Email = email
	add.Role = role
	if err := add.Run(); err != nil {
		u.tc.T.Fatal(err)
	}
}

func (u *userPlusDevice) readInviteEmails(email string) []string {
	arg := libkb.NewAPIArg("test/team/get_tokens")
	arg.Args = libkb.NewHTTPArgs()
	arg.Args.Add("email", libkb.S{Val: email})
	res, err := u.tc.G.API.Get(arg)
	if err != nil {
		u.tc.T.Fatal(err)
	}
	tokens := res.Body.AtKey("tokens")
	n, err := tokens.Len()
	if err != nil {
		u.tc.T.Fatal(err)
	}
	if n == 0 {
		u.tc.T.Fatalf("no invite tokens for %s", email)
	}

	exp := make([]string, n)
	for i := 0; i < n; i++ {
		token, err := tokens.AtIndex(i).GetString()
		if err != nil {
			u.tc.T.Fatal(err)
		}
		exp[i] = token
	}

	return exp
}

func (u *userPlusDevice) acceptEmailInvite(token string) {
	c := client.NewCmdTeamAcceptInviteRunner(u.tc.G)
	c.Token = token
	if err := c.Run(); err != nil {
		u.tc.T.Fatal(err)
	}
}

func (u *userPlusDevice) revokePaperKey() {
	id := u.paperKeyID()

	runner := client.NewCmdDeviceRemoveRunner(u.tc.G)
	runner.SetIDOrName(id.String())
	if err := runner.Run(); err != nil {
		u.tc.T.Fatal(err)
	}
}

func (u *userPlusDevice) devices() []keybase1.Device {
	d, err := u.deviceClient.DeviceList(context.TODO(), 0)
	if err != nil {
		u.tc.T.Fatal(err)
	}
	return d
}

func (u *userPlusDevice) paperKeyID() keybase1.DeviceID {
	for _, d := range u.devices() {
		if d.Type == libkb.DeviceTypePaper {
			return d.DeviceID
		}
	}
	u.tc.T.Fatal("no paper key found")
	return keybase1.DeviceID("")
}

func (u *userPlusDevice) waitForTeamChangedGregor(team string, toSeqno keybase1.Seqno) {
	// process 10 team rotations or 10s worth of time
	for i := 0; i < 10; i++ {
		select {
		case arg := <-u.notifications.rotateCh:
			u.tc.T.Logf("membership change received: %+v", arg)
			if arg.TeamName == team && arg.Changes.MembershipChanged && !arg.Changes.KeyRotated && !arg.Changes.Renamed && arg.LatestSeqno == toSeqno {
				u.tc.T.Logf("change matched!")
				return
			}
			u.tc.T.Logf("ignoring change message (expected team = %q, seqno = %d)", team, toSeqno)
		case <-time.After(1 * time.Second):
		}
	}
	u.tc.T.Fatalf("timed out waiting for team rotate %s", team)
}

func (u *userPlusDevice) waitForRotate(team string, toSeqno keybase1.Seqno) {
	// jump start the clkr queue processing loop
	u.kickTeamRekeyd()

	// process 10 team rotations or 10s worth of time
	for i := 0; i < 10; i++ {
		select {
		case arg := <-u.notifications.rotateCh:
			u.tc.T.Logf("rotate received: %+v", arg)
			if arg.TeamName == team && arg.Changes.KeyRotated && arg.LatestSeqno == toSeqno {
				u.tc.T.Logf("rotate matched!")
				return
			}
			u.tc.T.Logf("ignoring rotate message")
		case <-time.After(1 * time.Second):
		}
	}
	u.tc.T.Fatalf("timed out waiting for team rotate %s", team)
}

func (u *userPlusDevice) prooveRooter() {
	cmd := client.NewCmdProveRooterRunner(u.tc.G, u.username)
	if err := cmd.Run(); err != nil {
		u.tc.T.Fatal(err)
	}
}

func (u *userPlusDevice) kickTeamRekeyd() {
	kickTeamRekeyd(u.tc.G, u.tc.T)
}

func kickTeamRekeyd(g *libkb.GlobalContext, t testing.TB) {
	apiArg := libkb.APIArg{
		Endpoint: "test/accelerate_team_rekeyd",
		Args: libkb.HTTPArgs{
			"timeout": libkb.I{Val: 2000},
		},
		SessionType: libkb.APISessionTypeREQUIRED,
	}

	_, err := g.API.Post(apiArg)
	if err != nil {
		t.Fatalf("Failed to accelerate team rekeyd: %s", err)
	}
}

func GetTeamForTestByStringName(ctx context.Context, g *libkb.GlobalContext, name string) (*teams.Team, error) {
	return teams.Load(ctx, g, keybase1.LoadTeamArg{
		Name:        name,
		ForceRepoll: true,
	})
}

type teamNotifyHandler struct {
	rotateCh chan keybase1.TeamChangedArg
}

func newTeamNotifyHandler() *teamNotifyHandler {
	return &teamNotifyHandler{
		rotateCh: make(chan keybase1.TeamChangedArg, 1),
	}
}

func (n *teamNotifyHandler) TeamChanged(ctx context.Context, arg keybase1.TeamChangedArg) error {
	n.rotateCh <- arg
	return nil
}

func TestGetTeamRootID(t *testing.T) {
	tt := newTeamTester(t)
	defer tt.cleanup()

	tt.addUser("onr")

	t.Logf("create a team")
	parentName, err := keybase1.TeamNameFromString(tt.users[0].createTeam())
	require.NoError(t, err)

	parentID := parentName.ToTeamID()

	t.Logf("create a subteam")
	subteamID, err := teams.CreateSubteam(context.TODO(), tt.users[0].tc.G, "mysubteam", parentName)
	require.NoError(t, err)

	subteamName, err := parentName.Append("mysubteam")

	t.Logf("create a sub-subteam")
	subteamID2, err := teams.CreateSubteam(context.TODO(), tt.users[0].tc.G, "teamofsubs", subteamName)
	require.NoError(t, err)

	getAndCompare := func(id keybase1.TeamID) {
		retID, err := teams.GetRootID(context.TODO(), tt.users[0].tc.G, id)
		require.NoError(t, err)
		require.Equal(t, parentID, retID)
	}

	getAndCompare(*subteamID)
	getAndCompare(*subteamID2)
	getAndCompare(parentID)
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

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 helpers

import (
	log "github.com/golang/glog"
	"github.com/youtube/vitess/go/vt/topo"
	"golang.org/x/net/context"
)

// Tee is an implementation of topo.Server that uses a primary
// underlying topo.Server for all changes, but also duplicates the
// changes to a secondary topo.Server. It also locks both topo servers
// when needed.  It is meant to be used during transitions from one
// topo.Server to another.
//
// - primary: we read everything from it, and write to it. We also create
//     MasterParticipation from it.
// - secondary: we write to it as well, but we usually don't fail.
// - we lock primary/secondary if reverseLockOrder is False,
// or secondary/primary if reverseLockOrder is True.
type Tee struct {
	primary   topo.Impl
	secondary topo.Impl

	readFrom       topo.Impl
	readFromSecond topo.Impl

	lockFirst  topo.Impl
	lockSecond topo.Impl
}

// NewTee returns a new topo.Impl object
func NewTee(primary, secondary topo.Impl, reverseLockOrder bool) *Tee {
	lockFirst := primary
	lockSecond := secondary
	if reverseLockOrder {
		lockFirst = secondary
		lockSecond = primary
	}
	return &Tee{
		primary:        primary,
		secondary:      secondary,
		readFrom:       primary,
		readFromSecond: secondary,
		lockFirst:      lockFirst,
		lockSecond:     lockSecond,
	}
}

//
// topo.Server management interface.
//

// Close is part of the topo.Server interface
func (tee *Tee) Close() {
	tee.primary.Close()
	tee.secondary.Close()
}

//
// Backend API
//

// ListDir is part of the topo.Backend interface.
func (tee *Tee) ListDir(ctx context.Context, cell, dirPath string) ([]string, error) {
	return tee.primary.ListDir(ctx, cell, dirPath)
}

// Create is part of the topo.Backend interface.
func (tee *Tee) Create(ctx context.Context, cell, filePath string, contents []byte) (topo.Version, error) {
	primaryVersion, err := tee.primary.Create(ctx, cell, filePath, contents)
	if err != nil {
		return nil, err
	}

	// This is critical enough that we want to fail. However, we support
	// an unconditional update if the file already exists.
	_, err = tee.secondary.Create(ctx, cell, filePath, contents)
	if err == topo.ErrNodeExists {
		_, err = tee.secondary.Update(ctx, cell, filePath, contents, nil)
	}
	if err != nil {
		return nil, err
	}

	return primaryVersion, nil
}

// Update is part of the topo.Backend interface.
func (tee *Tee) Update(ctx context.Context, cell, filePath string, contents []byte, version topo.Version) (topo.Version, error) {
	primaryVersion, err := tee.primary.Update(ctx, cell, filePath, contents, version)
	if err != nil {
		// Failed on primary, not updating secondary.
		return nil, err
	}

	// Always do an unconditional update on secondary.
	if _, err = tee.secondary.Update(ctx, cell, filePath, contents, nil); err != nil {
		log.Warningf("secondary.Update(%v,%v,unconditonal) failed: %v", cell, filePath, err)
	}
	return primaryVersion, nil
}

// Get is part of the topo.Backend interface.
func (tee *Tee) Get(ctx context.Context, cell, filePath string) ([]byte, topo.Version, error) {
	return tee.primary.Get(ctx, cell, filePath)
}

// Delete is part of the topo.Backend interface.
func (tee *Tee) Delete(ctx context.Context, cell, filePath string, version topo.Version) error {
	// If primary fails, no need to go further.
	if err := tee.primary.Delete(ctx, cell, filePath, version); err != nil {
		return err
	}

	// Always do an unconditonal delete on secondary.
	if err := tee.secondary.Delete(ctx, cell, filePath, nil); err != nil && err != topo.ErrNoNode {
		// Secondary didn't work, and the node wasn't gone already.
		log.Warningf("secondary.Delete(%v,%v) failed: %v", cell, filePath, err)
	}

	return nil
}

// Watch is part of the topo.Backend interface
func (tee *Tee) Watch(ctx context.Context, cell, filePath string) (*topo.WatchData, <-chan *topo.WatchData, topo.CancelFunc) {
	return tee.primary.Watch(ctx, cell, filePath)
}

//
// Lock management.
//

// teeTopoLockDescriptor implements the topo.LockDescriptor interface.
type teeTopoLockDescriptor struct {
	tee                  *Tee
	cell                 string
	dirPath              string
	firstLockDescriptor  topo.LockDescriptor
	secondLockDescriptor topo.LockDescriptor
}

// Lock is part of the topo.Backend interface.
func (tee *Tee) Lock(ctx context.Context, cell, dirPath, contents string) (topo.LockDescriptor, error) {
	// Lock lockFirst.
	fLD, err := tee.lockFirst.Lock(ctx, cell, dirPath, contents)
	if err != nil {
		return nil, err
	}

	// Lock lockSecond.
	sLD, err := tee.lockSecond.Lock(ctx, cell, dirPath, contents)
	if err != nil {
		if err := fLD.Unlock(ctx); err != nil {
			log.Warningf("Failed to unlock lockFirst after failed lockSecond lock for %v %v: %v", cell, dirPath, err)
		}
		return nil, err
	}

	// Remember both locks in teeTopoLockDescriptor.
	return &teeTopoLockDescriptor{
		tee:                  tee,
		cell:                 cell,
		dirPath:              dirPath,
		firstLockDescriptor:  fLD,
		secondLockDescriptor: sLD,
	}, nil
}

// Unlock is part of the topo.LockDescriptor interface.
func (ld *teeTopoLockDescriptor) Unlock(ctx context.Context) error {
	// Unlock lockSecond, then lockFirst.
	serr := ld.secondLockDescriptor.Unlock(ctx)
	ferr := ld.firstLockDescriptor.Unlock(ctx)

	if serr != nil {
		if ferr != nil {
			log.Warningf("First Unlock(%v, %v) failed: %v", ld.cell, ld.dirPath, ferr)
		}
		return serr
	}
	return ferr
}

// NewMasterParticipation is part of the topo.Server interface
func (tee *Tee) NewMasterParticipation(name, id string) (topo.MasterParticipation, error) {
	return tee.primary.NewMasterParticipation(name, id)
}
<commit_msg>Adding a comma.<commit_after>/*
Copyright 2017 Google Inc.

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 helpers

import (
	log "github.com/golang/glog"
	"github.com/youtube/vitess/go/vt/topo"
	"golang.org/x/net/context"
)

// Tee is an implementation of topo.Server that uses a primary
// underlying topo.Server for all changes, but also duplicates the
// changes to a secondary topo.Server. It also locks both topo servers
// when needed.  It is meant to be used during transitions from one
// topo.Server to another.
//
// - primary: we read everything from it, and write to it. We also create
//     MasterParticipation from it.
// - secondary: we write to it as well, but we usually don't fail.
// - we lock primary/secondary if reverseLockOrder is False,
// or secondary/primary if reverseLockOrder is True.
type Tee struct {
	primary   topo.Impl
	secondary topo.Impl

	readFrom       topo.Impl
	readFromSecond topo.Impl

	lockFirst  topo.Impl
	lockSecond topo.Impl
}

// NewTee returns a new topo.Impl object
func NewTee(primary, secondary topo.Impl, reverseLockOrder bool) *Tee {
	lockFirst := primary
	lockSecond := secondary
	if reverseLockOrder {
		lockFirst = secondary
		lockSecond = primary
	}
	return &Tee{
		primary:        primary,
		secondary:      secondary,
		readFrom:       primary,
		readFromSecond: secondary,
		lockFirst:      lockFirst,
		lockSecond:     lockSecond,
	}
}

//
// topo.Server management interface.
//

// Close is part of the topo.Server interface
func (tee *Tee) Close() {
	tee.primary.Close()
	tee.secondary.Close()
}

//
// Backend API
//

// ListDir is part of the topo.Backend interface.
func (tee *Tee) ListDir(ctx context.Context, cell, dirPath string) ([]string, error) {
	return tee.primary.ListDir(ctx, cell, dirPath)
}

// Create is part of the topo.Backend interface.
func (tee *Tee) Create(ctx context.Context, cell, filePath string, contents []byte) (topo.Version, error) {
	primaryVersion, err := tee.primary.Create(ctx, cell, filePath, contents)
	if err != nil {
		return nil, err
	}

	// This is critical enough that we want to fail. However, we support
	// an unconditional update if the file already exists.
	_, err = tee.secondary.Create(ctx, cell, filePath, contents)
	if err == topo.ErrNodeExists {
		_, err = tee.secondary.Update(ctx, cell, filePath, contents, nil)
	}
	if err != nil {
		return nil, err
	}

	return primaryVersion, nil
}

// Update is part of the topo.Backend interface.
func (tee *Tee) Update(ctx context.Context, cell, filePath string, contents []byte, version topo.Version) (topo.Version, error) {
	primaryVersion, err := tee.primary.Update(ctx, cell, filePath, contents, version)
	if err != nil {
		// Failed on primary, not updating secondary.
		return nil, err
	}

	// Always do an unconditional update on secondary.
	if _, err = tee.secondary.Update(ctx, cell, filePath, contents, nil); err != nil {
		log.Warningf("secondary.Update(%v,%v,unconditonal) failed: %v", cell, filePath, err)
	}
	return primaryVersion, nil
}

// Get is part of the topo.Backend interface.
func (tee *Tee) Get(ctx context.Context, cell, filePath string) ([]byte, topo.Version, error) {
	return tee.primary.Get(ctx, cell, filePath)
}

// Delete is part of the topo.Backend interface.
func (tee *Tee) Delete(ctx context.Context, cell, filePath string, version topo.Version) error {
	// If primary fails, no need to go further.
	if err := tee.primary.Delete(ctx, cell, filePath, version); err != nil {
		return err
	}

	// Always do an unconditonal delete on secondary.
	if err := tee.secondary.Delete(ctx, cell, filePath, nil); err != nil && err != topo.ErrNoNode {
		// Secondary didn't work, and the node wasn't gone already.
		log.Warningf("secondary.Delete(%v,%v) failed: %v", cell, filePath, err)
	}

	return nil
}

// Watch is part of the topo.Backend interface
func (tee *Tee) Watch(ctx context.Context, cell, filePath string) (*topo.WatchData, <-chan *topo.WatchData, topo.CancelFunc) {
	return tee.primary.Watch(ctx, cell, filePath)
}

//
// Lock management.
//

// teeTopoLockDescriptor implements the topo.LockDescriptor interface.
type teeTopoLockDescriptor struct {
	tee                  *Tee
	cell                 string
	dirPath              string
	firstLockDescriptor  topo.LockDescriptor
	secondLockDescriptor topo.LockDescriptor
}

// Lock is part of the topo.Backend interface.
func (tee *Tee) Lock(ctx context.Context, cell, dirPath, contents string) (topo.LockDescriptor, error) {
	// Lock lockFirst.
	fLD, err := tee.lockFirst.Lock(ctx, cell, dirPath, contents)
	if err != nil {
		return nil, err
	}

	// Lock lockSecond.
	sLD, err := tee.lockSecond.Lock(ctx, cell, dirPath, contents)
	if err != nil {
		if err := fLD.Unlock(ctx); err != nil {
			log.Warningf("Failed to unlock lockFirst after failed lockSecond lock for %v, %v: %v", cell, dirPath, err)
		}
		return nil, err
	}

	// Remember both locks in teeTopoLockDescriptor.
	return &teeTopoLockDescriptor{
		tee:                  tee,
		cell:                 cell,
		dirPath:              dirPath,
		firstLockDescriptor:  fLD,
		secondLockDescriptor: sLD,
	}, nil
}

// Unlock is part of the topo.LockDescriptor interface.
func (ld *teeTopoLockDescriptor) Unlock(ctx context.Context) error {
	// Unlock lockSecond, then lockFirst.
	serr := ld.secondLockDescriptor.Unlock(ctx)
	ferr := ld.firstLockDescriptor.Unlock(ctx)

	if serr != nil {
		if ferr != nil {
			log.Warningf("First Unlock(%v, %v) failed: %v", ld.cell, ld.dirPath, ferr)
		}
		return serr
	}
	return ferr
}

// NewMasterParticipation is part of the topo.Server interface
func (tee *Tee) NewMasterParticipation(name, id string) (topo.MasterParticipation, error) {
	return tee.primary.NewMasterParticipation(name, id)
}
<|endoftext|>


<commit_before>package arrays

import (
	. "launchpad.net/gocheck"
	"testing"
)

// Hook up gocheck into the "go test" runner.
func Test(t *testing.T) { TestingT(t) }

type S struct{}

var _ = Suite(&S{})

func (s *S) TestToStringArray(c *C) {
	obj := []interface{}{"A", "b", "c"}
	strs, err := StringArray(obj)
	c.Assert(err, IsNil)
	c.Check(strs, DeepEquals, []string{"A", "b", "c"})
}

func (s *S) TestToStringArrayFail(c *C) {
	obj := []interface{}{"A", 300, "c"} // not all strings
	strs, err := StringArray(obj)
	c.Assert(err, ErrorMatches, "Error converting int to string")
	c.Check(strs, DeepEquals, []string{"A"})
}
<commit_msg>tidy up types_test.go<commit_after>package arrays

import (
	. "launchpad.net/gocheck"
)

func (s *S) TestToStringArray(c *C) {
	obj := []interface{}{"A", "b", "c"}
	strs, err := StringArray(obj)
	c.Assert(err, IsNil)
	c.Check(strs, DeepEquals, []string{"A", "b", "c"})
}

func (s *S) TestToStringArrayFail(c *C) {
	obj := []interface{}{"A", 300, "c"} // not all strings
	strs, err := StringArray(obj)
	c.Assert(err, ErrorMatches, "Error converting int to string")
	c.Check(strs, DeepEquals, []string{"A"})
}
<|endoftext|>


<commit_before>package dcmnet

import (
	"reflect"
	"testing"

	"github.com/jeremyhuiskamp/dcm/dcm"
)

func TestRole(t *testing.T) {
	expectRole := func(r Role, scu, scp bool) {
		if r.IsSCU() != scu {
			t.Errorf("%s expected scu %t", r, scu)
		}
		if r.IsSCP() != scp {
			t.Errorf("%s expected scp %t", r, scp)
		}
	}

	expectRole(DefaultRole, true, false)

	var role Role
	expectRole(role, false, false)

	role.SetSCP(true)
	expectRole(role, false, true)

	role.SetSCU(true)
	expectRole(role, true, true)
}

// simple case with single, matching, accepted contexts
var simplePcs = PresentationContexts{
	Requested: []PresentationContext{{
		AbstractSyntax: "1.2.3",
		ID:             1,
		TransferSyntaxes: []dcm.TransferSyntax{
			dcm.ImplicitVRLittleEndian,
		},
	}},
	Accepted: []PresentationContext{{
		AbstractSyntax: "1.2.3",
		ID:             1,
		Result:         PCAcceptance,
		TransferSyntaxes: []dcm.TransferSyntax{
			dcm.ImplicitVRLittleEndian,
		},
	}},
}

// matches simplePcs above
var matchingTc = NewTransferCapability("1.2.3", dcm.ImplicitVRLittleEndian)

func expectMatchingTc(t *testing.T, got *TransferCapability) {
	if !reflect.DeepEqual(&matchingTc, got) {
		t.Errorf("unexpected transfer capability: %s", got)
	}
}

func TestPCsSingleAcceptance(t *testing.T) {
	if got := simplePcs.FindAcceptedTCap(PCID(1)); !reflect.DeepEqual(&matchingTc, got) {
		t.Errorf("unknown tc for pcid 1: %s", got)
	}
	expectMatchingTc(t, simplePcs.FindAcceptedTCap(PCID(1)))

	if got := simplePcs.FindAcceptedTCap(PCID(2)); got != nil {
		t.Errorf("expected no tc for pcid 2 but got: %s", got)
	}

	if got := simplePcs.FindAcceptedPCID(matchingTc); got == nil || PCID(1) != *got {
		t.Errorf("unexpected pcid: %d", got)
	}

	nonMatchingTc := matchingTc
	nonMatchingTc.AbstractSyntax = "1.2.3.4"
	if got := simplePcs.FindAcceptedPCID(nonMatchingTc); got != nil {
		t.Errorf("expected no pcid but got: %d", got)
	}
}

func TestPCsMultipleProposedTransferSyntaxes(t *testing.T) {
	pcs := simplePcs
	// No! This modifies the global!
	pcs.Requested[0].TransferSyntaxes = []dcm.TransferSyntax{
		// add a new one first, make sure it gets skipped:
		dcm.ExplicitVRLittleEndian,
		pcs.Requested[0].TransferSyntaxes[0],
	}

	expectMatchingTc(t, pcs.FindAcceptedTCap(PCID(1)))
}

func TestPCsNoOverlappingTransferSyntaxes(t *testing.T) {
	pcs := simplePcs
	// this probably isn't technically legal in dicom, but the code should
	// handle it:
	pcs.Accepted[0].TransferSyntaxes = []dcm.TransferSyntax{
		dcm.ExplicitVRBigEndian,
	}

	if got := pcs.FindAcceptedPCID(matchingTc); got != nil {
		t.Errorf("expected no pcid but got: %d", got)
	}
}

func TestPCsSingleUnacceptedContext(t *testing.T) {
	pcs := simplePcs
	pcs.Accepted[0].Result = PCUserRejection

	if got := pcs.FindAcceptedTCap(PCID(1)); got != nil {
		t.Errorf("expected no tcap but got: %d", got)
	}
	if got := pcs.FindAcceptedPCID(matchingTc); got != nil {
		t.Errorf("expected no pcid but got: %d", got)
	}
}
<commit_msg>avoid ordering dependency among tests<commit_after>package dcmnet

import (
	"reflect"
	"testing"

	"github.com/jeremyhuiskamp/dcm/dcm"
)

func TestRole(t *testing.T) {
	expectRole := func(r Role, scu, scp bool) {
		if r.IsSCU() != scu {
			t.Errorf("%s expected scu %t", r, scu)
		}
		if r.IsSCP() != scp {
			t.Errorf("%s expected scp %t", r, scp)
		}
	}

	expectRole(DefaultRole, true, false)

	var role Role
	expectRole(role, false, false)

	role.SetSCP(true)
	expectRole(role, false, true)

	role.SetSCU(true)
	expectRole(role, true, true)
}

// simple case with single, matching, accepted contexts
func simplePcs() PresentationContexts {
	return PresentationContexts{
		Requested: []PresentationContext{{
			AbstractSyntax: "1.2.3",
			ID:             1,
			TransferSyntaxes: []dcm.TransferSyntax{
				dcm.ImplicitVRLittleEndian,
			},
		}},
		Accepted: []PresentationContext{{
			AbstractSyntax: "1.2.3",
			ID:             1,
			Result:         PCAcceptance,
			TransferSyntaxes: []dcm.TransferSyntax{
				dcm.ImplicitVRLittleEndian,
			},
		}},
	}
}

// matches simplePcs above
var matchingTc = NewTransferCapability("1.2.3", dcm.ImplicitVRLittleEndian)

func expectMatchingTc(t *testing.T, got *TransferCapability) {
	if !reflect.DeepEqual(&matchingTc, got) {
		t.Errorf("unexpected transfer capability: %s", got)
	}
}

func TestPCsSingleAcceptance(t *testing.T) {
	pcs := simplePcs()
	if got := pcs.FindAcceptedTCap(PCID(1)); !reflect.DeepEqual(&matchingTc, got) {
		t.Errorf("unknown tc for pcid 1: %s", got)
	}
	expectMatchingTc(t, pcs.FindAcceptedTCap(PCID(1)))

	if got := pcs.FindAcceptedTCap(PCID(2)); got != nil {
		t.Errorf("expected no tc for pcid 2 but got: %s", got)
	}

	if got := pcs.FindAcceptedPCID(matchingTc); got == nil || PCID(1) != *got {
		t.Errorf("unexpected pcid: %d", got)
	}

	nonMatchingTc := matchingTc
	nonMatchingTc.AbstractSyntax = "1.2.3.4"
	if got := pcs.FindAcceptedPCID(nonMatchingTc); got != nil {
		t.Errorf("expected no pcid but got: %d", got)
	}
}

func TestPCsMultipleProposedTransferSyntaxes(t *testing.T) {
	pcs := simplePcs()
	pcs.Requested[0].TransferSyntaxes = []dcm.TransferSyntax{
		// add a new one first, make sure it gets skipped:
		dcm.ExplicitVRLittleEndian,
		pcs.Requested[0].TransferSyntaxes[0],
	}

	expectMatchingTc(t, pcs.FindAcceptedTCap(PCID(1)))
}

func TestPCsNoOverlappingTransferSyntaxes(t *testing.T) {
	pcs := simplePcs()
	// this probably isn't technically legal in dicom, but the code should
	// handle it:
	pcs.Accepted[0].TransferSyntaxes = []dcm.TransferSyntax{
		dcm.ExplicitVRBigEndian,
	}

	if got := pcs.FindAcceptedPCID(matchingTc); got != nil {
		t.Errorf("expected no pcid but got: %d", got)
	}
}

func TestPCsSingleUnacceptedContext(t *testing.T) {
	pcs := simplePcs()
	pcs.Accepted[0].Result = PCUserRejection

	if got := pcs.FindAcceptedTCap(PCID(1)); got != nil {
		t.Errorf("expected no tcap but got: %d", got)
	}
	if got := pcs.FindAcceptedPCID(matchingTc); got != nil {
		t.Errorf("expected no pcid but got: %d", got)
	}
}
<|endoftext|>


<commit_before>package ddb

import (
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/urfave/cli"
)

func ScanTable(ctx *cli.Context) error {
	tableName := ctx.String("table")

	if tableName == "" {
		cli.ShowSubcommandHelp(ctx)
		return nil
	}

	c := client()
	out, err := c.Scan(&dynamodb.ScanInput{
		TableName: aws.String(tableName),
	})
	if err != nil {
		log.Fatalln("ERROR", err)
	}

	kd := describeTableKey(tableName, c)

	limit := ctx.Int("row-limit")
	for i, item := range out.Items {
		if i >= limit {
			break
		}
		printItem(item, kd)
	}

	return nil
}
<commit_msg>Add space between items in ddb scan<commit_after>package ddb

import (
	"fmt"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/urfave/cli"
)

func ScanTable(ctx *cli.Context) error {
	tableName := ctx.String("table")

	if tableName == "" {
		cli.ShowSubcommandHelp(ctx)
		return nil
	}

	c := client()
	out, err := c.Scan(&dynamodb.ScanInput{
		TableName: aws.String(tableName),
	})
	if err != nil {
		log.Fatalln("ERROR", err)
	}

	kd := describeTableKey(tableName, c)

	limit := ctx.Int("row-limit")
	for i, item := range out.Items {
		if i >= limit {
			break
		}
		printItem(item, kd)
		fmt.Println()
	}

	return nil
}
<|endoftext|>


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

package output_runner

import (
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"github.com/bazelbuild/bazel-watcher/ibazel/log"
	"github.com/bazelbuild/bazel-watcher/ibazel/workspace"
	"github.com/bazelbuild/bazel-watcher/third_party/bazel/master/src/main/protobuf/blaze_query"
)

var (
	runOutput = flag.Bool(
		"run_output",
		true,
		"Search for commands in Bazel output that match a regex and execute them, the default path of file should be in the workspace root .bazel_fix_commands.json")
	runOutputInteractive = flag.Bool(
		"run_output_interactive",
		true,
		"Use an interactive prompt when executing commands in Bazel output")
	notifiedUser = false
)

// This RegExp will match ANSI escape codes.
var escapeCodeCleanerRegex = regexp.MustCompile("\\x1B\\[[\\x30-\\x3F]*[\\x20-\\x2F]*[\\x40-\\x7E]")

type OutputRunner struct {
	w workspace.Workspace
}

type Optcmd struct {
	Regex   string   `json:"regex"`
	Command string   `json:"command"`
	Args    []string `json:"args"`
}

func New() *OutputRunner {
	i := &OutputRunner{
		w: &workspace.MainWorkspace{},
	}
	return i
}

func (i *OutputRunner) Initialize(info *map[string]string) {}

func (i *OutputRunner) TargetDecider(rule *blaze_query.Rule) {}

func (i *OutputRunner) ChangeDetected(targets []string, changeType string, change string) {}

func (i *OutputRunner) BeforeCommand(targets []string, command string) {}

func (i *OutputRunner) AfterCommand(targets []string, command string, success bool, output *bytes.Buffer) {
	if *runOutput == false || output == nil {
		return
	}

	jsonCommandPath := ".bazel_fix_commands.json"
	defaultRegex := Optcmd{
		Regex:   "^buildozer '(.*)'\\s+(.*)$",
		Command: "buildozer",
		Args:    []string{"$1", "$2"},
	}

	optcmd := i.readConfigs(jsonCommandPath)
	if optcmd == nil {
		optcmd = []Optcmd{defaultRegex}
	}
	commandLines, commands, args := matchRegex(optcmd, output)
	for idx, _ := range commandLines {
		if *runOutputInteractive {
			if i.promptCommand(commandLines[idx]) {
				i.executeCommand(commands[idx], args[idx])
			}
		} else {
			i.executeCommand(commands[idx], args[idx])
		}
	}
}

func (o *OutputRunner) readConfigs(configPath string) []Optcmd {
	workspacePath, err := o.w.FindWorkspace()
	if err != nil {
		log.Fatalf("Error finding workspace: %v", err)
		os.Exit(5)
	}

	jsonFile, err := os.Open(filepath.Join(workspacePath, configPath))
	if os.IsNotExist(err) {
		// Note this is not attached to the os.IsNotExist because we don't want the
		// other error handler to catch if we hav already notified.
		if !notifiedUser {
			log.Banner(
				"Did you know iBazel can invoke programs like Gazelle, buildozer, and",
				"other BUILD file generators for you automatically based on bazel output?",
				"Documentation at: https://github.com/bazelbuild/bazel-watcher#output-runner")
		}
		notifiedUser = true
		return nil
	} else if err != nil {
		log.Errorf("Error reading config: %s", err)
		return nil
	}
	defer jsonFile.Close()

	byteValue, _ := ioutil.ReadAll(jsonFile)
	var optcmd []Optcmd
	err = json.Unmarshal(byteValue, &optcmd)
	if err != nil {
		log.Errorf("Error in .bazel_fix_commands.json: %s", err)
	}

	return optcmd
}

func matchRegex(optcmd []Optcmd, output *bytes.Buffer) ([]string, []string, [][]string) {
	var commandLines, commands []string
	var args [][]string
	distinctCommands := map[string]bool{}
	scanner := bufio.NewScanner(output)
	for scanner.Scan() {
		line := escapeCodeCleanerRegex.ReplaceAllLiteralString(scanner.Text(), "")
		for _, oc := range optcmd {
			re := regexp.MustCompile(oc.Regex)
			matches := re.FindStringSubmatch(line)
			if matches != nil && len(matches) >= 0 {
				command := convertArg(matches, oc.Command)
				cmdArgs := convertArgs(matches, oc.Args)
				fullCmd := strings.Join(append([]string{command}, cmdArgs...), " ")
				if _, found := distinctCommands[fullCmd]; !found {
					commandLines = append(commandLines, matches[0])
					commands = append(commands, command)
					args = append(args, cmdArgs)
					distinctCommands[fullCmd] = true
				}
			}
		}
	}
	return commandLines, commands, args
}

func convertArg(matches []string, arg string) string {
	if strings.HasPrefix(arg, "$") {
		val, _ := strconv.Atoi(arg[1:])
		return matches[val]
	}
	return arg
}

func convertArgs(matches []string, args []string) []string {
	var rst []string
	for i, _ := range args {
		if strings.HasPrefix(args[i], "$") {
			val, _ := strconv.Atoi(args[i][1:])
			rst = append(rst, matches[val])
		} else {
			rst = append(rst, args[i])
		}
	}
	return rst
}

func (_ *OutputRunner) promptCommand(command string) bool {
	reader := bufio.NewReader(os.Stdin)
	fmt.Fprintf(os.Stderr, "Do you want to execute this command?\n%s\n[y/N]", command)
	text, _ := reader.ReadString('\n')
	text = strings.ToLower(text)
	text = strings.TrimSpace(text)
	text = strings.TrimRight(text, "\n")
	if text == "y" {
		return true
	} else {
		return false
	}
}

func (o *OutputRunner) executeCommand(command string, args []string) {
	o.w.ExecuteCommand(command, args)
}

func (i *OutputRunner) Cleanup() {}
<commit_msg>Display output runner command in prompt, rather than output match (#531)<commit_after>// Copyright 2017 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package output_runner

import (
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"github.com/bazelbuild/bazel-watcher/ibazel/log"
	"github.com/bazelbuild/bazel-watcher/ibazel/workspace"
	"github.com/bazelbuild/bazel-watcher/third_party/bazel/master/src/main/protobuf/blaze_query"
)

var (
	runOutput = flag.Bool(
		"run_output",
		true,
		"Search for commands in Bazel output that match a regex and execute them, the default path of file should be in the workspace root .bazel_fix_commands.json")
	runOutputInteractive = flag.Bool(
		"run_output_interactive",
		true,
		"Use an interactive prompt when executing commands in Bazel output")
	notifiedUser = false
)

// This RegExp will match ANSI escape codes.
var escapeCodeCleanerRegex = regexp.MustCompile("\\x1B\\[[\\x30-\\x3F]*[\\x20-\\x2F]*[\\x40-\\x7E]")

type OutputRunner struct {
	w workspace.Workspace
}

type Optcmd struct {
	Regex   string   `json:"regex"`
	Command string   `json:"command"`
	Args    []string `json:"args"`
}

func New() *OutputRunner {
	i := &OutputRunner{
		w: &workspace.MainWorkspace{},
	}
	return i
}

func (i *OutputRunner) Initialize(info *map[string]string) {}

func (i *OutputRunner) TargetDecider(rule *blaze_query.Rule) {}

func (i *OutputRunner) ChangeDetected(targets []string, changeType string, change string) {}

func (i *OutputRunner) BeforeCommand(targets []string, command string) {}

func (i *OutputRunner) AfterCommand(targets []string, command string, success bool, output *bytes.Buffer) {
	if *runOutput == false || output == nil {
		return
	}

	jsonCommandPath := ".bazel_fix_commands.json"
	defaultRegex := Optcmd{
		Regex:   "^buildozer '(.*)'\\s+(.*)$",
		Command: "buildozer",
		Args:    []string{"$1", "$2"},
	}

	optcmd := i.readConfigs(jsonCommandPath)
	if optcmd == nil {
		optcmd = []Optcmd{defaultRegex}
	}
	commandLines, commands, args := matchRegex(optcmd, output)
	for idx, _ := range commandLines {
		if *runOutputInteractive {
			if i.promptCommand(commands[idx], args[idx]) {
				i.executeCommand(commands[idx], args[idx])
			}
		} else {
			i.executeCommand(commands[idx], args[idx])
		}
	}
}

func (o *OutputRunner) readConfigs(configPath string) []Optcmd {
	workspacePath, err := o.w.FindWorkspace()
	if err != nil {
		log.Fatalf("Error finding workspace: %v", err)
		os.Exit(5)
	}

	jsonFile, err := os.Open(filepath.Join(workspacePath, configPath))
	if os.IsNotExist(err) {
		// Note this is not attached to the os.IsNotExist because we don't want the
		// other error handler to catch if we hav already notified.
		if !notifiedUser {
			log.Banner(
				"Did you know iBazel can invoke programs like Gazelle, buildozer, and",
				"other BUILD file generators for you automatically based on bazel output?",
				"Documentation at: https://github.com/bazelbuild/bazel-watcher#output-runner")
		}
		notifiedUser = true
		return nil
	} else if err != nil {
		log.Errorf("Error reading config: %s", err)
		return nil
	}
	defer jsonFile.Close()

	byteValue, _ := ioutil.ReadAll(jsonFile)
	var optcmd []Optcmd
	err = json.Unmarshal(byteValue, &optcmd)
	if err != nil {
		log.Errorf("Error in .bazel_fix_commands.json: %s", err)
	}

	return optcmd
}

func matchRegex(optcmd []Optcmd, output *bytes.Buffer) ([]string, []string, [][]string) {
	var commandLines, commands []string
	var args [][]string
	distinctCommands := map[string]bool{}
	scanner := bufio.NewScanner(output)
	for scanner.Scan() {
		line := escapeCodeCleanerRegex.ReplaceAllLiteralString(scanner.Text(), "")
		for _, oc := range optcmd {
			re := regexp.MustCompile(oc.Regex)
			matches := re.FindStringSubmatch(line)
			if matches != nil && len(matches) >= 0 {
				command := convertArg(matches, oc.Command)
				cmdArgs := convertArgs(matches, oc.Args)
				fullCmd := strings.Join(append([]string{command}, cmdArgs...), " ")
				if _, found := distinctCommands[fullCmd]; !found {
					commandLines = append(commandLines, matches[0])
					commands = append(commands, command)
					args = append(args, cmdArgs)
					distinctCommands[fullCmd] = true
				}
			}
		}
	}
	return commandLines, commands, args
}

func convertArg(matches []string, arg string) string {
	if strings.HasPrefix(arg, "$") {
		val, _ := strconv.Atoi(arg[1:])
		return matches[val]
	}
	return arg
}

func convertArgs(matches []string, args []string) []string {
	var rst []string
	for i, _ := range args {
		if strings.HasPrefix(args[i], "$") {
			val, _ := strconv.Atoi(args[i][1:])
			rst = append(rst, matches[val])
		} else {
			rst = append(rst, args[i])
		}
	}
	return rst
}

func (_ *OutputRunner) promptCommand(command string, args []string) bool {
	reader := bufio.NewReader(os.Stdin)
	fmt.Fprintf(os.Stderr, "Do you want to execute this command?\n%s %s\n[y/N]", command, strings.Join(args, " "))
	text, _ := reader.ReadString('\n')
	text = strings.ToLower(text)
	text = strings.TrimSpace(text)
	text = strings.TrimRight(text, "\n")
	if text == "y" {
		return true
	} else {
		return false
	}
}

func (o *OutputRunner) executeCommand(command string, args []string) {
	o.w.ExecuteCommand(command, args)
}

func (i *OutputRunner) Cleanup() {}
<|endoftext|>


<commit_before>package agent

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/AdRoll/goamz/s3"
	"github.com/buildkite/agent/api"
	"github.com/buildkite/agent/logger"
	"github.com/buildkite/agent/mime"
)

type S3Uploader struct {
	// The destination which includes the S3 bucket name
	// and the path.
	// s3://my-bucket-name/foo/bar
	Destination string

	// Whether or not HTTP calls shoud be debugged
	DebugHTTP bool

	// The S3 Bucket we're uploading these files to
	Bucket *s3.Bucket
}

func (u *S3Uploader) Setup(destination string, debugHTTP bool) error {
	u.Destination = destination
	u.DebugHTTP = debugHTTP

	// Try to auth with S3
	auth, err := awsS3Auth()
	if err != nil {
		return errors.New(fmt.Sprintf("Error creating AWS S3 authentication: %s", err.Error()))
	}

	// Try and get the region
	region, err := awsS3Region()
	if err != nil {
		return err
	}

	logger.Debug("Authorizing S3 credentials and finding bucket `%s` in region `%s`...", u.bucketName(), region.Name)

	// Find the bucket
	s3 := s3.New(auth, region)
	bucket := s3.Bucket(u.bucketName())

	// If the list doesn't return an error, then we've got our bucket
	_, err = bucket.List("", "", "", 0)
	if err != nil {
		return errors.New("Could not find bucket `" + u.bucketName() + "` in region `" + region.Name + "` (" + err.Error() + ")")
	}

	u.Bucket = bucket

	return nil
}

func (u *S3Uploader) URL(artifact *api.Artifact) string {
	url, _ := url.Parse("http://" + u.bucketName() + ".s3.amazonaws.com")

	url.Path += u.artifactPath(artifact)

	return url.String()
}

func (u *S3Uploader) Upload(artifact *api.Artifact) error {
	permission := "public-read"
	if os.Getenv("BUILDKITE_S3_ACL") != "" {
		permission = os.Getenv("BUILDKITE_S3_ACL")
	} else if os.Getenv("AWS_S3_ACL") != "" {
		permission = os.Getenv("AWS_S3_ACL")
	}

	// The dirtiest validation method ever...
	if permission != "private" &&
		permission != "public-read" &&
		permission != "public-read-write" &&
		permission != "authenticated-read" &&
		permission != "bucket-owner-read" &&
		permission != "bucket-owner-full-control" {
		logger.Fatal("Invalid S3 ACL `%s`", permission)
	}

	Perms := s3.ACL(permission)

	logger.Debug("Reading file \"%s\"", artifact.AbsolutePath)
	data, err := ioutil.ReadFile(artifact.AbsolutePath)
	if err != nil {
		return errors.New("Failed to read file " + artifact.AbsolutePath + " (" + err.Error() + ")")
	}

	logger.Debug("Uploading \"%s\" to bucket with permission `%s`", u.artifactPath(artifact), permission)
	err = u.Bucket.Put(u.artifactPath(artifact), data, u.mimeType(artifact), Perms, s3.Options{})
	if err != nil {
		return errors.New(fmt.Sprintf("Failed to PUT file \"%s\" (%s)", u.artifactPath(artifact), err.Error()))
	}

	return nil
}

func (u *S3Uploader) artifactPath(artifact *api.Artifact) string {
	parts := []string{u.bucketPath(), artifact.Path}

	return strings.Join(parts, "/")
}

func (u *S3Uploader) bucketPath() string {
	return strings.Join(u.destinationParts()[1:len(u.destinationParts())], "/")
}

func (u *S3Uploader) bucketName() string {
	return u.destinationParts()[0]
}

func (u *S3Uploader) destinationParts() []string {
	trimmed := strings.TrimLeft(u.Destination, "s3://")

	return strings.Split(trimmed, "/")
}

func (u *S3Uploader) mimeType(a *api.Artifact) string {
	extension := filepath.Ext(a.Path)
	mimeType := mime.TypeByExtension(extension)

	if mimeType != "" {
		return mimeType
	} else {
		return "binary/octet-stream"
	}
}
<commit_msg>Use TrimPrefix instead of TrimLeft<commit_after>package agent

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/AdRoll/goamz/s3"
	"github.com/buildkite/agent/api"
	"github.com/buildkite/agent/logger"
	"github.com/buildkite/agent/mime"
)

type S3Uploader struct {
	// The destination which includes the S3 bucket name
	// and the path.
	// s3://my-bucket-name/foo/bar
	Destination string

	// Whether or not HTTP calls shoud be debugged
	DebugHTTP bool

	// The S3 Bucket we're uploading these files to
	Bucket *s3.Bucket
}

func (u *S3Uploader) Setup(destination string, debugHTTP bool) error {
	u.Destination = destination
	u.DebugHTTP = debugHTTP

	// Try to auth with S3
	auth, err := awsS3Auth()
	if err != nil {
		return errors.New(fmt.Sprintf("Error creating AWS S3 authentication: %s", err.Error()))
	}

	// Try and get the region
	region, err := awsS3Region()
	if err != nil {
		return err
	}

	logger.Debug("Authorizing S3 credentials and finding bucket `%s` in region `%s`...", u.bucketName(), region.Name)

	// Find the bucket
	s3 := s3.New(auth, region)
	bucket := s3.Bucket(u.bucketName())

	// If the list doesn't return an error, then we've got our bucket
	_, err = bucket.List("", "", "", 0)
	if err != nil {
		return errors.New("Could not find bucket `" + u.bucketName() + "` in region `" + region.Name + "` (" + err.Error() + ")")
	}

	u.Bucket = bucket

	return nil
}

func (u *S3Uploader) URL(artifact *api.Artifact) string {
	url, _ := url.Parse("http://" + u.bucketName() + ".s3.amazonaws.com")

	url.Path += u.artifactPath(artifact)

	return url.String()
}

func (u *S3Uploader) Upload(artifact *api.Artifact) error {
	permission := "public-read"
	if os.Getenv("BUILDKITE_S3_ACL") != "" {
		permission = os.Getenv("BUILDKITE_S3_ACL")
	} else if os.Getenv("AWS_S3_ACL") != "" {
		permission = os.Getenv("AWS_S3_ACL")
	}

	// The dirtiest validation method ever...
	if permission != "private" &&
		permission != "public-read" &&
		permission != "public-read-write" &&
		permission != "authenticated-read" &&
		permission != "bucket-owner-read" &&
		permission != "bucket-owner-full-control" {
		logger.Fatal("Invalid S3 ACL `%s`", permission)
	}

	Perms := s3.ACL(permission)

	logger.Debug("Reading file \"%s\"", artifact.AbsolutePath)
	data, err := ioutil.ReadFile(artifact.AbsolutePath)
	if err != nil {
		return errors.New("Failed to read file " + artifact.AbsolutePath + " (" + err.Error() + ")")
	}

	logger.Debug("Uploading \"%s\" to bucket with permission `%s`", u.artifactPath(artifact), permission)
	err = u.Bucket.Put(u.artifactPath(artifact), data, u.mimeType(artifact), Perms, s3.Options{})
	if err != nil {
		return errors.New(fmt.Sprintf("Failed to PUT file \"%s\" (%s)", u.artifactPath(artifact), err.Error()))
	}

	return nil
}

func (u *S3Uploader) artifactPath(artifact *api.Artifact) string {
	parts := []string{u.bucketPath(), artifact.Path}

	return strings.Join(parts, "/")
}

func (u *S3Uploader) bucketPath() string {
	return strings.Join(u.destinationParts()[1:len(u.destinationParts())], "/")
}

func (u *S3Uploader) bucketName() string {
	return u.destinationParts()[0]
}

func (u *S3Uploader) destinationParts() []string {
	trimmed := strings.TrimPrefix(u.Destination, "s3://")

	return strings.Split(trimmed, "/")
}

func (u *S3Uploader) mimeType(a *api.Artifact) string {
	extension := filepath.Ext(a.Path)
	mimeType := mime.TypeByExtension(extension)

	if mimeType != "" {
		return mimeType
	} else {
		return "binary/octet-stream"
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 Ole Krüger.

package dpt

import (
	"fmt"
)

// Switch is DPT 1.001.
type Switch bool

// Pack the datapoint value.
func (sw Switch) Pack() []byte {
	return packB1(bool(sw))
}

// Unpack the datapoint value from the given data.
func (sw *Switch) Unpack(data []byte) error {
	return unpackB1(data, (*bool)(sw))
}

// String generates a string representation.
func (sw Switch) String() string {
	if sw {
		return "On"
	}

	return "Off"
}

// ValueTemp is DPT 9.001.
type ValueTemp float32

// Pack the datapoint value.
func (temp ValueTemp) Pack() []byte {
	return packF16(float32(temp))
}

// Unpack the datapoint value from the given data.
func (temp *ValueTemp) Unpack(data []byte) error {
	return unpackF16(data, (*float32)(temp))
}

// String generates a string representation.
func (temp ValueTemp) String() string {
	return fmt.Sprintf("%.2f°C", float32(temp))
}
<commit_msg>Add DatapointValue interface<commit_after>// Copyright 2017 Ole Krüger.

package dpt

import (
	"fmt"
)

// A DatapointValue is a value of a datapoint.
type DatapointValue interface {
	Pack() []byte
	Unpack(data []byte) error
}

// Switch is DPT 1.001.
type Switch bool

// Pack the datapoint value.
func (sw Switch) Pack() []byte {
	return packB1(bool(sw))
}

// Unpack the datapoint value from the given data.
func (sw *Switch) Unpack(data []byte) error {
	return unpackB1(data, (*bool)(sw))
}

// String generates a string representation.
func (sw Switch) String() string {
	if sw {
		return "On"
	}

	return "Off"
}

// ValueTemp is DPT 9.001.
type ValueTemp float32

// Pack the datapoint value.
func (temp ValueTemp) Pack() []byte {
	return packF16(float32(temp))
}

// Unpack the datapoint value from the given data.
func (temp *ValueTemp) Unpack(data []byte) error {
	return unpackF16(data, (*float32)(temp))
}

// String generates a string representation.
func (temp ValueTemp) String() string {
	return fmt.Sprintf("%.2f°C", float32(temp))
}
<|endoftext|>


<commit_before>package wundergo_test

import (
	"log"
	"os"

	"github.com/nu7hatch/gouuid"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/robdimsdale/wundergo"
)

var (
	client wundergo.Client
)

func contains(lists *[]wundergo.List, list *wundergo.List) bool {
	for _, l := range *lists {
		if l == *list {
			return true
		}
	}
	return false
}

var _ = Describe("Wundergo library", func() {
	BeforeEach(func() {
		accessToken := os.Getenv("WL_ACCESS_TOKEN")
		clientID := os.Getenv("WL_CLIENT_ID")

		if accessToken == "" {
			log.Fatal("Error - WL_ACCESS_TOKEN must be provided")
		}

		if clientID == "" {
			log.Fatal("Error - WL_CLIENT_ID must be provided")
		}

		client = wundergo.NewOauthClient(accessToken, clientID)
	})

	Describe("Basic list functionality", func() {
		It("creates, updates and deletes new list", func() {
			uuid1, err := uuid.NewV4()
			Expect(err).NotTo(HaveOccurred())
			newListTitle1 := uuid1.String()

			uuid2, err := uuid.NewV4()
			Expect(err).NotTo(HaveOccurred())
			newListTitle2 := uuid2.String()

			originalLists, err := client.Lists()
			Expect(err).NotTo(HaveOccurred())

			newList, err := client.CreateList(newListTitle1)
			Expect(err).NotTo(HaveOccurred())

			newLists, err := client.Lists()
			Expect(err).NotTo(HaveOccurred())
			Expect(contains(newLists, newList)).To(BeTrue())

			newList.Title = newListTitle2
			updatedList, err := client.UpdateList(*newList)
			Expect(err).NotTo(HaveOccurred())
			newList.Revision = newList.Revision + 1
			Expect(updatedList).To(Equal(newList))

			_, err = client.TasksForListID(newList.ID)
			Expect(err).NotTo(HaveOccurred())

			task, err := client.CreateTask(
				"myTask",
				newList.ID,
				0,
				false,
				"",
				0,
				"1970-01-01",
				false,
			)
			newList.Revision = newList.Revision + 1
			Expect(err).NotTo(HaveOccurred())

			task.DueDate = "1971-01-01"
			task, err = client.UpdateTask(*task)
			newList.Revision = newList.Revision + 1
			Expect(err).NotTo(HaveOccurred())

			_, err = client.CreateNote("myContent", task.ID)
			newList.Revision = newList.Revision + 1
			Expect(err).NotTo(HaveOccurred())

			err = client.DeleteList(*newList)
			Expect(err).NotTo(HaveOccurred())

			afterDeleteLists, err := client.Lists()
			Expect(err).NotTo(HaveOccurred())

			Expect(afterDeleteLists).To(Equal(originalLists))
		})
	})
})
<commit_msg>Wrap integration test commands in Eventually.<commit_after>package wundergo_test

import (
	"log"
	"os"

	"github.com/nu7hatch/gouuid"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/robdimsdale/wundergo"
)

var (
	client wundergo.Client
)

func contains(lists *[]wundergo.List, list *wundergo.List) bool {
	for _, l := range *lists {
		if l == *list {
			return true
		}
	}
	return false
}

var _ = Describe("Wundergo library", func() {
	BeforeEach(func() {
		accessToken := os.Getenv("WL_ACCESS_TOKEN")
		clientID := os.Getenv("WL_CLIENT_ID")

		if accessToken == "" {
			log.Fatal("Error - WL_ACCESS_TOKEN must be provided")
		}

		if clientID == "" {
			log.Fatal("Error - WL_CLIENT_ID must be provided")
		}

		client = wundergo.NewOauthClient(accessToken, clientID)
	})

	Describe("Basic list functionality", func() {
		It("creates, updates and deletes new list", func() {
			uuid1, err := uuid.NewV4()
			Expect(err).NotTo(HaveOccurred())
			newListTitle1 := uuid1.String()

			uuid2, err := uuid.NewV4()
			Expect(err).NotTo(HaveOccurred())
			newListTitle2 := uuid2.String()

			var originalLists *[]wundergo.List
			Eventually(func() error {
				originalLists, err = client.Lists()
				return err
			}).ShouldNot(HaveOccurred())

			var newList *wundergo.List
			Eventually(func() error {
				newList, err = client.CreateList(newListTitle1)
				return err
			}).ShouldNot(HaveOccurred())

			var newLists *[]wundergo.List
			Eventually(func() error {
				newLists, err = client.Lists()
				return err
			}).ShouldNot(HaveOccurred())
			Expect(contains(newLists, newList)).To(BeTrue())

			newList.Title = newListTitle2
			var updatedList *wundergo.List
			Eventually(func() error {
				updatedList, err = client.UpdateList(*newList)
				return err
			}).ShouldNot(HaveOccurred())
			newList.Revision = newList.Revision + 1
			Expect(updatedList).To(Equal(newList))

			Eventually(func() error {
				_, err = client.TasksForListID(newList.ID)
				return err
			}).ShouldNot(HaveOccurred())

			var task *wundergo.Task
			Eventually(func() error {
				task, err = client.CreateTask(
					"myTask",
					newList.ID,
					0,
					false,
					"",
					0,
					"1970-01-01",
					false,
				)
				return err
			}).ShouldNot(HaveOccurred())
			newList.Revision = newList.Revision + 1

			task.DueDate = "1971-01-01"
			Eventually(func() error {
				task, err = client.UpdateTask(*task)
				return err
			}).ShouldNot(HaveOccurred())
			newList.Revision = newList.Revision + 1

			Eventually(func() error {
				_, err := client.CreateNote("myContent", task.ID)
				return err
			}).ShouldNot(HaveOccurred())
			newList.Revision = newList.Revision + 1

			Eventually(func() error {
				return client.DeleteList(*newList)
			}).ShouldNot(HaveOccurred())

			var afterDeleteLists *[]wundergo.List
			Eventually(func() error {
				afterDeleteLists, err = client.Lists()
				return err
			}).ShouldNot(HaveOccurred())

			Expect(afterDeleteLists).To(Equal(originalLists))
		})
	})
})
<|endoftext|>


<commit_before>package postgres

import (
	"fmt"
	"net/http"
	"testing"

	"github.com/nuveo/prest/api"
	. "github.com/smartystreets/goconvey/convey"
)

func TestWhereByRequest(t *testing.T) {
	Convey("Where by request without paginate", t, func() {
		r, err := http.NewRequest("GET", "/databases?dbname=prest&test=cool", nil)
		So(err, ShouldBeNil)
		where, values := WhereByRequest(r, 1)

		fmt.Println(where)
		fmt.Println(values)

		So(where, ShouldContainSubstring, "dbname=$")
		So(where, ShouldContainSubstring, "test=$")
		So(where, ShouldContainSubstring, " AND ")
		So(values, ShouldContain, "prest")
		So(values, ShouldContain, "cool")
	})

	Convey("Where by request with jsonb field", t, func() {
		r, err := http.NewRequest("GET", "/prest/public/test?name=nuveo&data->>description:jsonb=bla", nil)
		So(err, ShouldBeNil)
		where, values := WhereByRequest(r, 1)

		//fmt.Println(where)
		//fmt.Println(values)

		So(where, ShouldContainSubstring, "name=$")
		So(where, ShouldContainSubstring, "data->>'description'=$")
		So(where, ShouldContainSubstring, " AND ")

		So(values, ShouldContain, "nuveo")
		So(values, ShouldContain, "bla")
	})
}

func TestConnection(t *testing.T) {
	Convey("Verify database connection", t, func() {
		sqlx := Conn()
		So(sqlx, ShouldNotBeNil)
		err := sqlx.Ping()
		So(err, ShouldBeNil)
	})
}

func TestQuery(t *testing.T) {
	Convey("Query execution", t, func() {
		sql := "SELECT schema_name FROM information_schema.schemata ORDER BY schema_name ASC"
		json, err := Query(sql)
		So(err, ShouldBeNil)
		So(len(json), ShouldBeGreaterThan, 0)
	})

	Convey("Query execution with params", t, func() {
		sql := "SELECT schema_name FROM information_schema.schemata WHERE schema_name = $1 ORDER BY schema_name ASC"
		json, err := Query(sql, "public")
		So(err, ShouldBeNil)
		So(len(json), ShouldBeGreaterThan, 0)
	})
}

func TestPaginateIfPossible(t *testing.T) {
	Convey("Paginate if possible", t, func() {
		r, err := http.NewRequest("GET", "/databases?dbname=prest&test=cool&_page=1&_page_size=20", nil)
		So(err, ShouldBeNil)
		where := PaginateIfPossible(r)
		So(where, ShouldContainSubstring, "LIMIT 20 OFFSET(1 - 1) * 20")
	})
}

func TestInsert(t *testing.T) {
	Convey("Insert data into a table", t, func() {
		r := api.Request{
			Data: map[string]string{
				"name": "prest",
			},
		}
		json, err := Insert("prest", "public", "test", r)
		So(err, ShouldBeNil)
		So(len(json), ShouldBeGreaterThan, 0)
	})
}

func TestDelete(t *testing.T) {
	Convey("Delete data from table", t, func() {
		json, err := Delete("prest", "public", "test", "name=$1", []interface{}{"nuveo"})
		So(err, ShouldBeNil)
		So(len(json), ShouldBeGreaterThan, 0)
	})
}

func TestUpdate(t *testing.T) {
	Convey("Update data into a table", t, func() {
		r := api.Request{
			Data: map[string]string{
				"name": "prest",
			},
		}
		json, err := Update("prest", "public", "test", "name=$1", []interface{}{"prest"}, r)
		So(err, ShouldBeNil)
		So(len(json), ShouldBeGreaterThan, 0)
	})
}
<commit_msg>update tests<commit_after>package postgres

import (
	"fmt"
	"net/http"
	"testing"

	"github.com/nuveo/prest/api"
	. "github.com/smartystreets/goconvey/convey"
)

func TestWhereByRequest(t *testing.T) {
	Convey("Where by request without paginate", t, func() {
		r, err := http.NewRequest("GET", "/databases?dbname=prest&test=cool", nil)
		So(err, ShouldBeNil)
		where, values := WhereByRequest(r, 1)

		fmt.Println(where)
		fmt.Println(values)

		So(where, ShouldContainSubstring, "dbname=$")
		So(where, ShouldContainSubstring, "test=$")
		So(where, ShouldContainSubstring, " AND ")
		So(values, ShouldContain, "prest")
		So(values, ShouldContain, "cool")
	})

	Convey("Where by request with jsonb field", t, func() {
		r, err := http.NewRequest("GET", "/prest/public/test?name=nuveo&data->>description:jsonb=bla", nil)
		So(err, ShouldBeNil)
		where, values := WhereByRequest(r, 1)

		//fmt.Println(where)
		//fmt.Println(values)

		So(where, ShouldContainSubstring, "name=$")
		So(where, ShouldContainSubstring, "data->>'description'=$")
		So(where, ShouldContainSubstring, " AND ")

		So(values, ShouldContain, "nuveo")
		So(values, ShouldContain, "bla")
	})
}

func TestConnection(t *testing.T) {
	Convey("Verify database connection", t, func() {
		sqlx := Conn()
		So(sqlx, ShouldNotBeNil)
		err := sqlx.Ping()
		So(err, ShouldBeNil)
	})
}

func TestQuery(t *testing.T) {
	Convey("Query execution", t, func() {
		sql := "SELECT schema_name FROM information_schema.schemata ORDER BY schema_name ASC"
		json, err := Query(sql)
		So(err, ShouldBeNil)
		So(len(json), ShouldBeGreaterThan, 0)
	})

	Convey("Query execution with params", t, func() {
		sql := "SELECT schema_name FROM information_schema.schemata WHERE schema_name = $1 ORDER BY schema_name ASC"
		json, err := Query(sql, "public")
		So(err, ShouldBeNil)
		So(len(json), ShouldBeGreaterThan, 0)
	})
}

func TestPaginateIfPossible(t *testing.T) {
	Convey("Paginate if possible", t, func() {
		r, err := http.NewRequest("GET", "/databases?dbname=prest&test=cool&_page=1&_page_size=20", nil)
		So(err, ShouldBeNil)
		where, err := PaginateIfPossible(r)
		So(err, ShouldBeNil)
		So(where, ShouldContainSubstring, "LIMIT 20 OFFSET(1 - 1) * 20")
	})
}

func TestInsert(t *testing.T) {
	Convey("Insert data into a table", t, func() {
		r := api.Request{
			Data: map[string]string{
				"name": "prest",
			},
		}
		json, err := Insert("prest", "public", "test", r)
		So(err, ShouldBeNil)
		So(len(json), ShouldBeGreaterThan, 0)
	})
}

func TestDelete(t *testing.T) {
	Convey("Delete data from table", t, func() {
		json, err := Delete("prest", "public", "test", "name=$1", []interface{}{"nuveo"})
		So(err, ShouldBeNil)
		So(len(json), ShouldBeGreaterThan, 0)
	})
}

func TestUpdate(t *testing.T) {
	Convey("Update data into a table", t, func() {
		r := api.Request{
			Data: map[string]string{
				"name": "prest",
			},
		}
		json, err := Update("prest", "public", "test", "name=$1", []interface{}{"prest"}, r)
		So(err, ShouldBeNil)
		So(len(json), ShouldBeGreaterThan, 0)
	})
}
<|endoftext|>


<commit_before>package osmpbf

import (
	"code.google.com/p/goprotobuf/proto"
	"github.com/qedus/osmpbf/OSMPBF"
)

// Decoder for Blob with OSMData (PrimitiveBlock)
type dataDecoder struct {
	q []interface{}
}

func newDataDecoder() *dataDecoder {
	return &dataDecoder{make([]interface{}, 0, 8000)} // typical PrimitiveBlock contains 8k OSM entities

}

func (dec *dataDecoder) Decode(blob *OSMPBF.Blob) ([]interface{}, error) {
	dec.q = dec.q[:0]

	data, err := getData(blob)
	if err != nil {
		return nil, err
	}

	primitiveBlock := &OSMPBF.PrimitiveBlock{}
	if err := proto.Unmarshal(data, primitiveBlock); err != nil {
		return nil, err
	}

	dec.parsePrimitiveBlock(primitiveBlock)
	return dec.q, nil
}

func (dec *dataDecoder) parsePrimitiveBlock(pb *OSMPBF.PrimitiveBlock) {
	for _, pg := range pb.GetPrimitivegroup() {
		dec.parsePrimitiveGroup(pb, pg)
	}
}

func (dec *dataDecoder) parsePrimitiveGroup(pb *OSMPBF.PrimitiveBlock, pg *OSMPBF.PrimitiveGroup) {
	dec.parseNodes(pb, pg.GetNodes())
	dec.parseDenseNodes(pb, pg.GetDense())
	dec.parseWays(pb, pg.GetWays())
	dec.parseRelations(pb, pg.GetRelations())
}

func (dec *dataDecoder) parseNodes(pb *OSMPBF.PrimitiveBlock, nodes []*OSMPBF.Node) {
	st := pb.GetStringtable().GetS()
	granularity := int64(pb.GetGranularity())
	latOffset := pb.GetLatOffset()
	lonOffset := pb.GetLonOffset()

	for _, node := range nodes {
		id := node.GetId()
		lat := node.GetLat()
		lon := node.GetLon()

		latitude := 1e-9 * float64((latOffset + (granularity * lat)))
		longitude := 1e-9 * float64((lonOffset + (granularity * lon)))

		tags := extractTags(st, node.GetKeys(), node.GetVals())

		panic("Please test this first")

		dec.q = append(dec.q, &Node{id, latitude, longitude, tags})
	}

}

func (dec *dataDecoder) parseDenseNodes(pb *OSMPBF.PrimitiveBlock, dn *OSMPBF.DenseNodes) {
	st := pb.GetStringtable().GetS()
	granularity := int64(pb.GetGranularity())
	latOffset := pb.GetLatOffset()
	lonOffset := pb.GetLonOffset()
	ids := dn.GetId()
	lats := dn.GetLat()
	lons := dn.GetLon()
	tu := tagUnpacker{st, dn.GetKeysVals(), 0}
	var id, lat, lon int64
	for index := range ids {
		id = ids[index] + id
		lat = lats[index] + lat
		lon = lons[index] + lon
		latitude := 1e-9 * float64((latOffset + (granularity * lat)))
		longitude := 1e-9 * float64((lonOffset + (granularity * lon)))
		tags := tu.next()

		dec.q = append(dec.q, &Node{id, latitude, longitude, tags})
	}
}

func (dec *dataDecoder) parseWays(pb *OSMPBF.PrimitiveBlock, ways []*OSMPBF.Way) {
	st := pb.GetStringtable().GetS()
	for _, way := range ways {
		id := way.GetId()

		tags := extractTags(st, way.GetKeys(), way.GetVals())

		refs := way.GetRefs()
		var nodeID int64
		nodeIDs := make([]int64, len(refs))
		for index := range refs {
			nodeID = refs[index] + nodeID // delta encoding
			nodeIDs[index] = nodeID
		}

		dec.q = append(dec.q, &Way{id, tags, nodeIDs})
	}
}

// Make relation members from stringtable and three parallel arrays of IDs.
func extractMembers(stringTable []string, rel *OSMPBF.Relation) []Member {
	memIDs := rel.GetMemids()
	types := rel.GetTypes()
	roleIDs := rel.GetRolesSid()

	var memID int64
	members := make([]Member, len(memIDs))
	for index := range memIDs {
		memID = memIDs[index] + memID // delta encoding

		var memType MemberType
		switch types[index] {
		case OSMPBF.Relation_NODE:
			memType = NodeType
		case OSMPBF.Relation_WAY:
			memType = WayType
		case OSMPBF.Relation_RELATION:
			memType = RelationType
		}

		role := stringTable[roleIDs[index]]

		members[index] = Member{memID, memType, role}
	}

	return members
}

func (dec *dataDecoder) parseRelations(pb *OSMPBF.PrimitiveBlock, relations []*OSMPBF.Relation) {
	st := pb.GetStringtable().GetS()
	for _, rel := range relations {
		id := rel.GetId()
		tags := extractTags(st, rel.GetKeys(), rel.GetVals())
		members := extractMembers(st, rel)

		dec.q = append(dec.q, &Relation{id, tags, members})
	}
}
<commit_msg>Do not share decode result.<commit_after>package osmpbf

import (
	"code.google.com/p/goprotobuf/proto"
	"github.com/qedus/osmpbf/OSMPBF"
)

// Decoder for Blob with OSMData (PrimitiveBlock)
type dataDecoder struct {
	q []interface{}
}

func newDataDecoder() *dataDecoder {
	return &dataDecoder{}
}

func (dec *dataDecoder) Decode(blob *OSMPBF.Blob) ([]interface{}, error) {
	dec.q = make([]interface{}, 0, 8000) // typical PrimitiveBlock contains 8k OSM entities

	data, err := getData(blob)
	if err != nil {
		return nil, err
	}

	primitiveBlock := &OSMPBF.PrimitiveBlock{}
	if err := proto.Unmarshal(data, primitiveBlock); err != nil {
		return nil, err
	}

	dec.parsePrimitiveBlock(primitiveBlock)
	return dec.q, nil
}

func (dec *dataDecoder) parsePrimitiveBlock(pb *OSMPBF.PrimitiveBlock) {
	for _, pg := range pb.GetPrimitivegroup() {
		dec.parsePrimitiveGroup(pb, pg)
	}
}

func (dec *dataDecoder) parsePrimitiveGroup(pb *OSMPBF.PrimitiveBlock, pg *OSMPBF.PrimitiveGroup) {
	dec.parseNodes(pb, pg.GetNodes())
	dec.parseDenseNodes(pb, pg.GetDense())
	dec.parseWays(pb, pg.GetWays())
	dec.parseRelations(pb, pg.GetRelations())
}

func (dec *dataDecoder) parseNodes(pb *OSMPBF.PrimitiveBlock, nodes []*OSMPBF.Node) {
	st := pb.GetStringtable().GetS()
	granularity := int64(pb.GetGranularity())
	latOffset := pb.GetLatOffset()
	lonOffset := pb.GetLonOffset()

	for _, node := range nodes {
		id := node.GetId()
		lat := node.GetLat()
		lon := node.GetLon()

		latitude := 1e-9 * float64((latOffset + (granularity * lat)))
		longitude := 1e-9 * float64((lonOffset + (granularity * lon)))

		tags := extractTags(st, node.GetKeys(), node.GetVals())

		panic("Please test this first")

		dec.q = append(dec.q, &Node{id, latitude, longitude, tags})
	}

}

func (dec *dataDecoder) parseDenseNodes(pb *OSMPBF.PrimitiveBlock, dn *OSMPBF.DenseNodes) {
	st := pb.GetStringtable().GetS()
	granularity := int64(pb.GetGranularity())
	latOffset := pb.GetLatOffset()
	lonOffset := pb.GetLonOffset()
	ids := dn.GetId()
	lats := dn.GetLat()
	lons := dn.GetLon()
	tu := tagUnpacker{st, dn.GetKeysVals(), 0}
	var id, lat, lon int64
	for index := range ids {
		id = ids[index] + id
		lat = lats[index] + lat
		lon = lons[index] + lon
		latitude := 1e-9 * float64((latOffset + (granularity * lat)))
		longitude := 1e-9 * float64((lonOffset + (granularity * lon)))
		tags := tu.next()

		dec.q = append(dec.q, &Node{id, latitude, longitude, tags})
	}
}

func (dec *dataDecoder) parseWays(pb *OSMPBF.PrimitiveBlock, ways []*OSMPBF.Way) {
	st := pb.GetStringtable().GetS()
	for _, way := range ways {
		id := way.GetId()

		tags := extractTags(st, way.GetKeys(), way.GetVals())

		refs := way.GetRefs()
		var nodeID int64
		nodeIDs := make([]int64, len(refs))
		for index := range refs {
			nodeID = refs[index] + nodeID // delta encoding
			nodeIDs[index] = nodeID
		}

		dec.q = append(dec.q, &Way{id, tags, nodeIDs})
	}
}

// Make relation members from stringtable and three parallel arrays of IDs.
func extractMembers(stringTable []string, rel *OSMPBF.Relation) []Member {
	memIDs := rel.GetMemids()
	types := rel.GetTypes()
	roleIDs := rel.GetRolesSid()

	var memID int64
	members := make([]Member, len(memIDs))
	for index := range memIDs {
		memID = memIDs[index] + memID // delta encoding

		var memType MemberType
		switch types[index] {
		case OSMPBF.Relation_NODE:
			memType = NodeType
		case OSMPBF.Relation_WAY:
			memType = WayType
		case OSMPBF.Relation_RELATION:
			memType = RelationType
		}

		role := stringTable[roleIDs[index]]

		members[index] = Member{memID, memType, role}
	}

	return members
}

func (dec *dataDecoder) parseRelations(pb *OSMPBF.PrimitiveBlock, relations []*OSMPBF.Relation) {
	st := pb.GetStringtable().GetS()
	for _, rel := range relations {
		id := rel.GetId()
		tags := extractTags(st, rel.GetKeys(), rel.GetVals())
		members := extractMembers(st, rel)

		dec.q = append(dec.q, &Relation{id, tags, members})
	}
}
<|endoftext|>


<commit_before>package delmo

import (
	"bytes"
	"fmt"
	"os"
	"sync"
)

type Suite struct {
	options               CLIOptions
	config                *Config
	globalTaskEnvironment TaskEnvironment
	tests                 []TestConfig
}

func NewSuite(options CLIOptions, config *Config, globalTaskEnvironment TaskEnvironment) (*Suite, error) {
	suite := &Suite{
		options:               options,
		config:                config,
		globalTaskEnvironment: globalTaskEnvironment,
	}
	tests, err := suite.testsToRun(options.Tests, config.Tests)
	if err != nil {
		return nil, err
	}
	suite.tests = tests
	return suite, nil
}

func (s *Suite) Run() int {
	fmt.Printf("Running Test Suite for System %s\n", s.config.Suite.Name)
	executing := "Tests to execute: "
	for _, t := range s.tests {
		executing += t.Name + ", "
	}
	fmt.Printf(executing + "\n")
	err := s.initializeSystem()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		return 1
	}

	failed := []*TestReport{}
	succeeded := []*TestReport{}

	var wg sync.WaitGroup
	for _, test := range s.tests {
		wg.Add(1)
		fmt.Printf("Running test '%s'...\n", test.Name)
		runner := NewTestRunner(test, s.config.Tasks, s.globalTaskEnvironment)
		runtime, err := NewDockerCompose(s.config.Suite.System, test.Name)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error creating runtime for '%s'\n%s\n", test.Name, err)
			continue
		}
		go func() {
			defer wg.Done()

			// Capture the name because the test variable will change
			testName := test.Name

			var output TestOutput
			var outputBytes bytes.Buffer
			if s.options.ParallelExecution {
				output.Stdout = &outputBytes
				output.Stderr = &outputBytes
			} else {
				output = TestOutput{
					Stdout: os.Stdout,
					Stderr: os.Stderr,
				}
			}

			report := runner.RunTest(runtime, output)
			if report.Success {
				succeeded = append(succeeded, report)
				fmt.Printf("Test '%s' completed sucessfully!\n", testName)
			} else {
				failed = append(failed, report)
				fmt.Printf("Test '%s' Failed!\n%s\n", testName, report.Error)
				if s.options.ParallelExecution {
					fmt.Printf("Output from test '%s'\n%s\n", testName, outputBytes)
				}
			}
		}()

		if s.options.ParallelExecution == false {
			wg.Wait()
			fmt.Println("")
		}
	}

	if s.options.ParallelExecution == true {
		wg.Wait()
		fmt.Println("")
	}

	outputSummary(failed, succeeded)
	if len(failed) != 0 {
		return 1
	}
	return 0
}

func outputSummary(failed []*TestReport, succeeded []*TestReport) {
	fmt.Printf("SUMMARY:\n%d tests succeeded\n%d tests failed\n",
		len(succeeded),
		len(failed))
}

func (s *Suite) initializeSystem() error {
	dc, err := NewDockerCompose(s.config.Suite.System, "")
	if err != nil {
		return fmt.Errorf("Could not initialize docker-compose\n%s", err)
	}

	if s.options.SkipPull != true {
		fmt.Printf("\nPulling images for system %s...\n", s.config.Suite.Name)
		err = dc.Pull()
		if err != nil {
			return fmt.Errorf(fmt.Sprintf("Error pulling images\n%s\n", err))
		}
	}

	fmt.Printf("\nBuiling images for system %s...\n", s.config.Suite.Name)
	if s.options.OnlyBuildTask {
		err = dc.Build(s.config.Suite.TaskService)
	} else {
		err = dc.Build()
	}
	if err != nil {
		return fmt.Errorf("Could not build system\n%s", err)
	}

	fmt.Println("")

	return nil
}

func (s *Suite) testsToRun(testNames []string, allTests []TestConfig) ([]TestConfig, error) {
	if len(testNames) == 0 {
		return allTests, nil
	}
	var tests []TestConfig
	for _, n := range testNames {
		found := false
		for _, t := range allTests {
			if n == t.Name {
				tests = append(tests, t)
				found = true
				break
			}
		}
		if found == false {
			return nil, fmt.Errorf("Couldn't find test named: %s", n)
		}
	}
	return tests, nil
}
<commit_msg>Formatting<commit_after>package delmo

import (
	"bytes"
	"fmt"
	"os"
	"sync"
)

type Suite struct {
	options               CLIOptions
	config                *Config
	globalTaskEnvironment TaskEnvironment
	tests                 []TestConfig
}

func NewSuite(options CLIOptions, config *Config, globalTaskEnvironment TaskEnvironment) (*Suite, error) {
	suite := &Suite{
		options:               options,
		config:                config,
		globalTaskEnvironment: globalTaskEnvironment,
	}
	tests, err := suite.testsToRun(options.Tests, config.Tests)
	if err != nil {
		return nil, err
	}
	suite.tests = tests
	return suite, nil
}

func (s *Suite) Run() int {
	fmt.Printf("Running Test Suite for System %s\n", s.config.Suite.Name)
	executing := "Tests to execute: "
	for _, t := range s.tests {
		executing += t.Name + ", "
	}
	fmt.Printf(executing + "\n")

	err := s.initializeSystem()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		return 1
	}

	failed := []*TestReport{}
	succeeded := []*TestReport{}

	var wg sync.WaitGroup
	for _, test := range s.tests {
		wg.Add(1)
		fmt.Printf("Running test '%s'...\n", test.Name)
		runner := NewTestRunner(test, s.config.Tasks, s.globalTaskEnvironment)
		runtime, err := NewDockerCompose(s.config.Suite.System, test.Name)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error creating runtime for '%s'\n%s\n", test.Name, err)
			continue
		}

		go func() {
			defer wg.Done()

			// Capture the name because the test variable will change
			testName := test.Name

			var output TestOutput
			var outputBytes bytes.Buffer
			if s.options.ParallelExecution {
				output.Stdout = &outputBytes
				output.Stderr = &outputBytes
			} else {
				output = TestOutput{
					Stdout: os.Stdout,
					Stderr: os.Stderr,
				}
			}

			report := runner.RunTest(runtime, output)
			if report.Success {
				succeeded = append(succeeded, report)
				fmt.Printf("Test '%s' completed sucessfully!\n", testName)
			} else {
				failed = append(failed, report)
				fmt.Printf("Test '%s' Failed!\n%s\n", testName, report.Error)
				if s.options.ParallelExecution {
					fmt.Printf("Output from test '%s'\n%s\n", testName, outputBytes)
				}
			}
		}()

		if s.options.ParallelExecution == false {
			wg.Wait()
			fmt.Println("")
		}
	}

	if s.options.ParallelExecution == true {
		wg.Wait()
		fmt.Println("")
	}

	outputSummary(failed, succeeded)
	if len(failed) != 0 {
		return 1
	}
	return 0
}

func outputSummary(failed []*TestReport, succeeded []*TestReport) {
	fmt.Printf("SUMMARY:\n%d tests succeeded\n%d tests failed\n",
		len(succeeded),
		len(failed))
}

func (s *Suite) initializeSystem() error {
	dc, err := NewDockerCompose(s.config.Suite.System, "")
	if err != nil {
		return fmt.Errorf("Could not initialize docker-compose\n%s", err)
	}

	if s.options.SkipPull != true {
		fmt.Printf("\nPulling images for system %s...\n", s.config.Suite.Name)
		err = dc.Pull()
		if err != nil {
			return fmt.Errorf(fmt.Sprintf("Error pulling images\n%s\n", err))
		}
	}

	fmt.Printf("\nBuiling images for system %s...\n", s.config.Suite.Name)
	if s.options.OnlyBuildTask {
		err = dc.Build(s.config.Suite.TaskService)
	} else {
		err = dc.Build()
	}
	if err != nil {
		return fmt.Errorf("Could not build system\n%s", err)
	}

	fmt.Println("")

	return nil
}

func (s *Suite) testsToRun(testNames []string, allTests []TestConfig) ([]TestConfig, error) {
	if len(testNames) == 0 {
		return allTests, nil
	}
	var tests []TestConfig
	for _, n := range testNames {
		found := false
		for _, t := range allTests {
			if n == t.Name {
				tests = append(tests, t)
				found = true
				break
			}
		}
		if found == false {
			return nil, fmt.Errorf("Couldn't find test named: %s", n)
		}
	}
	return tests, nil
}
<|endoftext|>