<commit_before>package host

import (
	"bytes"
	"testing"

	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

// announcementFinder is a quick module that parses the blockchain for host
// announcements, keeping a record of all the announcements that get found.
type announcementFinder struct {
	cs modules.ConsensusSet

	// Announcements that have been seen. The two slices are wedded.
	netAddresses []modules.NetAddress
	publicKeys   []types.SiaPublicKey
}

// ProcessConsensusChange receives consensus changes from the consensus set and
// parses them for valid host announcements.
func (af *announcementFinder) ProcessConsensusChange(cc modules.ConsensusChange) {
	for _, block := range cc.AppliedBlocks {
		for _, txn := range block.Transactions {
			for _, arb := range txn.ArbitraryData {
				addr, pubKey, err := modules.DecodeAnnouncement(arb)
				if err == nil {
					af.netAddresses = append(af.netAddresses, addr)
					af.publicKeys = append(af.publicKeys, pubKey)
				}
			}
		}
	}
}

// Close will shut down the announcement finder.
func (af *announcementFinder) Close() error {
	af.cs.Unsubscribe(af)
	return nil
}

// newAnnouncementFinder will create and return an announcement finder.
func newAnnouncementFinder(cs modules.ConsensusSet) (*announcementFinder, error) {
	af := &announcementFinder{
		cs: cs,
	}
	err := cs.ConsensusSetSubscribe(af, modules.ConsensusChangeBeginning, make(chan struct{}))
	if err != nil {
		return nil, err
	}
	return af, nil
}

// TestHostAnnounce checks that the host announce function is operating
// correctly.
func TestHostAnnounce(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	ht, err := newHostTester("TestHostAnnounce")
	if err != nil {
		t.Fatal(err)
	}
	defer ht.Close()

	// Create an announcement finder to scan the blockchain for host
	// announcements.
	af, err := newAnnouncementFinder(ht.cs)
	if err != nil {
		t.Fatal(err)
	}
	defer af.Close()

	// Create an announcement, then use the address finding module to scan the
	// blockchain for the host's address.
	err = ht.host.Announce()
	if err != nil {
		t.Fatal(err)
	}
	_, err = ht.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}
	if len(af.publicKeys) != 1 {
		t.Fatal("could not find host announcement in blockchain")
	}
	if af.netAddresses[0] != ht.host.autoAddress {
		t.Error("announcement has wrong address")
	}
	if !bytes.Equal(af.publicKeys[0].Key, ht.host.publicKey.Key) {
		t.Error("announcement has wrong host key")
	}
}

// TestHostAnnounceAddress checks that the host announce address function is
// operating correctly.
func TestHostAnnounceAddress(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	ht, err := newHostTester("TestHostAnnounceAddress")
	if err != nil {
		t.Fatal(err)
	}
	defer ht.Close()

	// Create an announcement finder to scan the blockchain for host
	// announcements.
	af, err := newAnnouncementFinder(ht.cs)
	if err != nil {
		t.Fatal(err)
	}
	defer af.Close()

	// Create an announcement, then use the address finding module to scan the
	// blockchain for the host's address.
	addr := modules.NetAddress("foo.com:1234")
	err = ht.host.AnnounceAddress(addr)
	if err != nil {
		t.Fatal(err)
	}
	_, err = ht.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}
	if len(af.netAddresses) != 1 {
		t.Fatal("could not find host announcement in blockchain")
	}
	if af.netAddresses[0] != addr {
		t.Error("announcement has wrong address")
	}
	if !bytes.Equal(af.publicKeys[0].Key, ht.host.publicKey.Key) {
		t.Error("announcement has wrong host key")
	}
}
<commit_msg>replaced make with nil channel<commit_after>package host

import (
	"bytes"
	"testing"

	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

// announcementFinder is a quick module that parses the blockchain for host
// announcements, keeping a record of all the announcements that get found.
type announcementFinder struct {
	cs modules.ConsensusSet

	// Announcements that have been seen. The two slices are wedded.
	netAddresses []modules.NetAddress
	publicKeys   []types.SiaPublicKey
}

// ProcessConsensusChange receives consensus changes from the consensus set and
// parses them for valid host announcements.
func (af *announcementFinder) ProcessConsensusChange(cc modules.ConsensusChange) {
	for _, block := range cc.AppliedBlocks {
		for _, txn := range block.Transactions {
			for _, arb := range txn.ArbitraryData {
				addr, pubKey, err := modules.DecodeAnnouncement(arb)
				if err == nil {
					af.netAddresses = append(af.netAddresses, addr)
					af.publicKeys = append(af.publicKeys, pubKey)
				}
			}
		}
	}
}

// Close will shut down the announcement finder.
func (af *announcementFinder) Close() error {
	af.cs.Unsubscribe(af)
	return nil
}

// newAnnouncementFinder will create and return an announcement finder.
func newAnnouncementFinder(cs modules.ConsensusSet) (*announcementFinder, error) {
	af := &announcementFinder{
		cs: cs,
	}
	err := cs.ConsensusSetSubscribe(af, modules.ConsensusChangeBeginning, nil)
	if err != nil {
		return nil, err
	}
	return af, nil
}

// TestHostAnnounce checks that the host announce function is operating
// correctly.
func TestHostAnnounce(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	ht, err := newHostTester("TestHostAnnounce")
	if err != nil {
		t.Fatal(err)
	}
	defer ht.Close()

	// Create an announcement finder to scan the blockchain for host
	// announcements.
	af, err := newAnnouncementFinder(ht.cs)
	if err != nil {
		t.Fatal(err)
	}
	defer af.Close()

	// Create an announcement, then use the address finding module to scan the
	// blockchain for the host's address.
	err = ht.host.Announce()
	if err != nil {
		t.Fatal(err)
	}
	_, err = ht.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}
	if len(af.publicKeys) != 1 {
		t.Fatal("could not find host announcement in blockchain")
	}
	if af.netAddresses[0] != ht.host.autoAddress {
		t.Error("announcement has wrong address")
	}
	if !bytes.Equal(af.publicKeys[0].Key, ht.host.publicKey.Key) {
		t.Error("announcement has wrong host key")
	}
}

// TestHostAnnounceAddress checks that the host announce address function is
// operating correctly.
func TestHostAnnounceAddress(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	ht, err := newHostTester("TestHostAnnounceAddress")
	if err != nil {
		t.Fatal(err)
	}
	defer ht.Close()

	// Create an announcement finder to scan the blockchain for host
	// announcements.
	af, err := newAnnouncementFinder(ht.cs)
	if err != nil {
		t.Fatal(err)
	}
	defer af.Close()

	// Create an announcement, then use the address finding module to scan the
	// blockchain for the host's address.
	addr := modules.NetAddress("foo.com:1234")
	err = ht.host.AnnounceAddress(addr)
	if err != nil {
		t.Fatal(err)
	}
	_, err = ht.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}
	if len(af.netAddresses) != 1 {
		t.Fatal("could not find host announcement in blockchain")
	}
	if af.netAddresses[0] != addr {
		t.Error("announcement has wrong address")
	}
	if !bytes.Equal(af.publicKeys[0].Key, ht.host.publicKey.Key) {
		t.Error("announcement has wrong host key")
	}
}
<|endoftext|>


<commit_before>package setting

import (
	"os"
	"reflect"
	"testing"
)

func setenv(m map[string]string) {
	for k, v := range m {
		err := os.Setenv(k, v)
		if err != nil {
			panic(err)
		}
	}
}

func unsetenv(m map[string]string) {
	for k, _ := range m {
		err := os.Unsetenv(k)
		if err != nil {
			panic(err)
		}
	}
}

func TestRoundFlags(t *testing.T) {
	os.Unsetenv("AWS_DEFAULT_REGION")
	type want struct {
		o       []string
		region  string
		profile string
	}
	tests := []struct {
		in  []string
		env map[string]string
		w   want
	}{
		{
			[]string{"-foo", "-bar", "-baz"},
			nil,
			want{
				[]string{"-foo", "-bar", "-baz"},
				"",
				"default",
			},
		},
		{
			[]string{"foo", "bar", "baz"},
			nil,
			want{
				[]string{"foo", "bar", "baz"},
				"",
				"default",
			},
		},
		{
			[]string{"-region", "bar", "baz"},
			nil,
			want{
				[]string{"baz"},
				"bar",
				"default",
			},
		},
		{
			[]string{"-region=bar", "baz"},
			nil,
			want{
				[]string{"baz"},
				"bar",
				"default",
			},
		},
		{
			[]string{"-profile", "hoge", "baz"},
			nil,
			want{
				[]string{"baz"},
				"",
				"hoge",
			},
		},
		{
			[]string{"-profile=hoge", "baz"},
			nil,
			want{
				[]string{"baz"},
				"",
				"hoge",
			},
		},
		{
			[]string{"-profile", "hoge", "baz", "-region", "ap-northeast-1"},
			nil,
			want{
				[]string{"baz"},
				"ap-northeast-1",
				"hoge",
			},
		},
		{
			[]string{"-profile", "hoge", "baz", "-region=ap-northeast-1"},
			nil,
			want{
				[]string{"baz"},
				"ap-northeast-1",
				"hoge",
			},
		},
		{
			[]string{"-profile=hoge", "baz", "-region", "ap-northeast-1"},
			nil,
			want{
				[]string{"baz"},
				"ap-northeast-1",
				"hoge",
			},
		},
		{
			[]string{"-profile=hoge", "baz", "-region=ap-northeast-1"},
			nil,
			want{
				[]string{"baz"},
				"ap-northeast-1",
				"hoge",
			},
		},
		{
			[]string{"-profile=", "baz", "-region=ap-northeast-1"},
			nil,
			want{
				[]string{"baz"},
				"ap-northeast-1",
				"",
			},
		},
		{
			[]string{"-profile=hoge", "baz", "-region="},
			nil,
			want{
				[]string{"baz"},
				"",
				"hoge",
			},
		},
		{
			[]string{"-profile=", "baz", "-region="},
			nil,
			want{
				[]string{"baz"},
				"",
				"",
			},
		},
		{
			[]string{},
			nil,
			want{
				[]string{},
				"",
				"default",
			},
		},
		{
			[]string{},
			map[string]string{},
			want{
				[]string{},
				"",
				"default",
			},
		},
		{
			nil,
			map[string]string{},
			want{
				[]string{},
				"",
				"default",
			},
		},
		{
			nil,
			map[string]string{},
			want{
				nil,
				"",
				"default",
			},
		},
		{
			[]string{},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "",
			},
			want{
				[]string{},
				"",
				"default",
			},
		},
		{
			[]string{"bar"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "",
			},
			want{
				[]string{"bar"},
				"",
				"default",
			},
		},
		{
			[]string{"bar"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"default",
			},
		},
		{
			[]string{"bar"},
			map[string]string{
				"AWS_PROFILE_NAME": "hoge",
				"AWS_DEFAULT_REGION":       "",
			},
			want{
				[]string{"bar"},
				"",
				"hoge",
			},
		},
		{
			[]string{"bar"},
			map[string]string{
				"AWS_PROFILE_NAME": "hoge",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"hoge",
			},
		},
		{
			[]string{"bar", "-profile=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"hoge",
			},
		},
		{
			[]string{"bar", "-profile=-profile=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"-profile=hoge",
			},
		},
		{
			[]string{"bar", "-profile", "hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"hoge",
			},
		},
		{
			[]string{"bar", "-profile", "-profile=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"-profile=hoge",
			},
		},
		{
			[]string{"bar", "-region=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"hoge",
				"default",
			},
		},
		{
			[]string{"bar", "-region=-profile=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"-profile=hoge",
				"default",
			},
		},
		{
			[]string{"bar", "-region", "hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"hoge",
				"default",
			},
		},
		{
			[]string{"bar", "-region", "-profile=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"-profile=hoge",
				"default",
			},
		},
		{
			[]string{"bar", "-profile=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"hoge",
			},
		},
		{
			[]string{"bar", "-profile=-region=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"-region=hoge",
			},
		},
		{
			[]string{"bar", "-profile", "hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"hoge",
			},
		},
		{
			[]string{"bar", "-profile", "-region=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"-region=hoge",
			},
		},
		{
			[]string{"bar", "-region=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"hoge",
				"default",
			},
		},
		{
			[]string{"bar", "-region", "hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"hoge",
				"default",
			},
		},
		{
			[]string{"bar", "-region=hoge", "-profile=huga"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"hoge",
				"huga",
			},
		},
		{
			[]string{"bar", "-region=-profile=hoge", "-profile=huga"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"-profile=hoge",
				"huga",
			},
		},
		{
			[]string{"bar", "-region", "hoge", "-profile", "huga"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"hoge",
				"huga",
			},
		},
		{
			[]string{"bar", "-region", "-profile=hoge", "-profile", "huga"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"-profile=hoge",
				"huga",
			},
		},
	}

	for i, test := range tests {
		setenv(test.env)
		o, r, p := roundFlags(test.in)
		if (!reflect.DeepEqual(o, test.w.o) && (len(o) != 0 || len(test.w.o) != 0)) ||
			!reflect.DeepEqual(r, test.w.region) ||
			!reflect.DeepEqual(p, test.w.profile) {
			t.Fatalf("%d: want: %v, but: %v", i, test.w, want{
				o,
				r,
				p,
			})
		}
		unsetenv(test.env)
	}
}
<commit_msg>テスト側の修正<commit_after>package setting

import (
	"os"
	"reflect"
	"testing"
)

func setenv(m map[string]string) {
	for k, v := range m {
		err := os.Setenv(k, v)
		if err != nil {
			panic(err)
		}
	}
}

func unsetenv(m map[string]string) {
	for k, _ := range m {
		err := os.Unsetenv(k)
		if err != nil {
			panic(err)
		}
	}
}

func TestRoundFlags(t *testing.T) {
	os.Unsetenv("AWS_DEFAULT_REGION")
	type want struct {
		o       []string
		region  string
		profile string
	}
	tests := []struct {
		in  []string
		env map[string]string
		w   want
	}{
		{
			[]string{"-foo", "-bar", "-baz"},
			nil,
			want{
				[]string{"-foo", "-bar", "-baz"},
				"",
				"default",
			},
		},
		{
			[]string{"foo", "bar", "baz"},
			nil,
			want{
				[]string{"foo", "bar", "baz"},
				"",
				"default",
			},
		},
		{
			[]string{"-region", "bar", "baz"},
			nil,
			want{
				[]string{"baz"},
				"bar",
				"default",
			},
		},
		{
			[]string{"-region=bar", "baz"},
			nil,
			want{
				[]string{"baz"},
				"bar",
				"default",
			},
		},
		{
			[]string{"-profile", "hoge", "baz"},
			nil,
			want{
				[]string{"baz"},
				"",
				"hoge",
			},
		},
		{
			[]string{"-profile=hoge", "baz"},
			nil,
			want{
				[]string{"baz"},
				"",
				"hoge",
			},
		},
		{
			[]string{"-profile", "hoge", "baz", "-region", "ap-northeast-1"},
			nil,
			want{
				[]string{"baz"},
				"ap-northeast-1",
				"hoge",
			},
		},
		{
			[]string{"-profile", "hoge", "baz", "-region=ap-northeast-1"},
			nil,
			want{
				[]string{"baz"},
				"ap-northeast-1",
				"hoge",
			},
		},
		{
			[]string{"-profile=hoge", "baz", "-region", "ap-northeast-1"},
			nil,
			want{
				[]string{"baz"},
				"ap-northeast-1",
				"hoge",
			},
		},
		{
			[]string{"-profile=hoge", "baz", "-region=ap-northeast-1"},
			nil,
			want{
				[]string{"baz"},
				"ap-northeast-1",
				"hoge",
			},
		},
		{
			[]string{"-profile=", "baz", "-region=ap-northeast-1"},
			nil,
			want{
				[]string{"baz"},
				"ap-northeast-1",
				"",
			},
		},
		{
			[]string{"-profile=hoge", "baz", "-region="},
			nil,
			want{
				[]string{"baz"},
				"",
				"hoge",
			},
		},
		{
			[]string{"-profile=", "baz", "-region="},
			nil,
			want{
				[]string{"baz"},
				"",
				"",
			},
		},
		{
			[]string{},
			nil,
			want{
				[]string{},
				"",
				"default",
			},
		},
		{
			[]string{},
			map[string]string{},
			want{
				[]string{},
				"",
				"default",
			},
		},
		{
			nil,
			map[string]string{},
			want{
				[]string{},
				"",
				"default",
			},
		},
		{
			nil,
			map[string]string{},
			want{
				nil,
				"",
				"default",
			},
		},
		{
			[]string{},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "",
			},
			want{
				[]string{},
				"",
				"default",
			},
		},
		{
			[]string{"bar"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "",
			},
			want{
				[]string{"bar"},
				"",
				"default",
			},
		},
		{
			[]string{"bar"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"default",
			},
		},
		{
			[]string{"bar"},
			map[string]string{
				"AWS_PROFILE_NAME": "hoge",
				"AWS_DEFAULT_REGION":       "",
			},
			want{
				[]string{"bar"},
				"",
				"hoge",
			},
		},
		{
			[]string{"bar"},
			map[string]string{
				"AWS_PROFILE_NAME": "hoge",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"hoge",
			},
		},
		{
			[]string{"bar", "-profile=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"hoge",
			},
		},
		{
			[]string{"bar", "-profile=-profile=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"-profile=hoge",
			},
		},
		{
			[]string{"bar", "-profile", "hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"hoge",
			},
		},
		{
			[]string{"bar", "-profile", "-profile=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"-profile=hoge",
			},
		},
		{
			[]string{"bar", "-region=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"hoge",
				"default",
			},
		},
		{
			[]string{"bar", "-region=-profile=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"-profile=hoge",
				"default",
			},
		},
		{
			[]string{"bar", "-region", "hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"hoge",
				"default",
			},
		},
		{
			[]string{"bar", "-region", "-profile=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"-profile=hoge",
				"default",
			},
		},
		{
			[]string{"bar", "-profile=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"hoge",
			},
		},
		{
			[]string{"bar", "-profile=-region=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"-region=hoge",
			},
		},
		{
			[]string{"bar", "-profile", "hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"hoge",
			},
		},
		{
			[]string{"bar", "-profile", "-region=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"us-east-1",
				"-region=hoge",
			},
		},
		{
			[]string{"bar", "-region=hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"hoge",
				"default",
			},
		},
		{
			[]string{"bar", "-region", "hoge"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"hoge",
				"default",
			},
		},
		{
			[]string{"bar", "-region=hoge", "-profile=huga"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"hoge",
				"huga",
			},
		},
		{
			[]string{"bar", "-region=-profile=hoge", "-profile=huga"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"-profile=hoge",
				"huga",
			},
		},
		{
			[]string{"bar", "-region", "hoge", "-profile", "huga"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"hoge",
				"huga",
			},
		},
		{
			[]string{"bar", "-region", "-profile=hoge", "-profile", "huga"},
			map[string]string{
				"AWS_PROFILE_NAME": "",
				"AWS_DEFAULT_REGION":       "us-east-1",
			},
			want{
				[]string{"bar"},
				"-profile=hoge",
				"huga",
			},
		},
	}

	for i, test := range tests {
		setenv(test.env)
		o, r, p := roundArgs(test.in)
		if (!reflect.DeepEqual(o, test.w.o) && (len(o) != 0 || len(test.w.o) != 0)) ||
			!reflect.DeepEqual(r, test.w.region) ||
			!reflect.DeepEqual(p, test.w.profile) {
			t.Fatalf("%d: want: %v, but: %v", i, test.w, want{
				o,
				r,
				p,
			})
		}
		unsetenv(test.env)
	}
}
<|endoftext|>


<commit_before>package destroy

import (
	//	"bytes"
	//	//"fmt"
	//	"io/ioutil"
	"os"
	//	"regexp"
	//	"strings"
	//
	"github.com/craigmonson/colonize/config"
	"github.com/craigmonson/colonize/log"
	"github.com/craigmonson/colonize/util"
)

func Run(c *config.ColonizeConfig, l log.Logger, skipRemote bool) (error,string) {
	os.Chdir(c.TmplPath)

	if skipRemote {
		l.Log("Skipping remote setup")
	} else {
		l.Log("Running remote setup")
		util.RunCmd("./" + c.CombinedRemoteFilePath)
	}

	l.Log("Executing terraform destroy")
	return util.RunCmd(
		"terraform",
		"destroy",
		"-force",
		"-var-file", c.CombinedValsFilePath,
		"-var-file", c.CombinedDerivedValsFilePath,
	)
}
<commit_msg>added prep (#26)<commit_after>package destroy

import (
	//	"bytes"
	//	//"fmt"
	//	"io/ioutil"
	"os"
	//	"regexp"
	//	"strings"
	//
	"github.com/craigmonson/colonize/config"
	"github.com/craigmonson/colonize/log"
	"github.com/craigmonson/colonize/prep"
	"github.com/craigmonson/colonize/util"
)

func Run(c *config.ColonizeConfig, l log.Logger, skipRemote bool) (error,string) {
	os.Chdir(c.TmplPath)

	// always run prep first
	prep.Run(c, l)

	if skipRemote {
		l.Log("Skipping remote setup")
	} else {
		l.Log("Running remote setup")
		util.RunCmd("./" + c.CombinedRemoteFilePath)
	}

	l.Log("Executing terraform destroy")
	return util.RunCmd(
		"terraform",
		"destroy",
		"-force",
		"-var-file", c.CombinedValsFilePath,
		"-var-file", c.CombinedDerivedValsFilePath,
	)
}
<|endoftext|>


<commit_before>// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package ui

import (
	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/models/db"
	repo_model "code.gitea.io/gitea/models/repo"
	user_model "code.gitea.io/gitea/models/user"
	"code.gitea.io/gitea/modules/graceful"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/notification/base"
	"code.gitea.io/gitea/modules/queue"
)

type (
	notificationService struct {
		base.NullNotifier
		issueQueue queue.Queue
	}

	issueNotificationOpts struct {
		IssueID              int64
		CommentID            int64
		NotificationAuthorID int64
		ReceiverID           int64 // 0 -- ALL Watcher
	}
)

var _ base.Notifier = &notificationService{}

// NewNotifier create a new notificationService notifier
func NewNotifier() base.Notifier {
	ns := &notificationService{}
	ns.issueQueue = queue.CreateQueue("notification-service", ns.handle, issueNotificationOpts{})
	return ns
}

func (ns *notificationService) handle(data ...queue.Data) []queue.Data {
	for _, datum := range data {
		opts := datum.(issueNotificationOpts)
		if err := models.CreateOrUpdateIssueNotifications(opts.IssueID, opts.CommentID, opts.NotificationAuthorID, opts.ReceiverID); err != nil {
			log.Error("Was unable to create issue notification: %v", err)
		}
	}
	return nil
}

func (ns *notificationService) Run() {
	graceful.GetManager().RunWithShutdownFns(ns.issueQueue.Run)
}

func (ns *notificationService) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
	issue *models.Issue, comment *models.Comment, mentions []*user_model.User) {
	opts := issueNotificationOpts{
		IssueID:              issue.ID,
		NotificationAuthorID: doer.ID,
	}
	if comment != nil {
		opts.CommentID = comment.ID
	}
	_ = ns.issueQueue.Push(opts)
	for _, mention := range mentions {
		opts := issueNotificationOpts{
			IssueID:              issue.ID,
			NotificationAuthorID: doer.ID,
			ReceiverID:           mention.ID,
		}
		if comment != nil {
			opts.CommentID = comment.ID
		}
		_ = ns.issueQueue.Push(opts)
	}
}

func (ns *notificationService) NotifyNewIssue(issue *models.Issue, mentions []*user_model.User) {
	_ = ns.issueQueue.Push(issueNotificationOpts{
		IssueID:              issue.ID,
		NotificationAuthorID: issue.Poster.ID,
	})
	for _, mention := range mentions {
		_ = ns.issueQueue.Push(issueNotificationOpts{
			IssueID:              issue.ID,
			NotificationAuthorID: issue.Poster.ID,
			ReceiverID:           mention.ID,
		})
	}
}

func (ns *notificationService) NotifyIssueChangeStatus(doer *user_model.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) {
	_ = ns.issueQueue.Push(issueNotificationOpts{
		IssueID:              issue.ID,
		NotificationAuthorID: doer.ID,
	})
}

func (ns *notificationService) NotifyIssueChangeTitle(doer *user_model.User, issue *models.Issue, oldTitle string) {
	if err := issue.LoadPullRequest(); err != nil {
		log.Error("issue.LoadPullRequest: %v", err)
		return
	}
	if issue.IsPull && models.HasWorkInProgressPrefix(oldTitle) && !issue.PullRequest.IsWorkInProgress() {
		_ = ns.issueQueue.Push(issueNotificationOpts{
			IssueID:              issue.ID,
			NotificationAuthorID: doer.ID,
		})
	}
}

func (ns *notificationService) NotifyMergePullRequest(pr *models.PullRequest, doer *user_model.User) {
	_ = ns.issueQueue.Push(issueNotificationOpts{
		IssueID:              pr.Issue.ID,
		NotificationAuthorID: doer.ID,
	})
}

func (ns *notificationService) NotifyNewPullRequest(pr *models.PullRequest, mentions []*user_model.User) {
	if err := pr.LoadIssue(); err != nil {
		log.Error("Unable to load issue: %d for pr: %d: Error: %v", pr.IssueID, pr.ID, err)
		return
	}
	toNotify := make(map[int64]struct{}, 32)
	repoWatchers, err := repo_model.GetRepoWatchersIDs(db.DefaultContext, pr.Issue.RepoID)
	if err != nil {
		log.Error("GetRepoWatchersIDs: %v", err)
		return
	}
	for _, id := range repoWatchers {
		toNotify[id] = struct{}{}
	}
	issueParticipants, err := models.GetParticipantsIDsByIssueID(pr.IssueID)
	if err != nil {
		log.Error("GetParticipantsIDsByIssueID: %v", err)
		return
	}
	for _, id := range issueParticipants {
		toNotify[id] = struct{}{}
	}
	delete(toNotify, pr.Issue.PosterID)
	for _, mention := range mentions {
		toNotify[mention.ID] = struct{}{}
	}
	for receiverID := range toNotify {
		_ = ns.issueQueue.Push(issueNotificationOpts{
			IssueID:              pr.Issue.ID,
			NotificationAuthorID: pr.Issue.PosterID,
			ReceiverID:           receiverID,
		})
	}
}

func (ns *notificationService) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, c *models.Comment, mentions []*user_model.User) {
	opts := issueNotificationOpts{
		IssueID:              pr.Issue.ID,
		NotificationAuthorID: r.Reviewer.ID,
	}
	if c != nil {
		opts.CommentID = c.ID
	}
	_ = ns.issueQueue.Push(opts)
	for _, mention := range mentions {
		opts := issueNotificationOpts{
			IssueID:              pr.Issue.ID,
			NotificationAuthorID: r.Reviewer.ID,
			ReceiverID:           mention.ID,
		}
		if c != nil {
			opts.CommentID = c.ID
		}
		_ = ns.issueQueue.Push(opts)
	}
}

func (ns *notificationService) NotifyPullRequestCodeComment(pr *models.PullRequest, c *models.Comment, mentions []*user_model.User) {
	for _, mention := range mentions {
		_ = ns.issueQueue.Push(issueNotificationOpts{
			IssueID:              pr.Issue.ID,
			NotificationAuthorID: c.Poster.ID,
			CommentID:            c.ID,
			ReceiverID:           mention.ID,
		})
	}
}

func (ns *notificationService) NotifyPullRequestPushCommits(doer *user_model.User, pr *models.PullRequest, comment *models.Comment) {
	opts := issueNotificationOpts{
		IssueID:              pr.IssueID,
		NotificationAuthorID: doer.ID,
		CommentID:            comment.ID,
	}
	_ = ns.issueQueue.Push(opts)
}

func (ns *notificationService) NotifyPullRevieweDismiss(doer *user_model.User, review *models.Review, comment *models.Comment) {
	opts := issueNotificationOpts{
		IssueID:              review.IssueID,
		NotificationAuthorID: doer.ID,
		CommentID:            comment.ID,
	}
	_ = ns.issueQueue.Push(opts)
}

func (ns *notificationService) NotifyIssueChangeAssignee(doer *user_model.User, issue *models.Issue, assignee *user_model.User, removed bool, comment *models.Comment) {
	if !removed {
		opts := issueNotificationOpts{
			IssueID:              issue.ID,
			NotificationAuthorID: doer.ID,
			ReceiverID:           assignee.ID,
		}

		if comment != nil {
			opts.CommentID = comment.ID
		}

		_ = ns.issueQueue.Push(opts)
	}
}

func (ns *notificationService) NotifyPullReviewRequest(doer *user_model.User, issue *models.Issue, reviewer *user_model.User, isRequest bool, comment *models.Comment) {
	if isRequest {
		opts := issueNotificationOpts{
			IssueID:              issue.ID,
			NotificationAuthorID: doer.ID,
			ReceiverID:           reviewer.ID,
		}

		if comment != nil {
			opts.CommentID = comment.ID
		}

		_ = ns.issueQueue.Push(opts)
	}
}

func (ns *notificationService) NotifyRepoPendingTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository) {
	if err := models.CreateRepoTransferNotification(doer, newOwner, repo); err != nil {
		log.Error("NotifyRepoPendingTransfer: %v", err)
	}
}
<commit_msg>Fix problem when self-assign notification (#18797)<commit_after>// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package ui

import (
	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/models/db"
	repo_model "code.gitea.io/gitea/models/repo"
	user_model "code.gitea.io/gitea/models/user"
	"code.gitea.io/gitea/modules/graceful"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/notification/base"
	"code.gitea.io/gitea/modules/queue"
)

type (
	notificationService struct {
		base.NullNotifier
		issueQueue queue.Queue
	}

	issueNotificationOpts struct {
		IssueID              int64
		CommentID            int64
		NotificationAuthorID int64
		ReceiverID           int64 // 0 -- ALL Watcher
	}
)

var _ base.Notifier = &notificationService{}

// NewNotifier create a new notificationService notifier
func NewNotifier() base.Notifier {
	ns := &notificationService{}
	ns.issueQueue = queue.CreateQueue("notification-service", ns.handle, issueNotificationOpts{})
	return ns
}

func (ns *notificationService) handle(data ...queue.Data) []queue.Data {
	for _, datum := range data {
		opts := datum.(issueNotificationOpts)
		if err := models.CreateOrUpdateIssueNotifications(opts.IssueID, opts.CommentID, opts.NotificationAuthorID, opts.ReceiverID); err != nil {
			log.Error("Was unable to create issue notification: %v", err)
		}
	}
	return nil
}

func (ns *notificationService) Run() {
	graceful.GetManager().RunWithShutdownFns(ns.issueQueue.Run)
}

func (ns *notificationService) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
	issue *models.Issue, comment *models.Comment, mentions []*user_model.User) {
	opts := issueNotificationOpts{
		IssueID:              issue.ID,
		NotificationAuthorID: doer.ID,
	}
	if comment != nil {
		opts.CommentID = comment.ID
	}
	_ = ns.issueQueue.Push(opts)
	for _, mention := range mentions {
		opts := issueNotificationOpts{
			IssueID:              issue.ID,
			NotificationAuthorID: doer.ID,
			ReceiverID:           mention.ID,
		}
		if comment != nil {
			opts.CommentID = comment.ID
		}
		_ = ns.issueQueue.Push(opts)
	}
}

func (ns *notificationService) NotifyNewIssue(issue *models.Issue, mentions []*user_model.User) {
	_ = ns.issueQueue.Push(issueNotificationOpts{
		IssueID:              issue.ID,
		NotificationAuthorID: issue.Poster.ID,
	})
	for _, mention := range mentions {
		_ = ns.issueQueue.Push(issueNotificationOpts{
			IssueID:              issue.ID,
			NotificationAuthorID: issue.Poster.ID,
			ReceiverID:           mention.ID,
		})
	}
}

func (ns *notificationService) NotifyIssueChangeStatus(doer *user_model.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) {
	_ = ns.issueQueue.Push(issueNotificationOpts{
		IssueID:              issue.ID,
		NotificationAuthorID: doer.ID,
	})
}

func (ns *notificationService) NotifyIssueChangeTitle(doer *user_model.User, issue *models.Issue, oldTitle string) {
	if err := issue.LoadPullRequest(); err != nil {
		log.Error("issue.LoadPullRequest: %v", err)
		return
	}
	if issue.IsPull && models.HasWorkInProgressPrefix(oldTitle) && !issue.PullRequest.IsWorkInProgress() {
		_ = ns.issueQueue.Push(issueNotificationOpts{
			IssueID:              issue.ID,
			NotificationAuthorID: doer.ID,
		})
	}
}

func (ns *notificationService) NotifyMergePullRequest(pr *models.PullRequest, doer *user_model.User) {
	_ = ns.issueQueue.Push(issueNotificationOpts{
		IssueID:              pr.Issue.ID,
		NotificationAuthorID: doer.ID,
	})
}

func (ns *notificationService) NotifyNewPullRequest(pr *models.PullRequest, mentions []*user_model.User) {
	if err := pr.LoadIssue(); err != nil {
		log.Error("Unable to load issue: %d for pr: %d: Error: %v", pr.IssueID, pr.ID, err)
		return
	}
	toNotify := make(map[int64]struct{}, 32)
	repoWatchers, err := repo_model.GetRepoWatchersIDs(db.DefaultContext, pr.Issue.RepoID)
	if err != nil {
		log.Error("GetRepoWatchersIDs: %v", err)
		return
	}
	for _, id := range repoWatchers {
		toNotify[id] = struct{}{}
	}
	issueParticipants, err := models.GetParticipantsIDsByIssueID(pr.IssueID)
	if err != nil {
		log.Error("GetParticipantsIDsByIssueID: %v", err)
		return
	}
	for _, id := range issueParticipants {
		toNotify[id] = struct{}{}
	}
	delete(toNotify, pr.Issue.PosterID)
	for _, mention := range mentions {
		toNotify[mention.ID] = struct{}{}
	}
	for receiverID := range toNotify {
		_ = ns.issueQueue.Push(issueNotificationOpts{
			IssueID:              pr.Issue.ID,
			NotificationAuthorID: pr.Issue.PosterID,
			ReceiverID:           receiverID,
		})
	}
}

func (ns *notificationService) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, c *models.Comment, mentions []*user_model.User) {
	opts := issueNotificationOpts{
		IssueID:              pr.Issue.ID,
		NotificationAuthorID: r.Reviewer.ID,
	}
	if c != nil {
		opts.CommentID = c.ID
	}
	_ = ns.issueQueue.Push(opts)
	for _, mention := range mentions {
		opts := issueNotificationOpts{
			IssueID:              pr.Issue.ID,
			NotificationAuthorID: r.Reviewer.ID,
			ReceiverID:           mention.ID,
		}
		if c != nil {
			opts.CommentID = c.ID
		}
		_ = ns.issueQueue.Push(opts)
	}
}

func (ns *notificationService) NotifyPullRequestCodeComment(pr *models.PullRequest, c *models.Comment, mentions []*user_model.User) {
	for _, mention := range mentions {
		_ = ns.issueQueue.Push(issueNotificationOpts{
			IssueID:              pr.Issue.ID,
			NotificationAuthorID: c.Poster.ID,
			CommentID:            c.ID,
			ReceiverID:           mention.ID,
		})
	}
}

func (ns *notificationService) NotifyPullRequestPushCommits(doer *user_model.User, pr *models.PullRequest, comment *models.Comment) {
	opts := issueNotificationOpts{
		IssueID:              pr.IssueID,
		NotificationAuthorID: doer.ID,
		CommentID:            comment.ID,
	}
	_ = ns.issueQueue.Push(opts)
}

func (ns *notificationService) NotifyPullRevieweDismiss(doer *user_model.User, review *models.Review, comment *models.Comment) {
	opts := issueNotificationOpts{
		IssueID:              review.IssueID,
		NotificationAuthorID: doer.ID,
		CommentID:            comment.ID,
	}
	_ = ns.issueQueue.Push(opts)
}

func (ns *notificationService) NotifyIssueChangeAssignee(doer *user_model.User, issue *models.Issue, assignee *user_model.User, removed bool, comment *models.Comment) {
	if !removed && doer.ID != assignee.ID {
		opts := issueNotificationOpts{
			IssueID:              issue.ID,
			NotificationAuthorID: doer.ID,
			ReceiverID:           assignee.ID,
		}

		if comment != nil {
			opts.CommentID = comment.ID
		}

		_ = ns.issueQueue.Push(opts)
	}
}

func (ns *notificationService) NotifyPullReviewRequest(doer *user_model.User, issue *models.Issue, reviewer *user_model.User, isRequest bool, comment *models.Comment) {
	if isRequest {
		opts := issueNotificationOpts{
			IssueID:              issue.ID,
			NotificationAuthorID: doer.ID,
			ReceiverID:           reviewer.ID,
		}

		if comment != nil {
			opts.CommentID = comment.ID
		}

		_ = ns.issueQueue.Push(opts)
	}
}

func (ns *notificationService) NotifyRepoPendingTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository) {
	if err := models.CreateRepoTransferNotification(doer, newOwner, repo); err != nil {
		log.Error("NotifyRepoPendingTransfer: %v", err)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Skaffold Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cmd

import (
	"bytes"
	"fmt"
	"strings"
	"testing"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1beta7"
	"github.com/GoogleContainerTools/skaffold/testutil"
)

var (
	invalidFileName    string = "invalid-skaffold.yaml"
	validFileName      string = "valid-skaffold.yaml"
	upgradableFileName string = "upgradable-skaffold.yaml"
)

func TestFindConfigs(t *testing.T) {
	testutil.Run(t, "", func(tt *testutil.T) {
		latestVersion := latest.Version
		upgradableVersion := v1beta7.Version
		tmpDir1, tmpDir2 := setUpTempFiles(tt, latestVersion, upgradableVersion)

		tests := []struct {
			flagDir                string
			resultCounts           int
			shouldContainsFiles    []string
			shouldContainsVersions []string
		}{
			{
				flagDir:                tmpDir1,
				resultCounts:           2,
				shouldContainsFiles:    []string{validFileName, upgradableFileName},
				shouldContainsVersions: []string{latestVersion, upgradableVersion},
			},
			{
				flagDir:                tmpDir2,
				resultCounts:           1,
				shouldContainsFiles:    []string{validFileName},
				shouldContainsVersions: []string{latestVersion},
			},
		}
		for _, test := range tests {
			var b bytes.Buffer
			err := findConfigs(&b, test.flagDir)

			for _, f := range test.shouldContainsFiles {
				tt.CheckContains(fmt.Sprintf("%s/%s", test.flagDir, f), b.String())
			}

			for _, v := range test.shouldContainsVersions {
				tt.CheckContains(v, b.String())
			}

			tt.CheckDeepEqual(test.resultCounts, strings.Count(b.String(), "\n"))
			tt.CheckError(false, err)
		}
	})
}

/*
This helper function will generate the following file tree for testing purpose
...
├── tmpDir1
│   ├── valid-skaffold.yaml
|   ├── upgradable-skaffold.yaml
│   └── invalid-skaffold.yaml
└── tmpDir2
	├── valid-skaffold.yaml
	└── invalid-skaffold.yaml
*/
func setUpTempFiles(tt *testutil.T, latestVersion, upgradableVersion string) (string, string) {
	validYaml := fmt.Sprintf(`apiVersion: %s
kind: Config
build:
  artifacts:
  - image: docker/image
    docker:
      dockerfile: dockerfile.test
`, latestVersion)
	upgradableYaml := fmt.Sprintf(`apiVersion: %s
kind: Config
build:
  artifacts:
  - image: docker/image
    docker:
      dockerfile: dockerfile.test
`, upgradableVersion)
	invalidYaml := `This is invalid`

	tmpDir1 := tt.NewTempDir()
	tmpDir2 := tt.NewTempDir()

	files := []struct {
		fileName string
		content  string
		tmpDir   *testutil.TempDir
	}{
		{
			fileName: invalidFileName,
			content:  invalidYaml,
			tmpDir:   tmpDir1,
		},
		{
			fileName: validFileName,
			content:  validYaml,
			tmpDir:   tmpDir1,
		},
		{
			fileName: upgradableFileName,
			content:  upgradableYaml,
			tmpDir:   tmpDir1,
		},
		{
			fileName: invalidFileName,
			content:  invalidYaml,
			tmpDir:   tmpDir2,
		},
		{
			fileName: validFileName,
			content:  validYaml,
			tmpDir:   tmpDir2,
		},
	}

	for _, file := range files {
		file.tmpDir.Write(file.fileName, file.content)
	}

	return tmpDir1.Root(), tmpDir2.Root()
}
<commit_msg>Fix os path<commit_after>/*
Copyright 2019 The Skaffold Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cmd

import (
	"bytes"
	"fmt"
	"strings"
	"testing"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1beta7"
	"github.com/GoogleContainerTools/skaffold/testutil"
)

var (
	invalidFileName    string = "invalid-skaffold.yaml"
	validFileName      string = "valid-skaffold.yaml"
	upgradableFileName string = "upgradable-skaffold.yaml"
)

func TestFindConfigs(t *testing.T) {
	testutil.Run(t, "", func(tt *testutil.T) {
		latestVersion := latest.Version
		upgradableVersion := v1beta7.Version
		tmpDir1, tmpDir2 := setUpTempFiles(tt, latestVersion, upgradableVersion)

		tests := []struct {
			flagDir                *testutil.TempDir
			resultCounts           int
			shouldContainsFiles    []string
			shouldContainsVersions []string
		}{
			{
				flagDir:                tmpDir1,
				resultCounts:           2,
				shouldContainsFiles:    []string{validFileName, upgradableFileName},
				shouldContainsVersions: []string{latestVersion, upgradableVersion},
			},
			{
				flagDir:                tmpDir2,
				resultCounts:           1,
				shouldContainsFiles:    []string{validFileName},
				shouldContainsVersions: []string{latestVersion},
			},
		}
		for _, test := range tests {
			var b bytes.Buffer
			err := findConfigs(&b, test.flagDir.Root())

			for _, f := range test.shouldContainsFiles {
				tt.CheckContains(test.flagDir.Path(f), b.String())
			}

			for _, v := range test.shouldContainsVersions {
				tt.CheckContains(v, b.String())
			}

			tt.CheckDeepEqual(test.resultCounts, strings.Count(b.String(), "\n"))
			tt.CheckError(false, err)
		}
	})
}

/*
This helper function will generate the following file tree for testing purpose
...
├── tmpDir1
│   ├── valid-skaffold.yaml
|   ├── upgradable-skaffold.yaml
│   └── invalid-skaffold.yaml
└── tmpDir2
	├── valid-skaffold.yaml
	└── invalid-skaffold.yaml
*/
func setUpTempFiles(tt *testutil.T, latestVersion, upgradableVersion string) (*testutil.TempDir, *testutil.TempDir) {
	validYaml := fmt.Sprintf(`apiVersion: %s
kind: Config
build:
  artifacts:
  - image: docker/image
    docker:
      dockerfile: dockerfile.test
`, latestVersion)
	upgradableYaml := fmt.Sprintf(`apiVersion: %s
kind: Config
build:
  artifacts:
  - image: docker/image
    docker:
      dockerfile: dockerfile.test
`, upgradableVersion)
	invalidYaml := `This is invalid`

	tmpDir1 := tt.NewTempDir()
	tmpDir2 := tt.NewTempDir()

	files := []struct {
		fileName string
		content  string
		tmpDir   *testutil.TempDir
	}{
		{
			fileName: invalidFileName,
			content:  invalidYaml,
			tmpDir:   tmpDir1,
		},
		{
			fileName: validFileName,
			content:  validYaml,
			tmpDir:   tmpDir1,
		},
		{
			fileName: upgradableFileName,
			content:  upgradableYaml,
			tmpDir:   tmpDir1,
		},
		{
			fileName: invalidFileName,
			content:  invalidYaml,
			tmpDir:   tmpDir2,
		},
		{
			fileName: validFileName,
			content:  validYaml,
			tmpDir:   tmpDir2,
		},
	}

	for _, file := range files {
		file.tmpDir.Write(file.fileName, file.content)
	}

	return tmpDir1, tmpDir2
}
<|endoftext|>


<commit_before>package plugins

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/Jeffail/gabs"
	"github.com/Seklfreak/Robyul2/helpers"
	"github.com/bwmarrin/discordgo"
)

const (
	streamableApiBaseUrl = "https://api.streamable.com/%s"
)

type Streamable struct{}

func (s *Streamable) Commands() []string {
	return []string{
		"streamable",
	}
}

func (s *Streamable) Init(session *discordgo.Session) {

}

func (s *Streamable) Action(command string, content string, msg *discordgo.Message, session *discordgo.Session) { // [p]streamable [<link>] or attachment
	var err error

	session.ChannelTyping(msg.ChannelID)

	if len(content) <= 0 && len(msg.Attachments) <= 0 {
		_, err := session.ChannelMessageSend(msg.ChannelID, helpers.GetText("bot.arguments.invalid"))
		helpers.Relax(err)
		return
	}

	sourceUrl := content
	if len(msg.Attachments) > 0 {
		sourceUrl = msg.Attachments[0].URL
	}

	createStreamableEndpoint := fmt.Sprintf(streamableApiBaseUrl, fmt.Sprintf("import?url=%s", url.QueryEscape(sourceUrl)))
	request, err := http.NewRequest("GET", createStreamableEndpoint, nil)
	request.Header.Add("user-agent", helpers.DEFAULT_UA)
	request.SetBasicAuth(helpers.GetConfig().Path("streamable.username").Data().(string),
		helpers.GetConfig().Path("streamable.password").Data().(string))
	helpers.Relax(err)
	response, err := httpClient.Do(request)
	helpers.Relax(err)
	defer response.Body.Close()
	buf := bytes.NewBuffer(nil)
	_, err = io.Copy(buf, response.Body)
	helpers.Relax(err)

	jsonResult, err := gabs.ParseJSON(buf.Bytes())

	if err != nil || jsonResult.ExistsP("status") == false || jsonResult.Path("status").Data().(float64) >= 3 {
		_, err = session.ChannelMessageSend(msg.ChannelID,
			fmt.Sprintf("<@%s> Something went wrong while creating your streamable. <:blobscream:317043778823389184>",
				msg.Author.ID))
		helpers.Relax(err)
		return
	}

	session.ChannelMessageSend(msg.ChannelID, "Your streamable is processing, this may take a while. <:blobsleeping:317047101534109696>")
	session.ChannelTyping(msg.ChannelID)

	streamableShortcode := jsonResult.Path("shortcode").Data().(string)
	streamableUrl := ""
CheckStreamableStatusLoop:
	for {
		statusStreamableEndpoint := fmt.Sprintf(streamableApiBaseUrl, fmt.Sprintf("videos/%s", streamableShortcode))
		result, err := gabs.ParseJSON(helpers.NetGet(statusStreamableEndpoint))
		if err != nil {
			if strings.Contains(err.Error(), "Expected status 200; Got 429") {
				_, err = session.ChannelMessageSend(msg.ChannelID,
					fmt.Sprintf("<@%s> Too many requests, please try again later. <:blobscream:317043778823389184>",
						msg.Author.ID))
				helpers.Relax(err)
			} else {
				helpers.Relax(err)
			}
		}

		switch result.Path("status").Data().(float64) {
		case 0:
		case 1:
			time.Sleep(5 * time.Second)
			session.ChannelTyping(msg.ChannelID)
			continue CheckStreamableStatusLoop
		case 2:
			streamableUrl = result.Path("url").Data().(string)
			if !strings.Contains(streamableUrl, "://") {
				streamableUrl = "https://" + streamableUrl
			}
			break CheckStreamableStatusLoop
		default:
			_, err = session.ChannelMessageSend(msg.ChannelID,
				fmt.Sprintf("<@%s> Something went wrong while creating your streamable. <:blobscream:317043778823389184>",
					msg.Author.ID))
			helpers.Relax(err)
			return
		}
	}

	_, err = session.ChannelMessageSend(msg.ChannelID, fmt.Sprintf("<@%s> Your streamable is done: %s .", msg.Author.ID, streamableUrl))
	helpers.Relax(err)
}
<commit_msg>[streamable] fixes http client (fixes ROBYUL-DISCORD-AD)<commit_after>package plugins

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/Jeffail/gabs"
	"github.com/Seklfreak/Robyul2/helpers"
	"github.com/bwmarrin/discordgo"
)

const (
	streamableApiBaseUrl = "https://api.streamable.com/%s"
)

type Streamable struct{}

func (s *Streamable) Commands() []string {
	return []string{
		"streamable",
	}
}

func (s *Streamable) Init(session *discordgo.Session) {

}

func (s *Streamable) Action(command string, content string, msg *discordgo.Message, session *discordgo.Session) { // [p]streamable [<link>] or attachment
	var err error

	session.ChannelTyping(msg.ChannelID)

	if len(content) <= 0 && len(msg.Attachments) <= 0 {
		_, err := session.ChannelMessageSend(msg.ChannelID, helpers.GetText("bot.arguments.invalid"))
		helpers.Relax(err)
		return
	}

	sourceUrl := content
	if len(msg.Attachments) > 0 {
		sourceUrl = msg.Attachments[0].URL
	}

	createStreamableEndpoint := fmt.Sprintf(streamableApiBaseUrl, fmt.Sprintf("import?url=%s", url.QueryEscape(sourceUrl)))
	request, err := http.NewRequest("GET", createStreamableEndpoint, nil)
	helpers.Relax(err)
	request.Header.Add("user-agent", helpers.DEFAULT_UA)
	request.SetBasicAuth(helpers.GetConfig().Path("streamable.username").Data().(string),
		helpers.GetConfig().Path("streamable.password").Data().(string))
	httpClient = &http.Client{}
	response, err := httpClient.Do(request)
	helpers.Relax(err)
	defer response.Body.Close()
	buf := bytes.NewBuffer(nil)
	_, err = io.Copy(buf, response.Body)
	helpers.Relax(err)

	jsonResult, err := gabs.ParseJSON(buf.Bytes())

	if err != nil || jsonResult.ExistsP("status") == false || jsonResult.Path("status").Data().(float64) >= 3 {
		_, err = session.ChannelMessageSend(msg.ChannelID,
			fmt.Sprintf("<@%s> Something went wrong while creating your streamable. <:blobscream:317043778823389184>",
				msg.Author.ID))
		helpers.Relax(err)
		return
	}

	session.ChannelMessageSend(msg.ChannelID, "Your streamable is processing, this may take a while. <:blobsleeping:317047101534109696>")
	session.ChannelTyping(msg.ChannelID)

	streamableShortcode := jsonResult.Path("shortcode").Data().(string)
	streamableUrl := ""
CheckStreamableStatusLoop:
	for {
		statusStreamableEndpoint := fmt.Sprintf(streamableApiBaseUrl, fmt.Sprintf("videos/%s", streamableShortcode))
		result, err := gabs.ParseJSON(helpers.NetGet(statusStreamableEndpoint))
		if err != nil {
			if strings.Contains(err.Error(), "Expected status 200; Got 429") {
				_, err = session.ChannelMessageSend(msg.ChannelID,
					fmt.Sprintf("<@%s> Too many requests, please try again later. <:blobscream:317043778823389184>",
						msg.Author.ID))
				helpers.Relax(err)
			} else {
				helpers.Relax(err)
			}
		}

		switch result.Path("status").Data().(float64) {
		case 0:
		case 1:
			time.Sleep(5 * time.Second)
			session.ChannelTyping(msg.ChannelID)
			continue CheckStreamableStatusLoop
		case 2:
			streamableUrl = result.Path("url").Data().(string)
			if !strings.Contains(streamableUrl, "://") {
				streamableUrl = "https://" + streamableUrl
			}
			break CheckStreamableStatusLoop
		default:
			_, err = session.ChannelMessageSend(msg.ChannelID,
				fmt.Sprintf("<@%s> Something went wrong while creating your streamable. <:blobscream:317043778823389184>",
					msg.Author.ID))
			helpers.Relax(err)
			return
		}
	}

	_, err = session.ChannelMessageSend(msg.ChannelID, fmt.Sprintf("<@%s> Your streamable is done: %s .", msg.Author.ID, streamableUrl))
	helpers.Relax(err)
}
<|endoftext|>


<commit_before>package hostdb

// scan.go contains the functions which periodically scan the list of all hosts
// to see which hosts are online or offline, and to get any updates to the
// settings of the hosts.

import (
	"crypto/rand"
	"math/big"
	"net"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
)

// queueScan will add a host to the queue to be scanned.
func (hdb *HostDB) queueScan(entry modules.HostDBEntry) {
	// If this entry is already in the scan pool, can return immediately.
	_, exists := hdb.scanMap[entry.PublicKey.String()]
	if exists {
		return
	}

	// Add the entry to a waitlist, then check if any thread is currently
	// emptying the waitlist. If not, spawn a thread to empty the waitlist.
	hdb.scanMap[entry.PublicKey.String()] = struct{}{}
	hdb.scanList = append(hdb.scanList, entry)
	if hdb.scanWait {
		// Another thread is emptying the scan list, nothing to worry about.
		return
	}

	// Sanity check - the scan map and the scan list should have the same
	// length.
	if build.DEBUG && len(hdb.scanMap) > len(hdb.scanList)+scanningThreads {
		hdb.log.Critical("The hostdb scan map has seemingly grown too large:", len(hdb.scanMap), len(hdb.scanList), scanningThreads)
	}

	hdb.scanWait = true
	go func() {
		// Nobody is emptying the scan list, volunteer.
		if hdb.tg.Add() != nil {
			// Hostdb is shutting down, don't spin up another thread.  It is
			// okay to leave scanWait set to true as that will not affect
			// shutdown.
			return
		}
		defer hdb.tg.Done()

		for {
			hdb.mu.Lock()
			if len(hdb.scanList) == 0 {
				// Scan list is empty, can exit. Let the world know that nobody
				// is emptying the scan list anymore.
				hdb.scanWait = false
				hdb.mu.Unlock()
				return
			}
			// Get the next host, shrink the scan list.
			entry := hdb.scanList[0]
			hdb.scanList = hdb.scanList[1:]
			delete(hdb.scanMap, entry.PublicKey.String())
			scansRemaining := len(hdb.scanList)

			// Grab the most recent entry for this host.
			recentEntry, exists := hdb.hostTree.Select(entry.PublicKey)
			if exists {
				entry = recentEntry
			}
			hdb.mu.Unlock()

			// Block while waiting for an opening in the scan pool.
			hdb.log.Debugf("Sending host %v for scan, %v hosts remain", entry.PublicKey.String(), scansRemaining)
			select {
			case hdb.scanPool <- entry:
				// iterate again
			case <-hdb.tg.StopChan():
				// quit
				return
			}
		}
	}()
}

// updateEntry updates an entry in the hostdb after a scan has taken place.
//
// CAUTION: This function will automatically add multiple entries to a new host
// to give that host some base uptime. This makes this function co-dependent
// with the host weight functions. Adjustment of the host weight functions need
// to keep this function in mind, and vice-versa.
func (hdb *HostDB) updateEntry(entry modules.HostDBEntry, netErr error) {
	// If the host is not online, toss out this update.
	if !hdb.online {
		return
	}

	// Grab the host from the host tree.
	newEntry, exists := hdb.hostTree.Select(entry.PublicKey)
	if exists {
		newEntry.HostExternalSettings = entry.HostExternalSettings
	} else {
		newEntry = entry
	}

	// Add the datapoints for the scan.
	if len(newEntry.ScanHistory) < 2 {
		// Add two scans to the scan history. Two are needed because the scans
		// are forward looking, but we want this first scan to represent as
		// much as one week of uptime or downtime.
		earliestStartTime := time.Now().Add(time.Hour * 7 * 24 * -1) // Permit up to a week of starting uptime or downtime.
		suggestedStartTime := time.Now().Add(time.Minute * 10 * time.Duration(hdb.blockHeight-entry.FirstSeen) * -1)
		if suggestedStartTime.Before(earliestStartTime) {
			suggestedStartTime = earliestStartTime
		}
		newEntry.ScanHistory = modules.HostDBScans{
			{Timestamp: suggestedStartTime, Success: netErr == nil},
			{Timestamp: time.Now(), Success: netErr == nil},
		}
	} else {
		if newEntry.ScanHistory[len(newEntry.ScanHistory)-1].Success && netErr != nil {
			hdb.log.Debugf("Host %v is being downgraded from an online host to an offline host: %v\n", newEntry.PublicKey.String(), netErr)
		}
		newEntry.ScanHistory = append(newEntry.ScanHistory, modules.HostDBScan{Timestamp: time.Now(), Success: netErr == nil})
	}

	// If the host's earliest scan is more than a month old and there is no
	// recent uptime, mark the host for deletion.
	var recentUptime bool
	for _, scan := range entry.ScanHistory {
		if scan.Success {
			recentUptime = true
		}
	}

	// If the host has been offline for too long, delete the host from the
	// hostdb.
	if time.Now().Sub(newEntry.ScanHistory[0].Timestamp) > maxHostDowntime && !recentUptime && len(newEntry.ScanHistory) >= minScans {
		err := hdb.hostTree.Remove(newEntry.PublicKey)
		if err != nil {
			hdb.log.Println("ERROR: unable to remove host newEntry which has had a ton of downtime:", err)
		}

		// The function should terminate here as no more interaction is needed
		// with this host.
		return
	}

	// Compress any old scans into the historic values.
	for len(newEntry.ScanHistory) > minScans && time.Now().Sub(newEntry.ScanHistory[0].Timestamp) > maxHostDowntime {
		timePassed := newEntry.ScanHistory[1].Timestamp.Sub(newEntry.ScanHistory[0].Timestamp)
		if newEntry.ScanHistory[1].Success {
			newEntry.HistoricUptime += timePassed
		} else {
			newEntry.HistoricDowntime += timePassed
		}
		newEntry.ScanHistory = newEntry.ScanHistory[1:]
	}

	// Add the updated entry
	if !exists {
		err := hdb.hostTree.Insert(newEntry)
		if err != nil {
			hdb.log.Println("ERROR: unable to insert entry which is was thought to be new:", err)
		} else {
			hdb.log.Debugf("Adding host %v to the hostdb. Net error: %v\n", newEntry.PublicKey.String(), netErr)
		}
	} else {
		err := hdb.hostTree.Modify(newEntry)
		if err != nil {
			hdb.log.Println("ERROR: unable to modify entry which is thought to exist:", err)
		} else {
			hdb.log.Debugf("Adding host %v to the hostdb. Net error: %v\n", newEntry.PublicKey.String(), netErr)
		}
	}
}

// managedScanHost will connect to a host and grab the settings, verifying
// uptime and updating to the host's preferences.
func (hdb *HostDB) managedScanHost(entry modules.HostDBEntry) {
	// Request settings from the queued host entry.
	netAddr := entry.NetAddress
	pubKey := entry.PublicKey
	hdb.log.Debugf("Scanning host %v at %v", pubKey, netAddr)

	var settings modules.HostExternalSettings
	err := func() error {
		dialer := &net.Dialer{
			Cancel:  hdb.tg.StopChan(),
			Timeout: hostRequestTimeout,
		}
		conn, err := dialer.Dial("tcp", string(netAddr))
		if err != nil {
			return err
		}
		connCloseChan := make(chan struct{})
		go func() {
			select {
			case <-hdb.tg.StopChan():
			case <-connCloseChan:
			}
			conn.Close()
		}()
		defer close(connCloseChan)
		conn.SetDeadline(time.Now().Add(hostScanDeadline))

		err = encoding.WriteObject(conn, modules.RPCSettings)
		if err != nil {
			return err
		}
		var pubkey crypto.PublicKey
		copy(pubkey[:], pubKey.Key)
		return crypto.ReadSignedObject(conn, &settings, maxSettingsLen, pubkey)
	}()
	if err != nil {
		hdb.log.Debugf("Scan of host at %v failed: %v", netAddr, err)
	} else {
		hdb.log.Debugf("Scan of host at %v succeeded.", netAddr)
		entry.HostExternalSettings = settings
	}

	// Update the host tree to have a new entry, including the new error. Then
	// delete the entry from the scan map as the scan has been successful.
	hdb.mu.Lock()
	hdb.updateEntry(entry, err)
	hdb.mu.Unlock()
}

// threadedProbeHosts pulls hosts from the thread pool and runs a scan on them.
func (hdb *HostDB) threadedProbeHosts() {
	err := hdb.tg.Add()
	if err != nil {
		return
	}
	defer hdb.tg.Done()

	for {
		select {
		case <-hdb.tg.StopChan():
			return
		case hostEntry := <-hdb.scanPool:
			// Block the scan until the host is online.
			for {
				hdb.mu.RLock()
				online := hdb.online
				hdb.mu.RUnlock()
				if online {
					break
				}

				// Check again in 30 seconds.
				select {
				case <-time.After(time.Second * 30):
					continue
				case <-hdb.tg.StopChan():
					return
				}
			}

			// There appears to be internet connectivity, continue with the
			// scan.
			hdb.managedScanHost(hostEntry)
		}
	}
}

// threadedScan is an ongoing function which will query the full set of hosts
// every few hours to see who is online and available for uploading.
func (hdb *HostDB) threadedScan() {
	err := hdb.tg.Add()
	if err != nil {
		return
	}
	defer hdb.tg.Done()

	for {
		// Set up a scan for the hostCheckupQuanity most valuable hosts in the
		// hostdb. Hosts that fail their scans will be docked significantly,
		// pushing them further back in the hierarchy, ensuring that for the
		// most part only online hosts are getting scanned unless there are
		// fewer than hostCheckupQuantity of them.

		// Grab a set of hosts to scan, grab hosts that are active, inactive,
		// and offline to get high diversity.
		var onlineHosts, offlineHosts []modules.HostDBEntry
		for _, host := range hdb.hostTree.All() {
			if len(onlineHosts) >= hostCheckupQuantity && len(offlineHosts) >= hostCheckupQuantity {
				break
			}

			// Figure out if the host is online or offline.
			online := len(host.ScanHistory) > 0 && host.ScanHistory[len(host.ScanHistory)-1].Success
			if online && len(onlineHosts) < hostCheckupQuantity {
				onlineHosts = append(onlineHosts, host)
			} else if !online && len(offlineHosts) < hostCheckupQuantity {
				offlineHosts = append(onlineHosts, host)
			}
		}

		// Queue the scans for each host.
		hdb.log.Println("Performing scan on", len(onlineHosts), "online hosts and", len(offlineHosts), "offline hosts.")
		hdb.mu.Lock()
		for _, host := range onlineHosts {
			hdb.queueScan(host)
		}
		for _, host := range offlineHosts {
			hdb.queueScan(host)
		}
		hdb.mu.Unlock()

		// Sleep for a random amount of time before doing another round of
		// scanning. The minimums and maximums keep the scan time reasonable,
		// while the randomness prevents the scanning from always happening at
		// the same time of day or week.
		maxBig := big.NewInt(int64(maxScanSleep))
		minBig := big.NewInt(int64(minScanSleep))
		randSleep, err := rand.Int(rand.Reader, maxBig.Sub(maxBig, minBig))
		if err != nil {
			build.Critical(err)
			// If there's an error, sleep for the default amount of time.
			defaultBig := big.NewInt(int64(defaultScanSleep))
			randSleep = defaultBig.Sub(defaultBig, minBig)
		}

		// Sleep until it's time for the next scan cycle.
		select {
		case <-hdb.tg.StopChan():
			return
		case <-time.After(time.Duration(randSleep.Int64()) + minScanSleep):
		}
	}
}
<commit_msg>repair hostdb scan behavior<commit_after>package hostdb

// scan.go contains the functions which periodically scan the list of all hosts
// to see which hosts are online or offline, and to get any updates to the
// settings of the hosts.

import (
	"net"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
)

// queueScan will add a host to the queue to be scanned.
func (hdb *HostDB) queueScan(entry modules.HostDBEntry) {
	// If this entry is already in the scan pool, can return immediately.
	_, exists := hdb.scanMap[entry.PublicKey.String()]
	if exists {
		return
	}

	// Add the entry to a waitlist, then check if any thread is currently
	// emptying the waitlist. If not, spawn a thread to empty the waitlist.
	hdb.scanMap[entry.PublicKey.String()] = struct{}{}
	hdb.scanList = append(hdb.scanList, entry)
	if hdb.scanWait {
		// Another thread is emptying the scan list, nothing to worry about.
		return
	}

	// Sanity check - the scan map and the scan list should have the same
	// length.
	if build.DEBUG && len(hdb.scanMap) > len(hdb.scanList)+scanningThreads {
		hdb.log.Critical("The hostdb scan map has seemingly grown too large:", len(hdb.scanMap), len(hdb.scanList), scanningThreads)
	}

	hdb.scanWait = true
	go func() {
		// Nobody is emptying the scan list, volunteer.
		if hdb.tg.Add() != nil {
			// Hostdb is shutting down, don't spin up another thread.  It is
			// okay to leave scanWait set to true as that will not affect
			// shutdown.
			return
		}
		defer hdb.tg.Done()

		for {
			hdb.mu.Lock()
			if len(hdb.scanList) == 0 {
				// Scan list is empty, can exit. Let the world know that nobody
				// is emptying the scan list anymore.
				hdb.scanWait = false
				hdb.mu.Unlock()
				return
			}
			// Get the next host, shrink the scan list.
			entry := hdb.scanList[0]
			hdb.scanList = hdb.scanList[1:]
			delete(hdb.scanMap, entry.PublicKey.String())
			scansRemaining := len(hdb.scanList)

			// Grab the most recent entry for this host.
			recentEntry, exists := hdb.hostTree.Select(entry.PublicKey)
			if exists {
				entry = recentEntry
			}
			hdb.mu.Unlock()

			// Block while waiting for an opening in the scan pool.
			hdb.log.Debugf("Sending host %v for scan, %v hosts remain", entry.PublicKey.String(), scansRemaining)
			select {
			case hdb.scanPool <- entry:
				// iterate again
			case <-hdb.tg.StopChan():
				// quit
				return
			}
		}
	}()
}

// updateEntry updates an entry in the hostdb after a scan has taken place.
//
// CAUTION: This function will automatically add multiple entries to a new host
// to give that host some base uptime. This makes this function co-dependent
// with the host weight functions. Adjustment of the host weight functions need
// to keep this function in mind, and vice-versa.
func (hdb *HostDB) updateEntry(entry modules.HostDBEntry, netErr error) {
	// If the host is not online, toss out this update.
	if !hdb.online {
		return
	}

	// Grab the host from the host tree.
	newEntry, exists := hdb.hostTree.Select(entry.PublicKey)
	if exists {
		newEntry.HostExternalSettings = entry.HostExternalSettings
	} else {
		newEntry = entry
	}

	// Add the datapoints for the scan.
	if len(newEntry.ScanHistory) < 2 {
		// Add two scans to the scan history. Two are needed because the scans
		// are forward looking, but we want this first scan to represent as
		// much as one week of uptime or downtime.
		earliestStartTime := time.Now().Add(time.Hour * 7 * 24 * -1) // Permit up to a week of starting uptime or downtime.
		suggestedStartTime := time.Now().Add(time.Minute * 10 * time.Duration(hdb.blockHeight-entry.FirstSeen) * -1)
		if suggestedStartTime.Before(earliestStartTime) {
			suggestedStartTime = earliestStartTime
		}
		newEntry.ScanHistory = modules.HostDBScans{
			{Timestamp: suggestedStartTime, Success: netErr == nil},
			{Timestamp: time.Now(), Success: netErr == nil},
		}
	} else {
		if newEntry.ScanHistory[len(newEntry.ScanHistory)-1].Success && netErr != nil {
			hdb.log.Debugf("Host %v is being downgraded from an online host to an offline host: %v\n", newEntry.PublicKey.String(), netErr)
		}
		newEntry.ScanHistory = append(newEntry.ScanHistory, modules.HostDBScan{Timestamp: time.Now(), Success: netErr == nil})
	}

	// If the host's earliest scan is more than a month old and there is no
	// recent uptime, mark the host for deletion.
	var recentUptime bool
	for _, scan := range entry.ScanHistory {
		if scan.Success {
			recentUptime = true
		}
	}

	// If the host has been offline for too long, delete the host from the
	// hostdb.
	if time.Now().Sub(newEntry.ScanHistory[0].Timestamp) > maxHostDowntime && !recentUptime && len(newEntry.ScanHistory) >= minScans {
		err := hdb.hostTree.Remove(newEntry.PublicKey)
		if err != nil {
			hdb.log.Println("ERROR: unable to remove host newEntry which has had a ton of downtime:", err)
		}

		// The function should terminate here as no more interaction is needed
		// with this host.
		return
	}

	// Compress any old scans into the historic values.
	for len(newEntry.ScanHistory) > minScans && time.Now().Sub(newEntry.ScanHistory[0].Timestamp) > maxHostDowntime {
		timePassed := newEntry.ScanHistory[1].Timestamp.Sub(newEntry.ScanHistory[0].Timestamp)
		if newEntry.ScanHistory[1].Success {
			newEntry.HistoricUptime += timePassed
		} else {
			newEntry.HistoricDowntime += timePassed
		}
		newEntry.ScanHistory = newEntry.ScanHistory[1:]
	}

	// Add the updated entry
	if !exists {
		err := hdb.hostTree.Insert(newEntry)
		if err != nil {
			hdb.log.Println("ERROR: unable to insert entry which is was thought to be new:", err)
		} else {
			hdb.log.Debugf("Adding host %v to the hostdb. Net error: %v\n", newEntry.PublicKey.String(), netErr)
		}
	} else {
		err := hdb.hostTree.Modify(newEntry)
		if err != nil {
			hdb.log.Println("ERROR: unable to modify entry which is thought to exist:", err)
		} else {
			hdb.log.Debugf("Adding host %v to the hostdb. Net error: %v\n", newEntry.PublicKey.String(), netErr)
		}
	}
}

// managedScanHost will connect to a host and grab the settings, verifying
// uptime and updating to the host's preferences.
func (hdb *HostDB) managedScanHost(entry modules.HostDBEntry) {
	// Request settings from the queued host entry.
	netAddr := entry.NetAddress
	pubKey := entry.PublicKey
	hdb.log.Debugf("Scanning host %v at %v", pubKey, netAddr)

	var settings modules.HostExternalSettings
	err := func() error {
		dialer := &net.Dialer{
			Cancel:  hdb.tg.StopChan(),
			Timeout: hostRequestTimeout,
		}
		conn, err := dialer.Dial("tcp", string(netAddr))
		if err != nil {
			return err
		}
		connCloseChan := make(chan struct{})
		go func() {
			select {
			case <-hdb.tg.StopChan():
			case <-connCloseChan:
			}
			conn.Close()
		}()
		defer close(connCloseChan)
		conn.SetDeadline(time.Now().Add(hostScanDeadline))

		err = encoding.WriteObject(conn, modules.RPCSettings)
		if err != nil {
			return err
		}
		var pubkey crypto.PublicKey
		copy(pubkey[:], pubKey.Key)
		return crypto.ReadSignedObject(conn, &settings, maxSettingsLen, pubkey)
	}()
	if err != nil {
		hdb.log.Debugf("Scan of host at %v failed: %v", netAddr, err)
	} else {
		hdb.log.Debugf("Scan of host at %v succeeded.", netAddr)
		entry.HostExternalSettings = settings
	}

	// Update the host tree to have a new entry, including the new error. Then
	// delete the entry from the scan map as the scan has been successful.
	hdb.mu.Lock()
	hdb.updateEntry(entry, err)
	hdb.mu.Unlock()
}

// threadedProbeHosts pulls hosts from the thread pool and runs a scan on them.
func (hdb *HostDB) threadedProbeHosts() {
	err := hdb.tg.Add()
	if err != nil {
		return
	}
	defer hdb.tg.Done()

	for {
		select {
		case <-hdb.tg.StopChan():
			return
		case hostEntry := <-hdb.scanPool:
			// Block the scan until the host is online.
			for {
				hdb.mu.RLock()
				online := hdb.online
				hdb.mu.RUnlock()
				if online {
					break
				}

				// Check again in 30 seconds.
				select {
				case <-time.After(time.Second * 30):
					continue
				case <-hdb.tg.StopChan():
					return
				}
			}

			// There appears to be internet connectivity, continue with the
			// scan.
			hdb.managedScanHost(hostEntry)
		}
	}
}

// threadedScan is an ongoing function which will query the full set of hosts
// every few hours to see who is online and available for uploading.
func (hdb *HostDB) threadedScan() {
	err := hdb.tg.Add()
	if err != nil {
		return
	}
	defer hdb.tg.Done()

	for {
		// Set up a scan for the hostCheckupQuanity most valuable hosts in the
		// hostdb. Hosts that fail their scans will be docked significantly,
		// pushing them further back in the hierarchy, ensuring that for the
		// most part only online hosts are getting scanned unless there are
		// fewer than hostCheckupQuantity of them.

		// Grab a set of hosts to scan, grab hosts that are active, inactive,
		// and offline to get high diversity.
		var onlineHosts, offlineHosts []modules.HostDBEntry
		for _, host := range hdb.hostTree.All() {
			if len(onlineHosts) >= hostCheckupQuantity && len(offlineHosts) >= hostCheckupQuantity {
				break
			}

			// Figure out if the host is online or offline.
			online := len(host.ScanHistory) > 0 && host.ScanHistory[len(host.ScanHistory)-1].Success
			if online && len(onlineHosts) < hostCheckupQuantity {
				onlineHosts = append(onlineHosts, host)
			} else if !online && len(offlineHosts) < hostCheckupQuantity {
				offlineHosts = append(offlineHosts, host)
			}
		}

		// Queue the scans for each host.
		hdb.log.Println("Performing scan on", len(onlineHosts), "online hosts and", len(offlineHosts), "offline hosts.")
		hdb.mu.Lock()
		for _, host := range onlineHosts {
			hdb.queueScan(host)
		}
		for _, host := range offlineHosts {
			hdb.queueScan(host)
		}
		hdb.mu.Unlock()

		// Sleep for a random amount of time before doing another round of
		// scanning. The minimums and maximums keep the scan time reasonable,
		// while the randomness prevents the scanning from always happening at
		// the same time of day or week.
		sleepTime := defaultScanSleep
		sleepRange := int(maxScanSleep - minScanSleep)
		sleepRand, err := crypto.RandIntn(sleepRange)
		if err != nil {
			build.Critical(err)
		} else {
			sleepTime = minScanSleep + time.Duration(sleepRand)
		}

		// Sleep until it's time for the next scan cycle.
		select {
		case <-hdb.tg.StopChan():
			return
		case <-time.After(sleepTime):
		}
	}
}
<|endoftext|>


<commit_before>package v2

import (
	"fmt"
	"os"

	"code.cloudfoundry.org/cli/actor/sharedaction"
	"code.cloudfoundry.org/cli/actor/v2action"
	"code.cloudfoundry.org/cli/command"
	"code.cloudfoundry.org/cli/command/flag"
	"code.cloudfoundry.org/cli/command/v2/shared"
)

//go:generate counterfeiter . CreateAppManifestActor

type CreateAppManifestActor interface {
	CreateApplicationManifestByNameAndSpace(appName string, spaceGUID string, filePath string) (v2action.Warnings, error)
}

type CreateAppManifestCommand struct {
	RequiredArgs    flag.AppName `positional-args:"yes"`
	FilePath        flag.Path    `short:"p" description:"Specify a path for file creation. If path not specified, manifest file is created in current working directory."`
	usage           interface{}  `usage:"CF_NAME create-app-manifest APP_NAME [-p /path/to/<app-name>_manifest.yml]"`
	relatedCommands interface{}  `related_commands:"apps, push"`

	UI          command.UI
	Config      command.Config
	SharedActor command.SharedActor
	Actor       CreateAppManifestActor
}

func (cmd *CreateAppManifestCommand) Setup(config command.Config, ui command.UI) error {
	cmd.UI = ui
	cmd.Config = config
	cmd.SharedActor = sharedaction.NewActor()

	ccClient, uaaClient, err := shared.NewClients(config, ui, true)
	if err != nil {
		return err
	}
	cmd.Actor = v2action.NewActor(ccClient, uaaClient, config)

	return nil
}

func (cmd CreateAppManifestCommand) Execute(args []string) error {
	err := cmd.SharedActor.CheckTarget(cmd.Config, true, true)
	if err != nil {
		return shared.HandleError(err)
	}

	user, err := cmd.Config.CurrentUser()
	if err != nil {
		return shared.HandleError(err)
	}

	cmd.UI.DisplayText("Creating an app manifest from current settings of app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{
		"AppName":   cmd.RequiredArgs.AppName,
		"OrgName":   cmd.Config.TargetedOrganization().Name,
		"SpaceName": cmd.Config.TargetedSpace().Name,
		"Username":  user.Name,
	})

	manifestPath := cmd.FilePath.String()
	if manifestPath == "" {
		manifestPath = fmt.Sprintf(".%s%s_manifest.yml", string(os.PathSeparator), cmd.RequiredArgs.AppName)
	}
	warnings, err := cmd.Actor.CreateApplicationManifestByNameAndSpace(cmd.RequiredArgs.AppName, cmd.Config.TargetedSpace().GUID, manifestPath)

	cmd.UI.DisplayWarnings(warnings)
	if err != nil {
		return shared.HandleError(err)
	}

	cmd.UI.DisplayOK()
	cmd.UI.DisplayText("Manifest file created successfully at {{.FilePath}}", map[string]interface{}{
		"FilePath": manifestPath,
	})

	return nil
}
<commit_msg>added color to create-app-manifest<commit_after>package v2

import (
	"fmt"
	"os"

	"code.cloudfoundry.org/cli/actor/sharedaction"
	"code.cloudfoundry.org/cli/actor/v2action"
	"code.cloudfoundry.org/cli/command"
	"code.cloudfoundry.org/cli/command/flag"
	"code.cloudfoundry.org/cli/command/v2/shared"
)

//go:generate counterfeiter . CreateAppManifestActor

type CreateAppManifestActor interface {
	CreateApplicationManifestByNameAndSpace(appName string, spaceGUID string, filePath string) (v2action.Warnings, error)
}

type CreateAppManifestCommand struct {
	RequiredArgs    flag.AppName `positional-args:"yes"`
	FilePath        flag.Path    `short:"p" description:"Specify a path for file creation. If path not specified, manifest file is created in current working directory."`
	usage           interface{}  `usage:"CF_NAME create-app-manifest APP_NAME [-p /path/to/<app-name>_manifest.yml]"`
	relatedCommands interface{}  `related_commands:"apps, push"`

	UI          command.UI
	Config      command.Config
	SharedActor command.SharedActor
	Actor       CreateAppManifestActor
}

func (cmd *CreateAppManifestCommand) Setup(config command.Config, ui command.UI) error {
	cmd.UI = ui
	cmd.Config = config
	cmd.SharedActor = sharedaction.NewActor()

	ccClient, uaaClient, err := shared.NewClients(config, ui, true)
	if err != nil {
		return err
	}
	cmd.Actor = v2action.NewActor(ccClient, uaaClient, config)

	return nil
}

func (cmd CreateAppManifestCommand) Execute(args []string) error {
	err := cmd.SharedActor.CheckTarget(cmd.Config, true, true)
	if err != nil {
		return shared.HandleError(err)
	}

	user, err := cmd.Config.CurrentUser()
	if err != nil {
		return shared.HandleError(err)
	}

	cmd.UI.DisplayTextWithFlavor("Creating an app manifest from current settings of app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{
		"AppName":   cmd.RequiredArgs.AppName,
		"OrgName":   cmd.Config.TargetedOrganization().Name,
		"SpaceName": cmd.Config.TargetedSpace().Name,
		"Username":  user.Name,
	})

	manifestPath := cmd.FilePath.String()
	if manifestPath == "" {
		manifestPath = fmt.Sprintf(".%s%s_manifest.yml", string(os.PathSeparator), cmd.RequiredArgs.AppName)
	}
	warnings, err := cmd.Actor.CreateApplicationManifestByNameAndSpace(cmd.RequiredArgs.AppName, cmd.Config.TargetedSpace().GUID, manifestPath)

	cmd.UI.DisplayWarnings(warnings)
	if err != nil {
		return shared.HandleError(err)
	}

	cmd.UI.DisplayOK()
	cmd.UI.DisplayText("Manifest file created successfully at {{.FilePath}}", map[string]interface{}{
		"FilePath": manifestPath,
	})

	return nil
}
<|endoftext|>


<commit_before>package swarm

import (
	"golang.org/x/net/context"

	"github.com/docker/docker/api/client"
	"github.com/docker/docker/api/client/inspect"
	"github.com/docker/docker/cli"
	"github.com/spf13/cobra"
)

type inspectOptions struct {
	format string
	//	pretty  bool
}

func newInspectCommand(dockerCli *client.DockerCli) *cobra.Command {
	var opts inspectOptions

	cmd := &cobra.Command{
		Use:   "inspect [OPTIONS]",
		Short: "Inspect the Swarm",
		Args:  cli.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			// if opts.pretty && len(opts.format) > 0 {
			//	return fmt.Errorf("--format is incompatible with human friendly format")
			// }
			return runInspect(dockerCli, opts)
		},
	}

	flags := cmd.Flags()
	flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given go template")
	//flags.BoolVarP(&opts.pretty, "pretty", "h", false, "Print the information in a human friendly format.")
	return cmd
}

func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error {
	client := dockerCli.Client()
	ctx := context.Background()

	swarm, err := client.SwarmInspect(ctx)
	if err != nil {
		return err
	}

	getRef := func(_ string) (interface{}, []byte, error) {
		return swarm, nil, nil
	}

	//	if !opts.pretty {
	return inspect.Inspect(dockerCli.Out(), []string{""}, opts.format, getRef)
	//	}

	//return printHumanFriendly(dockerCli.Out(), opts.refs, getRef)
}
<commit_msg>Remove dead code for "inspect --pretty"<commit_after>package swarm

import (
	"golang.org/x/net/context"

	"github.com/docker/docker/api/client"
	"github.com/docker/docker/api/client/inspect"
	"github.com/docker/docker/cli"
	"github.com/spf13/cobra"
)

type inspectOptions struct {
	format string
}

func newInspectCommand(dockerCli *client.DockerCli) *cobra.Command {
	var opts inspectOptions

	cmd := &cobra.Command{
		Use:   "inspect [OPTIONS]",
		Short: "Inspect the Swarm",
		Args:  cli.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			return runInspect(dockerCli, opts)
		},
	}

	flags := cmd.Flags()
	flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given go template")
	return cmd
}

func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error {
	client := dockerCli.Client()
	ctx := context.Background()

	swarm, err := client.SwarmInspect(ctx)
	if err != nil {
		return err
	}

	getRef := func(_ string) (interface{}, []byte, error) {
		return swarm, nil, nil
	}

	return inspect.Inspect(dockerCli.Out(), []string{""}, opts.format, getRef)
}
<|endoftext|>