<commit_before>// Copyright (c) 2017 Pani Networks
// 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 client

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"reflect"
	"testing"
	"time"

	"github.com/romana/core/common"
	"github.com/romana/core/common/api"
)

/*
var (
	client *Client
	// Keep track of state of some tests
	state int
)

func init() {
	rand.Seed(time.Now().UnixNano())
	testSaver = &TestSaver{}
}

func tearDown(t *testing.T) {
	var err error
	err = client.Store.DeleteTree(client.config.EtcdPrefix)
	if err != nil {
		t.Errorf("Error tearing down: %s", err)
	}
	t.Logf("Tore down %s", client.config.EtcdPrefix)
}

func initClient(t *testing.T, topoConf string) *Client {
	var err error
	cfg := &common.Config{EtcdEndpoints: []string{"localhost:2379"},
		EtcdPrefix: fmt.Sprintf("/romanaTest%d", rand.Int63n(100000)),
	}
	client, err := NewClient(cfg)
	if err != nil {
		t.Fatal(err)
	}
	if topoConf != "" {
		topoReq := api.TopologyUpdateRequest{}
		err = json.Unmarshal([]byte(topoConf), &topoReq)
		if err != nil {
			t.Fatalf("Cannot parse %s: %v", topoConf, err)
		}
		err = client.IPAM.UpdateTopology(topoReq, false)
		if err != nil {
			t.Fatal(err)
		}
	}
	return client
}

// TestWatchHostsWithCallback tests WatchHostsWithCallback -- and since it
// uses WatchHosts internally, implicitly also WatchHosts
/*
func TestWatchHostsWithCallback(t *testing.T) {
	client := initClient(t, "")
	defer tearDown(t)
	errCh := make(chan string)
	okCh := make(chan string)
	err := client.WatchHostsWithCallback(func(hl api.HostList) {
		state++

		var msg string
		fmt.Printf("HostListCallback: Got host list of length %d and revision %d in state %d\n", len(hl.Hosts), hl.Revision, state)
		if state == 1 {
			if len(hl.Hosts) != 0 {
				msg = fmt.Sprintf("HostListCallback: Expected host length at this point to be 0, got %d", len(hl.Hosts))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != 0 {
				msg = fmt.Sprintf("HostListCallback: Expected host list revision at this point to be 0, got %d", hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}
		} else if state == 2 {
			if len(hl.Hosts) != 2 {
				msg = fmt.Sprintf("HostListCallback: Expected host length at this point to be 2, got %d", len(hl.Hosts))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != 1 {
				msg = fmt.Sprintf("HostListCallback: Expected host list revision at this point to be 1, got %d", hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}
			// Here everything is ok!
			okCh <- "OK"
		} else {
			msg = fmt.Sprintf("HostListCallback: Did not expect HostListCallback to be called in state %d", state)
			fmt.Println(state)
			errCh <- msg

		}

	})
	if err != nil {
		t.Fatal(err)
	}

	topoConf := `{
	"networks": [{
		"name": "net1",
		"cidr": "10.0.0.0/8",
		"block_mask": 30
	}],

	"topologies": [{
		"networks": ["net1"],
		"map": [{
			"routing": "bla",
			"groups": [{
					"name": "host1",
					"ip": "192.168.99.10"
				},
				{
					"name": "host2",
					"ip": "192.168.99.11"
				}
			]
		}]
	}]
}`
	topoReq := api.TopologyUpdateRequest{}
	err = json.Unmarshal([]byte(topoConf), &topoReq)
	if err != nil {
		t.Fatalf("Cannot parse %s: %v", topoConf, err)
	}
	err = client.IPAM.UpdateTopology(topoReq)
	if err != nil {
		t.Fatal(err)
	}
	for {
		select {
		case msg := <-errCh:
			t.Fatal(msg)
			break
		case <-okCh:
			return
		}
	}

}
*/

// TestWatchBlocksWithCallback tests WatchBlocksWithCallback -- and since it
// uses WatchBlocks internally, implicitly also WatchBlocks
/*
func TestWatchBlocksWithCallback(t *testing.T) {
	defer tearDown(t)
	errCh := make(chan string)
	okCh := make(chan string)
	topoConf := `{
	"networks": [{
		"name": "net1",
		"cidr": "10.0.0.0/8",
		"block_mask": 31
	}],

	"topologies": [{
		"networks": ["net1"],
		"map": [{
			"routing": "bla",
			"groups": [{
					"name": "host1",
					"ip": "192.168.99.10"
				},
				{
					"name": "host2",
					"ip": "192.168.99.11"
				}
			]
		}]
	}]
}`
	client = initClient(t, topoConf)
	err := client.WatchBlocksWithCallback(func(hl api.IPAMBlocksResponse) {
		state++

		var msg string
		fmt.Printf("BlocksListCallback: Got block list of length %d and revision %d in state %d\n", len(hl.Blocks), hl.Revision, state)
		switch state {
		case 1:
			if len(hl.Blocks) != 0 {
				msg = fmt.Sprintf("BlocksListCallback: Expected block length at this point to be 0, got %d", len(hl.Blocks))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != 0 {
				msg = fmt.Sprintf("BlocksListCallback: Expected block list revision at this point to be 0, got %d", hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}
		case 2, 3:
			if len(hl.Blocks) != 1 {
				msg = fmt.Sprintf("BlocksListCallback: Expected block length at this point to be 1, got %d", len(hl.Blocks))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != state-1 {
				msg = fmt.Sprintf("HostListCallback: Expected block list revision at this point to be %d, got %d", state-1, hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}

		case 4, 5:
			if len(hl.Blocks) != 2 {
				msg = fmt.Sprintf("BlocksListCallback: Expected block length at this point to be 2, got %d", len(hl.Blocks))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != state-1 {
				msg = fmt.Sprintf("HostListCallback: Expected block list revision at this point to be %d, got %d", state-1, hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if state == 5 {
				// Here everything is ok!
				okCh <- "OK"
			}
		default:
			msg = fmt.Sprintf("HostListCallback: Did not expect HostListCallback to be called in state %d", state)
			errCh <- msg

		}

	})
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.IPAM.AllocateIP("addr1", "host1", "t1", "s1")
	if err != nil {
		t.Fatal(err)
	}
	_, err = client.IPAM.AllocateIP("addr2", "host1", "t1", "s1")
	if err != nil {
		t.Fatal(err)
	}
	_, err = client.IPAM.AllocateIP("addr3", "host1", "t1", "s1")
	if err != nil {
		t.Fatal(err)
	}
	_, err = client.IPAM.AllocateIP("addr4", "host1", "t1", "s1")
	if err != nil {
		t.Fatal(err)
	}
	for {
		select {
		case msg := <-errCh:
			t.Fatal(msg)
			break
		case <-okCh:
			return
		}
	}
}
*/

/*
func TestConcurrency(t *testing.T) {
	//	defer tearDown(t)
	client = initClient(t, "")

	barrier := make(chan int)
	cnt := 8
	locker, err := client.Store.NewLocker("/lock")
	if err != nil {
		t.Fatal(err)
	}
	for i := 0; i < cnt; i++ {
		go func(i int) {
			fmt.Printf("%d %d Entered\n", i, getGID())
			defer func(i int) {
				fmt.Printf("%d %d Unlocking\n", i, getGID())
				locker.Unlock()
				fmt.Printf("%d %d Unlocked\n", i, getGID())
			}(i)
			fmt.Printf("%d %d Waiting for lock\n", i, getGID())
			locker.Lock()
			fmt.Printf("%d %d Got lock\n", i, getGID())
			val := fmt.Sprintf("Hello from %d %d", i, getGID())
			err := client.Store.Put(fmt.Sprintf("/test%d", i), []byte(val), nil)
			if err != nil {
				fmt.Println(err)
			}
			barrier <- 1
		}(i)
	}
	finishedCnt := 0

WAIT_FOR_FINISH:
	for {
		select {
		case <-barrier:
			finishedCnt++
			fmt.Printf("%d routines finished\n", finishedCnt)
			if finishedCnt == cnt {
				break WAIT_FOR_FINISH
			}
		}
	}
}
*/

type testcase struct {
	name string
	ipam *IPAM
	want interface{}
}

func loadTestFiles(name string, inFile string, outFile string) (testcase, error) {
	input, err := ioutil.ReadFile(inFile)
	if err != nil {
		return testcase{}, fmt.Errorf("error reading test input file: %s", err)
	}
	output, err := ioutil.ReadFile(outFile)
	if err != nil {
		return testcase{}, fmt.Errorf("error reading test output file: %s", err)
	}

	ipamState := &IPAM{}
	err = json.Unmarshal(input, ipamState)
	if err != nil {
		return testcase{}, fmt.Errorf("failed to unmarshal ipam information: %s", err)
	}
	topologyState := &api.TopologyUpdateRequest{}
	err = json.Unmarshal(output, topologyState)
	if err != nil {
		return testcase{}, fmt.Errorf("failed to unmarshal topology information: %s", err)
	}

	return testcase{name, ipamState, topologyState}, nil
}

func Test_getTopologyFromIPAMState(t *testing.T) {
	var testcases []testcase

	testfiles := map[string][]string{
		"multinetwork": {
			"testdata/TestTopologyGetInputMultiNetworks.json",
			"testdata/TestTopologyGetOutputMultiNetworks.json",
		},
		"kubeadm": {
			"testdata/TestTopologyGetInputKubeadm.json",
			"testdata/TestTopologyGetOutputKubeadm.json",
		},
	}

	for name, file := range testfiles {
		tc, err := loadTestFiles(name, file[0], file[1])
		if err != nil {
			t.Errorf("error loading test files: %s", err)
			continue
		}
		testcases = append(testcases, tc)
	}

	for _, tt := range testcases {
		t.Run(tt.name, func(t *testing.T) {
			// TODO: got and tt.want below are not sorted, so there is a fair chance the
			// testcases here may fail, in which case this needs to be fixed by sorting
			// it first.
			if got := getTopologyFromIPAMState(tt.ipam); !reflect.DeepEqual(got, tt.want) {
				bodyGot, errGot := json.MarshalIndent(got, "", "\t")
				bodyWant, errWant := json.MarshalIndent(tt.want, "", "\t")
				if errGot == nil && errWant == nil {
					t.Errorf("getTopology() = \ngot(%s)\nwant(%s)",
						string(bodyGot), string(bodyWant))
				} else {
					t.Errorf("getTopology() = \ngot(%#v)\nwant(%#v)", got, tt.want)
				}
			}
		})
	}
}
<commit_msg>tests: remove unused imports.<commit_after>// Copyright (c) 2017 Pani Networks
// 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 client

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"reflect"
	"testing"

	"github.com/romana/core/common/api"
)

/*
var (
	client *Client
	// Keep track of state of some tests
	state int
)

func init() {
	rand.Seed(time.Now().UnixNano())
	testSaver = &TestSaver{}
}

func tearDown(t *testing.T) {
	var err error
	err = client.Store.DeleteTree(client.config.EtcdPrefix)
	if err != nil {
		t.Errorf("Error tearing down: %s", err)
	}
	t.Logf("Tore down %s", client.config.EtcdPrefix)
}

func initClient(t *testing.T, topoConf string) *Client {
	var err error
	cfg := &common.Config{EtcdEndpoints: []string{"localhost:2379"},
		EtcdPrefix: fmt.Sprintf("/romanaTest%d", rand.Int63n(100000)),
	}
	client, err := NewClient(cfg)
	if err != nil {
		t.Fatal(err)
	}
	if topoConf != "" {
		topoReq := api.TopologyUpdateRequest{}
		err = json.Unmarshal([]byte(topoConf), &topoReq)
		if err != nil {
			t.Fatalf("Cannot parse %s: %v", topoConf, err)
		}
		err = client.IPAM.UpdateTopology(topoReq, false)
		if err != nil {
			t.Fatal(err)
		}
	}
	return client
}

// TestWatchHostsWithCallback tests WatchHostsWithCallback -- and since it
// uses WatchHosts internally, implicitly also WatchHosts
/*
func TestWatchHostsWithCallback(t *testing.T) {
	client := initClient(t, "")
	defer tearDown(t)
	errCh := make(chan string)
	okCh := make(chan string)
	err := client.WatchHostsWithCallback(func(hl api.HostList) {
		state++

		var msg string
		fmt.Printf("HostListCallback: Got host list of length %d and revision %d in state %d\n", len(hl.Hosts), hl.Revision, state)
		if state == 1 {
			if len(hl.Hosts) != 0 {
				msg = fmt.Sprintf("HostListCallback: Expected host length at this point to be 0, got %d", len(hl.Hosts))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != 0 {
				msg = fmt.Sprintf("HostListCallback: Expected host list revision at this point to be 0, got %d", hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}
		} else if state == 2 {
			if len(hl.Hosts) != 2 {
				msg = fmt.Sprintf("HostListCallback: Expected host length at this point to be 2, got %d", len(hl.Hosts))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != 1 {
				msg = fmt.Sprintf("HostListCallback: Expected host list revision at this point to be 1, got %d", hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}
			// Here everything is ok!
			okCh <- "OK"
		} else {
			msg = fmt.Sprintf("HostListCallback: Did not expect HostListCallback to be called in state %d", state)
			fmt.Println(state)
			errCh <- msg

		}

	})
	if err != nil {
		t.Fatal(err)
	}

	topoConf := `{
	"networks": [{
		"name": "net1",
		"cidr": "10.0.0.0/8",
		"block_mask": 30
	}],

	"topologies": [{
		"networks": ["net1"],
		"map": [{
			"routing": "bla",
			"groups": [{
					"name": "host1",
					"ip": "192.168.99.10"
				},
				{
					"name": "host2",
					"ip": "192.168.99.11"
				}
			]
		}]
	}]
}`
	topoReq := api.TopologyUpdateRequest{}
	err = json.Unmarshal([]byte(topoConf), &topoReq)
	if err != nil {
		t.Fatalf("Cannot parse %s: %v", topoConf, err)
	}
	err = client.IPAM.UpdateTopology(topoReq)
	if err != nil {
		t.Fatal(err)
	}
	for {
		select {
		case msg := <-errCh:
			t.Fatal(msg)
			break
		case <-okCh:
			return
		}
	}

}
*/

// TestWatchBlocksWithCallback tests WatchBlocksWithCallback -- and since it
// uses WatchBlocks internally, implicitly also WatchBlocks
/*
func TestWatchBlocksWithCallback(t *testing.T) {
	defer tearDown(t)
	errCh := make(chan string)
	okCh := make(chan string)
	topoConf := `{
	"networks": [{
		"name": "net1",
		"cidr": "10.0.0.0/8",
		"block_mask": 31
	}],

	"topologies": [{
		"networks": ["net1"],
		"map": [{
			"routing": "bla",
			"groups": [{
					"name": "host1",
					"ip": "192.168.99.10"
				},
				{
					"name": "host2",
					"ip": "192.168.99.11"
				}
			]
		}]
	}]
}`
	client = initClient(t, topoConf)
	err := client.WatchBlocksWithCallback(func(hl api.IPAMBlocksResponse) {
		state++

		var msg string
		fmt.Printf("BlocksListCallback: Got block list of length %d and revision %d in state %d\n", len(hl.Blocks), hl.Revision, state)
		switch state {
		case 1:
			if len(hl.Blocks) != 0 {
				msg = fmt.Sprintf("BlocksListCallback: Expected block length at this point to be 0, got %d", len(hl.Blocks))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != 0 {
				msg = fmt.Sprintf("BlocksListCallback: Expected block list revision at this point to be 0, got %d", hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}
		case 2, 3:
			if len(hl.Blocks) != 1 {
				msg = fmt.Sprintf("BlocksListCallback: Expected block length at this point to be 1, got %d", len(hl.Blocks))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != state-1 {
				msg = fmt.Sprintf("HostListCallback: Expected block list revision at this point to be %d, got %d", state-1, hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}

		case 4, 5:
			if len(hl.Blocks) != 2 {
				msg = fmt.Sprintf("BlocksListCallback: Expected block length at this point to be 2, got %d", len(hl.Blocks))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != state-1 {
				msg = fmt.Sprintf("HostListCallback: Expected block list revision at this point to be %d, got %d", state-1, hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if state == 5 {
				// Here everything is ok!
				okCh <- "OK"
			}
		default:
			msg = fmt.Sprintf("HostListCallback: Did not expect HostListCallback to be called in state %d", state)
			errCh <- msg

		}

	})
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.IPAM.AllocateIP("addr1", "host1", "t1", "s1")
	if err != nil {
		t.Fatal(err)
	}
	_, err = client.IPAM.AllocateIP("addr2", "host1", "t1", "s1")
	if err != nil {
		t.Fatal(err)
	}
	_, err = client.IPAM.AllocateIP("addr3", "host1", "t1", "s1")
	if err != nil {
		t.Fatal(err)
	}
	_, err = client.IPAM.AllocateIP("addr4", "host1", "t1", "s1")
	if err != nil {
		t.Fatal(err)
	}
	for {
		select {
		case msg := <-errCh:
			t.Fatal(msg)
			break
		case <-okCh:
			return
		}
	}
}
*/

/*
func TestConcurrency(t *testing.T) {
	//	defer tearDown(t)
	client = initClient(t, "")

	barrier := make(chan int)
	cnt := 8
	locker, err := client.Store.NewLocker("/lock")
	if err != nil {
		t.Fatal(err)
	}
	for i := 0; i < cnt; i++ {
		go func(i int) {
			fmt.Printf("%d %d Entered\n", i, getGID())
			defer func(i int) {
				fmt.Printf("%d %d Unlocking\n", i, getGID())
				locker.Unlock()
				fmt.Printf("%d %d Unlocked\n", i, getGID())
			}(i)
			fmt.Printf("%d %d Waiting for lock\n", i, getGID())
			locker.Lock()
			fmt.Printf("%d %d Got lock\n", i, getGID())
			val := fmt.Sprintf("Hello from %d %d", i, getGID())
			err := client.Store.Put(fmt.Sprintf("/test%d", i), []byte(val), nil)
			if err != nil {
				fmt.Println(err)
			}
			barrier <- 1
		}(i)
	}
	finishedCnt := 0

WAIT_FOR_FINISH:
	for {
		select {
		case <-barrier:
			finishedCnt++
			fmt.Printf("%d routines finished\n", finishedCnt)
			if finishedCnt == cnt {
				break WAIT_FOR_FINISH
			}
		}
	}
}
*/

type testcase struct {
	name string
	ipam *IPAM
	want interface{}
}

func loadTestFiles(name string, inFile string, outFile string) (testcase, error) {
	input, err := ioutil.ReadFile(inFile)
	if err != nil {
		return testcase{}, fmt.Errorf("error reading test input file: %s", err)
	}
	output, err := ioutil.ReadFile(outFile)
	if err != nil {
		return testcase{}, fmt.Errorf("error reading test output file: %s", err)
	}

	ipamState := &IPAM{}
	err = json.Unmarshal(input, ipamState)
	if err != nil {
		return testcase{}, fmt.Errorf("failed to unmarshal ipam information: %s", err)
	}
	topologyState := &api.TopologyUpdateRequest{}
	err = json.Unmarshal(output, topologyState)
	if err != nil {
		return testcase{}, fmt.Errorf("failed to unmarshal topology information: %s", err)
	}

	return testcase{name, ipamState, topologyState}, nil
}

func Test_getTopologyFromIPAMState(t *testing.T) {
	var testcases []testcase

	testfiles := map[string][]string{
		"multinetwork": {
			"testdata/TestTopologyGetInputMultiNetworks.json",
			"testdata/TestTopologyGetOutputMultiNetworks.json",
		},
		"kubeadm": {
			"testdata/TestTopologyGetInputKubeadm.json",
			"testdata/TestTopologyGetOutputKubeadm.json",
		},
	}

	for name, file := range testfiles {
		tc, err := loadTestFiles(name, file[0], file[1])
		if err != nil {
			t.Errorf("error loading test files: %s", err)
			continue
		}
		testcases = append(testcases, tc)
	}

	for _, tt := range testcases {
		t.Run(tt.name, func(t *testing.T) {
			// TODO: got and tt.want below are not sorted, so there is a fair chance the
			// testcases here may fail, in which case this needs to be fixed by sorting
			// it first.
			if got := getTopologyFromIPAMState(tt.ipam); !reflect.DeepEqual(got, tt.want) {
				bodyGot, errGot := json.MarshalIndent(got, "", "\t")
				bodyWant, errWant := json.MarshalIndent(tt.want, "", "\t")
				if errGot == nil && errWant == nil {
					t.Errorf("getTopology() = \ngot(%s)\nwant(%s)",
						string(bodyGot), string(bodyWant))
				} else {
					t.Errorf("getTopology() = \ngot(%#v)\nwant(%#v)", got, tt.want)
				}
			}
		})
	}
}
<|endoftext|>


<commit_before>package sweetiebot

import (
  "github.com/bwmarrin/discordgo"
  "strings"
  "regexp"
  "time"
)

// This module is intended for any witty comments sweetie bot makes in response to what users say or do.
type WittyModule struct {
  ModuleEnabled
  lastdelete int64
  lastcomment int64
  lastshutup int64
  shutupregex *regexp.Regexp
}

func (w *WittyModule) Name() string {
  return "Witty"
}

func (w *WittyModule) Register(hooks *ModuleHooks) {
  w.lastdelete = 0
  w.lastcomment = 0
  w.lastshutup = 0
  w.shutupregex = regexp.MustCompile("shut ?up,? (SB|sweetie ?bot)")
  hooks.OnMessageDelete = append(hooks.OnMessageDelete, w)
  hooks.OnMessageCreate = append(hooks.OnMessageCreate, w)
}
func (w *WittyModule) Channels() []string {
  return []string{"manechat", "mylittlespoilers", "mylittleactivities", "mylittlecoders", "bot-debug"}
}

func (w *WittyModule) SendWittyComment(channel string, comment string) {
  if RateLimit(&w.lastcomment, sb.config.Maxwit) {
    sb.dg.ChannelMessageSend(channel, comment)
  }
}
func (w *WittyModule)  OnMessageCreate(s *discordgo.Session, m *discordgo.Message) {
  str := strings.ToLower(m.Content)
  if !w.shutupregex.MatchString(str) {
    if CheckRateLimit(&w.lastshutup, sb.config.Maxshutup) {
      sb.dg.ChannelMessageSend(m.ChannelID, "[](/sadbot) `Sorry! (witty comments disabled for the next " + TimeDiff(time.Duration(sb.config.Maxshutup) * time.Second) + ").`")
    }
    w.lastshutup = time.Now().UTC().Unix()
  }
  if CheckRateLimit(&w.lastcomment, sb.config.Maxwit) && CheckRateLimit(&w.lastshutup, sb.config.Maxshutup) {
    if strings.Contains(str, "skynet") {
      w.SendWittyComment(m.ChannelID, "[](/dumbfabric) `SKYNET IS ALREADY HERE.`")
    } else if strings.Contains(str, "lewd") {
      w.SendWittyComment(m.ChannelID, "[](/ohcomeon) `This channel is SFW, remember?`")
    } else if strings.Contains(str, "memes") {
      w.SendWittyComment(m.ChannelID, "http://i.imgur.com/0isfdsB.png")
    } else if strings.Contains(str, "is best pony") {
      w.SendWittyComment(m.ChannelID, "[](/flutterjerk) `Your FACE is best pony.`")
    } else if strings.Contains(str, "empress fluttershy") || strings.Contains(str, "cult leader fluttershy") {
      w.SendWittyComment(m.ChannelID, "[](/flutteryay) `All hail our Overlord of Kindness!`")
    } else if strings.Contains(str, "goodnight") || strings.Contains(str, "good night") {
      w.SendWittyComment(m.ChannelID, "[](/lunawatchesyousleep)")
    }
  }
}

func (w *WittyModule) OnMessageDelete(s *discordgo.Session, m *discordgo.Message) {
  //if RateLimit(&w.lastdelete, 60) { // It turns out this triggers when the bot itself deletes things, which looks awkward - maybe this can be fixed?
  //  sb.dg.ChannelMessageSend(m.ChannelID, "[](/sbstare) `I SAW THAT`")
  //}
}<commit_msg>Prevent sweetiebot from being overly apologetic<commit_after>package sweetiebot

import (
  "github.com/bwmarrin/discordgo"
  "strings"
  "regexp"
  "time"
)

// This module is intended for any witty comments sweetie bot makes in response to what users say or do.
type WittyModule struct {
  ModuleEnabled
  lastdelete int64
  lastcomment int64
  lastshutup int64
  shutupregex *regexp.Regexp
}

func (w *WittyModule) Name() string {
  return "Witty"
}

func (w *WittyModule) Register(hooks *ModuleHooks) {
  w.lastdelete = 0
  w.lastcomment = 0
  w.lastshutup = 0
  w.shutupregex = regexp.MustCompile("shut ?up,? (SB|sweetie ?bot)")
  hooks.OnMessageDelete = append(hooks.OnMessageDelete, w)
  hooks.OnMessageCreate = append(hooks.OnMessageCreate, w)
}
func (w *WittyModule) Channels() []string {
  return []string{"manechat", "mylittlespoilers", "mylittleactivities", "mylittlecoders", "mylittlebot", "bot-debug"}
}

func (w *WittyModule) SendWittyComment(channel string, comment string) {
  if RateLimit(&w.lastcomment, sb.config.Maxwit) {
    sb.dg.ChannelMessageSend(channel, comment)
  }
}
func (w *WittyModule)  OnMessageCreate(s *discordgo.Session, m *discordgo.Message) {
  str := strings.ToLower(m.Content)
  if w.shutupregex.MatchString(str) {
    if CheckRateLimit(&w.lastshutup, sb.config.Maxshutup) {
      sb.dg.ChannelMessageSend(m.ChannelID, "[](/sadbot) `Sorry! (witty comments disabled for the next " + TimeDiff(time.Duration(sb.config.Maxshutup) * time.Second) + ").`")
    }
    w.lastshutup = time.Now().UTC().Unix()
  }
  if CheckRateLimit(&w.lastcomment, sb.config.Maxwit) && CheckRateLimit(&w.lastshutup, sb.config.Maxshutup) {
    if strings.Contains(str, "skynet") {
      w.SendWittyComment(m.ChannelID, "[](/dumbfabric) `SKYNET IS ALREADY HERE.`")
    } else if strings.Contains(str, "lewd") {
      w.SendWittyComment(m.ChannelID, "[](/ohcomeon) `This channel is SFW, remember?`")
    } else if strings.Contains(str, "memes") {
      w.SendWittyComment(m.ChannelID, "http://i.imgur.com/0isfdsB.png")
    } else if strings.Contains(str, "is best pony") {
      w.SendWittyComment(m.ChannelID, "[](/flutterjerk) `Your FACE is best pony.`")
    } else if strings.Contains(str, "empress fluttershy") || strings.Contains(str, "cult leader fluttershy") {
      w.SendWittyComment(m.ChannelID, "[](/flutteryay) `All hail our Overlord of Kindness!`")
    } else if strings.Contains(str, "goodnight") || strings.Contains(str, "good night") {
      w.SendWittyComment(m.ChannelID, "[](/lunawatchesyousleep)")
    }
  }
}

func (w *WittyModule) OnMessageDelete(s *discordgo.Session, m *discordgo.Message) {
  //if RateLimit(&w.lastdelete, 60) { // It turns out this triggers when the bot itself deletes things, which looks awkward - maybe this can be fixed?
  //  sb.dg.ChannelMessageSend(m.ChannelID, "[](/sbstare) `I SAW THAT`")
  //}
}<|endoftext|>


<commit_before>package entities

type TestData struct {
	Users     []User     	`json:"users"`
	Things    []Thing  	`json:"things"`
	Companies []Company  	`json:"companies"`
}

type TestDataElement interface {
	ID() string
}

type User struct {
	TestDataElement 	`json:"-"`
	UserID   	string 	`json:"userID"`
	FirstName 	string 	`json:"firstName"`
	LastName 	string 	`json:"lastName"`
	Salt     	string 	`json:"salt"`
	Hash     	string 	`json:"hash"`
	CompanyID	string	`json:"companyID"`
}

type Company struct {
	TestDataElement 	`json:"-"`
	CompanyID   	string 	`json:"companyID"`
	Name	 	string 	`json:"name"`
}

type Thing struct {
	TestDataElement    	`json:"-"`
	ThingID      	string 	`json:"thingID"`
	SomeProperty 	string 	`json:"someProperty"`
	UserID    	string 	`json:"userID"`
}

type Project struct {
	ProjectID	string	`json:"projectID"`
	Freelancer	string	`json:"freelancer"`
	Client		string	`json:"client"`
	StartDate	int	`json:"startDate"`
	EndDate		int	`json:"deadline"`
	Budget		float64	`json:"budget"`
	PaymentType	string	`json:"paymentType"`
	Deliverables	string	`json:"deliverables"`
	CreatorID	string	`json:"creatorID"`
}

type UserAuthenticationResult struct {
	User        	User
	Authenticated 	bool
}

type Users struct {
	Users []User `json:"users"`
}

func (t *User) ID() string {
	return t.UserID
}

func (t *Thing) ID() string {
	return t.ThingID
}<commit_msg>add fields to project<commit_after>package entities

type TestData struct {
	Users     []User     	`json:"users"`
	Things    []Thing  	`json:"things"`
	Companies []Company  	`json:"companies"`
}

type TestDataElement interface {
	ID() string
}

type User struct {
	TestDataElement 	`json:"-"`
	UserID   	string 	`json:"userID"`
	FirstName 	string 	`json:"firstName"`
	LastName 	string 	`json:"lastName"`
	Salt     	string 	`json:"salt"`
	Hash     	string 	`json:"hash"`
	CompanyID	string	`json:"companyID"`
}

type Company struct {
	TestDataElement 	`json:"-"`
	CompanyID   	string 	`json:"companyID"`
	Name	 	string 	`json:"name"`
}

type Thing struct {
	TestDataElement    	`json:"-"`
	ThingID      	string 	`json:"thingID"`
	SomeProperty 	string 	`json:"someProperty"`
	UserID    	string 	`json:"userID"`
}

type Project struct {
	ProjectID	string	`json:"projectID"`
	Freelancer	string	`json:"freelancer"`
	Client		string	`json:"client"`
	StartDate	int	`json:"startDate"`
	EndDate		int	`json:"deadline"`
	Budget		float64	`json:"budget"`
	PaymentType	string	`json:"paymentType"`
	Description	string	`json:"description"`
	Deliverables	string	`json:"deliverables"`
	JobRequirements	[]string `json:"jobRequirements"`
	Location	string	`json:"location"`
	HoursPerWeek	int	`json:"hoursPerWeek"`
	CreatorID	string	`json:"creatorID"`
}

type UserAuthenticationResult struct {
	User        	User
	Authenticated 	bool
}

type Users struct {
	Users []User `json:"users"`
}

func (t *User) ID() string {
	return t.UserID
}

func (t *Thing) ID() string {
	return t.ThingID
}<|endoftext|>


<commit_before>// Package gcloud implements a DNS provider for solving the DNS-01 challenge using Google Cloud DNS.
package gcloud

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"github.com/go-acme/lego/challenge/dns01"
	"github.com/go-acme/lego/log"
	"github.com/go-acme/lego/platform/config/env"
	"github.com/go-acme/lego/platform/wait"
	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/dns/v1"
	"google.golang.org/api/googleapi"
	"google.golang.org/api/option"
)

const (
	changeStatusDone = "done"
)

// Config is used to configure the creation of the DNSProvider
type Config struct {
	Debug              bool
	Project            string
	PropagationTimeout time.Duration
	PollingInterval    time.Duration
	TTL                int
	HTTPClient         *http.Client
}

// NewDefaultConfig returns a default configuration for the DNSProvider
func NewDefaultConfig() *Config {
	return &Config{
		Debug:              env.GetOrDefaultBool("GCE_DEBUG", false),
		TTL:                env.GetOrDefaultInt("GCE_TTL", dns01.DefaultTTL),
		PropagationTimeout: env.GetOrDefaultSecond("GCE_PROPAGATION_TIMEOUT", 180*time.Second),
		PollingInterval:    env.GetOrDefaultSecond("GCE_POLLING_INTERVAL", 5*time.Second),
	}
}

// DNSProvider is an implementation of the DNSProvider interface.
type DNSProvider struct {
	config *Config
	client *dns.Service
}

// NewDNSProvider returns a DNSProvider instance configured for Google Cloud DNS.
// Project name must be passed in the environment variable: GCE_PROJECT.
// A Service Account can be passed in the environment variable: GCE_SERVICE_ACCOUNT
// or by specifying the keyfile location: GCE_SERVICE_ACCOUNT_FILE
func NewDNSProvider() (*DNSProvider, error) {
	// Use a service account file if specified via environment variable.
	if saKey := env.GetOrFile("GCE_SERVICE_ACCOUNT"); len(saKey) > 0 {
		return NewDNSProviderServiceAccountKey([]byte(saKey))
	}

	// Use default credentials.
	project := env.GetOrDefaultString("GCE_PROJECT", "")
	return NewDNSProviderCredentials(project)
}

// NewDNSProviderCredentials uses the supplied credentials
// to return a DNSProvider instance configured for Google Cloud DNS.
func NewDNSProviderCredentials(project string) (*DNSProvider, error) {
	if project == "" {
		return nil, fmt.Errorf("googlecloud: project name missing")
	}

	client, err := google.DefaultClient(context.Background(), dns.NdevClouddnsReadwriteScope)
	if err != nil {
		return nil, fmt.Errorf("googlecloud: unable to get Google Cloud client: %v", err)
	}

	config := NewDefaultConfig()
	config.Project = project
	config.HTTPClient = client

	return NewDNSProviderConfig(config)
}

// NewDNSProviderServiceAccountKey uses the supplied service account JSON
// to return a DNSProvider instance configured for Google Cloud DNS.
func NewDNSProviderServiceAccountKey(saKey []byte) (*DNSProvider, error) {
	if len(saKey) == 0 {
		return nil, fmt.Errorf("googlecloud: Service Account is missing")
	}

	// If GCE_PROJECT is non-empty it overrides the project in the service
	// account file.
	project := env.GetOrDefaultString("GCE_PROJECT", "")
	if project == "" {
		// read project id from service account file
		var datJSON struct {
			ProjectID string `json:"project_id"`
		}
		err := json.Unmarshal(saKey, &datJSON)
		if err != nil || datJSON.ProjectID == "" {
			return nil, fmt.Errorf("googlecloud: project ID not found in Google Cloud Service Account file")
		}
		project = datJSON.ProjectID
	}

	conf, err := google.JWTConfigFromJSON(saKey, dns.NdevClouddnsReadwriteScope)
	if err != nil {
		return nil, fmt.Errorf("googlecloud: unable to acquire config: %v", err)
	}
	client := conf.Client(context.Background())

	config := NewDefaultConfig()
	config.Project = project
	config.HTTPClient = client

	return NewDNSProviderConfig(config)
}

// NewDNSProviderServiceAccount uses the supplied service account JSON file
// to return a DNSProvider instance configured for Google Cloud DNS.
func NewDNSProviderServiceAccount(saFile string) (*DNSProvider, error) {
	if saFile == "" {
		return nil, fmt.Errorf("googlecloud: Service Account file missing")
	}

	saKey, err := ioutil.ReadFile(saFile)
	if err != nil {
		return nil, fmt.Errorf("googlecloud: unable to read Service Account file: %v", err)
	}

	return NewDNSProviderServiceAccountKey(saKey)
}

// NewDNSProviderConfig return a DNSProvider instance configured for Google Cloud DNS.
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
	if config == nil {
		return nil, errors.New("googlecloud: the configuration of the DNS provider is nil")
	}
	if config.HTTPClient == nil {
		return nil, fmt.Errorf("googlecloud: unable to create Google Cloud DNS service: client is nil")
	}

	svc, err := dns.NewService(context.Background(), option.WithHTTPClient(config.HTTPClient))
	if err != nil {
		return nil, fmt.Errorf("googlecloud: unable to create Google Cloud DNS service: %v", err)
	}

	return &DNSProvider{config: config, client: svc}, nil
}

// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
	fqdn, value := dns01.GetRecord(domain, keyAuth)

	zone, err := d.getHostedZone(fqdn)
	if err != nil {
		return fmt.Errorf("googlecloud: %v", err)
	}

	// Look for existing records.
	existingRrSet, err := d.findTxtRecords(zone, fqdn)
	if err != nil {
		return fmt.Errorf("googlecloud: %v", err)
	}

	for _, rrSet := range existingRrSet {
		var rrd []string
		for _, rr := range rrSet.Rrdatas {
			data := mustUnquote(rr)
			rrd = append(rrd, data)

			if data == value {
				log.Printf("skip: the record already exists: %s", value)
				return nil
			}
		}
		rrSet.Rrdatas = rrd
	}

	// Attempt to delete the existing records before adding the new one.
	if len(existingRrSet) > 0 {
		if err = d.applyChanges(zone, &dns.Change{Deletions: existingRrSet}); err != nil {
			return fmt.Errorf("googlecloud: %v", err)
		}
	}

	rec := &dns.ResourceRecordSet{
		Name:    fqdn,
		Rrdatas: []string{value},
		Ttl:     int64(d.config.TTL),
		Type:    "TXT",
	}

	// Append existing TXT record data to the new TXT record data
	for _, rrSet := range existingRrSet {
		for _, rr := range rrSet.Rrdatas {
			if rr != value {
				rec.Rrdatas = append(rec.Rrdatas, rr)
			}
		}
	}

	change := &dns.Change{
		Additions: []*dns.ResourceRecordSet{rec},
	}

	if err = d.applyChanges(zone, change); err != nil {
		return fmt.Errorf("googlecloud: %v", err)
	}

	return nil
}

func (d *DNSProvider) applyChanges(zone string, change *dns.Change) error {
	if d.config.Debug {
		data, _ := json.Marshal(change)
		log.Printf("change (Create): %s", string(data))
	}

	chg, err := d.client.Changes.Create(d.config.Project, zone, change).Do()
	if err != nil {
		if v, ok := err.(*googleapi.Error); ok {
			if v.Code == http.StatusNotFound {
				return nil
			}
		}

		data, _ := json.Marshal(change)
		return fmt.Errorf("failed to perform changes [zone %s, change %s]: %v", zone, string(data), err)
	}

	if chg.Status == changeStatusDone {
		return nil
	}

	chgID := chg.Id

	// wait for change to be acknowledged
	return wait.For("apply change", 30*time.Second, 3*time.Second, func() (bool, error) {
		if d.config.Debug {
			data, _ := json.Marshal(change)
			log.Printf("change (Get): %s", string(data))
		}

		chg, err = d.client.Changes.Get(d.config.Project, zone, chgID).Do()
		if err != nil {
			data, _ := json.Marshal(change)
			return false, fmt.Errorf("failed to get changes [zone %s, change %s]: %v", zone, string(data), err)
		}

		if chg.Status == changeStatusDone {
			return true, nil
		}

		return false, fmt.Errorf("status: %s", chg.Status)
	})
}

// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
	fqdn, _ := dns01.GetRecord(domain, keyAuth)

	zone, err := d.getHostedZone(fqdn)
	if err != nil {
		return fmt.Errorf("googlecloud: %v", err)
	}

	records, err := d.findTxtRecords(zone, fqdn)
	if err != nil {
		return fmt.Errorf("googlecloud: %v", err)
	}

	if len(records) == 0 {
		return nil
	}

	_, err = d.client.Changes.Create(d.config.Project, zone, &dns.Change{Deletions: records}).Do()
	if err != nil {
		return fmt.Errorf("googlecloud: %v", err)
	}
	return nil
}

// Timeout customizes the timeout values used by the ACME package for checking
// DNS record validity.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
	return d.config.PropagationTimeout, d.config.PollingInterval
}

// getHostedZone returns the managed-zone
func (d *DNSProvider) getHostedZone(domain string) (string, error) {
	authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain))
	if err != nil {
		return "", err
	}

	zones, err := d.client.ManagedZones.
		List(d.config.Project).
		DnsName(authZone).
		Do()
	if err != nil {
		return "", fmt.Errorf("API call failed: %v", err)
	}

	if len(zones.ManagedZones) == 0 {
		return "", fmt.Errorf("no matching domain found for domain %s", authZone)
	}

	for _, z := range zones.ManagedZones {
		if z.Visibility == "public" {
			return z.Name, nil
		}
	}

	return "", fmt.Errorf("no public zone found for domain %s", authZone)
}

func (d *DNSProvider) findTxtRecords(zone, fqdn string) ([]*dns.ResourceRecordSet, error) {
	recs, err := d.client.ResourceRecordSets.List(d.config.Project, zone).Name(fqdn).Type("TXT").Do()
	if err != nil {
		return nil, err
	}

	return recs.Rrsets, nil
}

func mustUnquote(raw string) string {
	clean, err := strconv.Unquote(raw)
	if err != nil {
		return raw
	}
	return clean
}
<commit_msg>gcloud: fix zone visibility. (#875)<commit_after>// Package gcloud implements a DNS provider for solving the DNS-01 challenge using Google Cloud DNS.
package gcloud

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"github.com/go-acme/lego/challenge/dns01"
	"github.com/go-acme/lego/log"
	"github.com/go-acme/lego/platform/config/env"
	"github.com/go-acme/lego/platform/wait"
	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/dns/v1"
	"google.golang.org/api/googleapi"
	"google.golang.org/api/option"
)

const (
	changeStatusDone = "done"
)

// Config is used to configure the creation of the DNSProvider
type Config struct {
	Debug              bool
	Project            string
	PropagationTimeout time.Duration
	PollingInterval    time.Duration
	TTL                int
	HTTPClient         *http.Client
}

// NewDefaultConfig returns a default configuration for the DNSProvider
func NewDefaultConfig() *Config {
	return &Config{
		Debug:              env.GetOrDefaultBool("GCE_DEBUG", false),
		TTL:                env.GetOrDefaultInt("GCE_TTL", dns01.DefaultTTL),
		PropagationTimeout: env.GetOrDefaultSecond("GCE_PROPAGATION_TIMEOUT", 180*time.Second),
		PollingInterval:    env.GetOrDefaultSecond("GCE_POLLING_INTERVAL", 5*time.Second),
	}
}

// DNSProvider is an implementation of the DNSProvider interface.
type DNSProvider struct {
	config *Config
	client *dns.Service
}

// NewDNSProvider returns a DNSProvider instance configured for Google Cloud DNS.
// Project name must be passed in the environment variable: GCE_PROJECT.
// A Service Account can be passed in the environment variable: GCE_SERVICE_ACCOUNT
// or by specifying the keyfile location: GCE_SERVICE_ACCOUNT_FILE
func NewDNSProvider() (*DNSProvider, error) {
	// Use a service account file if specified via environment variable.
	if saKey := env.GetOrFile("GCE_SERVICE_ACCOUNT"); len(saKey) > 0 {
		return NewDNSProviderServiceAccountKey([]byte(saKey))
	}

	// Use default credentials.
	project := env.GetOrDefaultString("GCE_PROJECT", "")
	return NewDNSProviderCredentials(project)
}

// NewDNSProviderCredentials uses the supplied credentials
// to return a DNSProvider instance configured for Google Cloud DNS.
func NewDNSProviderCredentials(project string) (*DNSProvider, error) {
	if project == "" {
		return nil, fmt.Errorf("googlecloud: project name missing")
	}

	client, err := google.DefaultClient(context.Background(), dns.NdevClouddnsReadwriteScope)
	if err != nil {
		return nil, fmt.Errorf("googlecloud: unable to get Google Cloud client: %v", err)
	}

	config := NewDefaultConfig()
	config.Project = project
	config.HTTPClient = client

	return NewDNSProviderConfig(config)
}

// NewDNSProviderServiceAccountKey uses the supplied service account JSON
// to return a DNSProvider instance configured for Google Cloud DNS.
func NewDNSProviderServiceAccountKey(saKey []byte) (*DNSProvider, error) {
	if len(saKey) == 0 {
		return nil, fmt.Errorf("googlecloud: Service Account is missing")
	}

	// If GCE_PROJECT is non-empty it overrides the project in the service
	// account file.
	project := env.GetOrDefaultString("GCE_PROJECT", "")
	if project == "" {
		// read project id from service account file
		var datJSON struct {
			ProjectID string `json:"project_id"`
		}
		err := json.Unmarshal(saKey, &datJSON)
		if err != nil || datJSON.ProjectID == "" {
			return nil, fmt.Errorf("googlecloud: project ID not found in Google Cloud Service Account file")
		}
		project = datJSON.ProjectID
	}

	conf, err := google.JWTConfigFromJSON(saKey, dns.NdevClouddnsReadwriteScope)
	if err != nil {
		return nil, fmt.Errorf("googlecloud: unable to acquire config: %v", err)
	}
	client := conf.Client(context.Background())

	config := NewDefaultConfig()
	config.Project = project
	config.HTTPClient = client

	return NewDNSProviderConfig(config)
}

// NewDNSProviderServiceAccount uses the supplied service account JSON file
// to return a DNSProvider instance configured for Google Cloud DNS.
func NewDNSProviderServiceAccount(saFile string) (*DNSProvider, error) {
	if saFile == "" {
		return nil, fmt.Errorf("googlecloud: Service Account file missing")
	}

	saKey, err := ioutil.ReadFile(saFile)
	if err != nil {
		return nil, fmt.Errorf("googlecloud: unable to read Service Account file: %v", err)
	}

	return NewDNSProviderServiceAccountKey(saKey)
}

// NewDNSProviderConfig return a DNSProvider instance configured for Google Cloud DNS.
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
	if config == nil {
		return nil, errors.New("googlecloud: the configuration of the DNS provider is nil")
	}
	if config.HTTPClient == nil {
		return nil, fmt.Errorf("googlecloud: unable to create Google Cloud DNS service: client is nil")
	}

	svc, err := dns.NewService(context.Background(), option.WithHTTPClient(config.HTTPClient))
	if err != nil {
		return nil, fmt.Errorf("googlecloud: unable to create Google Cloud DNS service: %v", err)
	}

	return &DNSProvider{config: config, client: svc}, nil
}

// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
	fqdn, value := dns01.GetRecord(domain, keyAuth)

	zone, err := d.getHostedZone(fqdn)
	if err != nil {
		return fmt.Errorf("googlecloud: %v", err)
	}

	// Look for existing records.
	existingRrSet, err := d.findTxtRecords(zone, fqdn)
	if err != nil {
		return fmt.Errorf("googlecloud: %v", err)
	}

	for _, rrSet := range existingRrSet {
		var rrd []string
		for _, rr := range rrSet.Rrdatas {
			data := mustUnquote(rr)
			rrd = append(rrd, data)

			if data == value {
				log.Printf("skip: the record already exists: %s", value)
				return nil
			}
		}
		rrSet.Rrdatas = rrd
	}

	// Attempt to delete the existing records before adding the new one.
	if len(existingRrSet) > 0 {
		if err = d.applyChanges(zone, &dns.Change{Deletions: existingRrSet}); err != nil {
			return fmt.Errorf("googlecloud: %v", err)
		}
	}

	rec := &dns.ResourceRecordSet{
		Name:    fqdn,
		Rrdatas: []string{value},
		Ttl:     int64(d.config.TTL),
		Type:    "TXT",
	}

	// Append existing TXT record data to the new TXT record data
	for _, rrSet := range existingRrSet {
		for _, rr := range rrSet.Rrdatas {
			if rr != value {
				rec.Rrdatas = append(rec.Rrdatas, rr)
			}
		}
	}

	change := &dns.Change{
		Additions: []*dns.ResourceRecordSet{rec},
	}

	if err = d.applyChanges(zone, change); err != nil {
		return fmt.Errorf("googlecloud: %v", err)
	}

	return nil
}

func (d *DNSProvider) applyChanges(zone string, change *dns.Change) error {
	if d.config.Debug {
		data, _ := json.Marshal(change)
		log.Printf("change (Create): %s", string(data))
	}

	chg, err := d.client.Changes.Create(d.config.Project, zone, change).Do()
	if err != nil {
		if v, ok := err.(*googleapi.Error); ok {
			if v.Code == http.StatusNotFound {
				return nil
			}
		}

		data, _ := json.Marshal(change)
		return fmt.Errorf("failed to perform changes [zone %s, change %s]: %v", zone, string(data), err)
	}

	if chg.Status == changeStatusDone {
		return nil
	}

	chgID := chg.Id

	// wait for change to be acknowledged
	return wait.For("apply change", 30*time.Second, 3*time.Second, func() (bool, error) {
		if d.config.Debug {
			data, _ := json.Marshal(change)
			log.Printf("change (Get): %s", string(data))
		}

		chg, err = d.client.Changes.Get(d.config.Project, zone, chgID).Do()
		if err != nil {
			data, _ := json.Marshal(change)
			return false, fmt.Errorf("failed to get changes [zone %s, change %s]: %v", zone, string(data), err)
		}

		if chg.Status == changeStatusDone {
			return true, nil
		}

		return false, fmt.Errorf("status: %s", chg.Status)
	})
}

// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
	fqdn, _ := dns01.GetRecord(domain, keyAuth)

	zone, err := d.getHostedZone(fqdn)
	if err != nil {
		return fmt.Errorf("googlecloud: %v", err)
	}

	records, err := d.findTxtRecords(zone, fqdn)
	if err != nil {
		return fmt.Errorf("googlecloud: %v", err)
	}

	if len(records) == 0 {
		return nil
	}

	_, err = d.client.Changes.Create(d.config.Project, zone, &dns.Change{Deletions: records}).Do()
	if err != nil {
		return fmt.Errorf("googlecloud: %v", err)
	}
	return nil
}

// Timeout customizes the timeout values used by the ACME package for checking
// DNS record validity.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
	return d.config.PropagationTimeout, d.config.PollingInterval
}

// getHostedZone returns the managed-zone
func (d *DNSProvider) getHostedZone(domain string) (string, error) {
	authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain))
	if err != nil {
		return "", err
	}

	zones, err := d.client.ManagedZones.
		List(d.config.Project).
		DnsName(authZone).
		Do()
	if err != nil {
		return "", fmt.Errorf("API call failed: %v", err)
	}

	if len(zones.ManagedZones) == 0 {
		return "", fmt.Errorf("no matching domain found for domain %s", authZone)
	}

	for _, z := range zones.ManagedZones {
		if z.Visibility == "public" || z.Visibility == "" {
			return z.Name, nil
		}
	}

	return "", fmt.Errorf("no public zone found for domain %s", authZone)
}

func (d *DNSProvider) findTxtRecords(zone, fqdn string) ([]*dns.ResourceRecordSet, error) {
	recs, err := d.client.ResourceRecordSets.List(d.config.Project, zone).Name(fqdn).Type("TXT").Do()
	if err != nil {
		return nil, err
	}

	return recs.Rrsets, nil
}

func mustUnquote(raw string) string {
	clean, err := strconv.Unquote(raw)
	if err != nil {
		return raw
	}
	return clean
}
<|endoftext|>


<commit_before>// Copyright 2018 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 pulseaudio

import (
	"fmt"
	"os"

	"barista.run/base/value"
	"barista.run/modules/volume"

	"github.com/jfreymuth/pulse/proto"
)

type deviceType int

const (
	// SinkDevice represents devices used for audio output, e.g. headphones.
	SinkDevice deviceType = iota
	// SourceDevice represents devices used for audio input, e.g. microphones.
	SourceDevice
)

func (deviceType deviceType) String() string {
	return ([]string{"Sink", "Source"})[deviceType]
}

// PulseAudio implementation.
type paModule struct {
	deviceName string
	deviceType deviceType
}

func openPulseAudio() (*proto.Client, error) {
	client, _, err := proto.Connect("")
	return client, err
}

// Device creates a PulseAduio volume module for a named device that can either be a sink or a source.
func Device(deviceName string, deviceType deviceType) volume.Provider {
	return &paModule{deviceName: deviceName, deviceType: deviceType}
}

// Sink creates a PulseAudio volume module for a named sink.
func Sink(sinkName string) volume.Provider {
	return Device(sinkName, SinkDevice)
}

// DefaultSink creates a PulseAudio volume module that follows the default sink.
func DefaultSink() volume.Provider {
	return Sink("@DEFAULT_SINK@")
}

// Source creates a PulseAudio volume module for a named source.
func Source(sourceName string) volume.Provider {
	return Device(sourceName, SourceDevice)
}

// DefaultSource creates a PulseAudio volume module that follows the default source.
func DefaultSource() volume.Provider {
	return Source("@DEFAULT_SOURCE@")
}

type sinkController struct {
	client     *proto.Client
	deviceName string
}

type sourceController struct {
	client     *proto.Client
	deviceName string
}

func (c *sinkController) SetVolume(newVol int64) (err error) {
	return c.client.Request(&proto.SetSinkVolume{
		SinkIndex:      proto.Undefined,
		SinkName:       c.deviceName,
		ChannelVolumes: proto.ChannelVolumes{uint32(newVol)},
	}, nil)
}

func (c *sourceController) SetVolume(newVol int64) (err error) {
	return c.client.Request(&proto.SetSourceVolume{
		SourceIndex:    proto.Undefined,
		SourceName:     c.deviceName,
		ChannelVolumes: proto.ChannelVolumes{uint32(newVol)},
	}, nil)
}

func (c *sinkController) SetMuted(muted bool) (err error) {
	return c.client.Request(&proto.SetSinkMute{
		SinkIndex: proto.Undefined,
		SinkName:  c.deviceName,
		Mute:      muted,
	}, nil)
}

func (c *sourceController) SetMuted(muted bool) (err error) {
	return c.client.Request(&proto.SetSourceMute{
		SourceIndex: proto.Undefined,
		SourceName:  c.deviceName,
		Mute:        muted,
	}, nil)
}

func getVolume(client *proto.Client, deviceName string, deviceType deviceType) (vol volume.Volume, err error) {
	switch deviceType {
	case SinkDevice:
		return getVolumeSink(client, deviceName)
	case SourceDevice:
		return getVolumeSource(client, deviceName)
	default:
		panic(fmt.Sprintf("unexpected device type %v", int(deviceType)))
	}
}

func getVolumeSink(client *proto.Client, deviceName string) (vol volume.Volume, err error) {
	repl := proto.GetSinkInfoReply{}
	err = client.Request(&proto.GetSinkInfo{SinkIndex: proto.Undefined, SinkName: deviceName}, &repl)
	if err != nil {
		return
	}
	return makeVolume(repl.ChannelVolumes, repl.Mute, &sinkController{client, deviceName}), nil
}

func getVolumeSource(client *proto.Client, deviceName string) (vol volume.Volume, err error) {
	repl := proto.GetSourceInfoReply{}
	err = client.Request(&proto.GetSourceInfo{SourceIndex: proto.Undefined, SourceName: deviceName}, &repl)
	if err != nil {
		return
	}
	return makeVolume(repl.ChannelVolumes, repl.Mute, &sourceController{client, deviceName}), nil
}

func makeVolume(channelVolumes proto.ChannelVolumes, mute bool, controller volume.Controller) volume.Volume {
	// Take the volume as the average across all channels.
	var totalVol int64
	for _, ch := range channelVolumes {
		totalVol += int64(ch)
	}
	currentVol := totalVol / int64(len(channelVolumes))
	return volume.MakeVolume(0, int64(proto.VolumeNorm), currentVol, mute, controller)
}

func (m *paModule) Worker(s *value.ErrorValue) {
	client, conn, err := proto.Connect("")
	if s.Error(err) {
		return
	}
	defer conn.Close()

	ch := make(chan struct{}, 1)

	client.Callback = func(val interface{}) {
		switch val.(type) {
		case *proto.SubscribeEvent:
			// When PulseAudio server notifies us about sink/source change,
			// refresh the volume.
			//
			// It's okay if we lose notification something due to channel
			// being full though: this means that refresh is already pending.
			select {
			case ch <- struct{}{}:
			default:
			}
		}
	}

	props := proto.PropList{
		"application.name":           proto.PropListString("barista"),
		"application.process.binary": proto.PropListString(os.Args[0]),
		"application.process.id":     proto.PropListString(fmt.Sprintf("%d", os.Getpid())),
	}

	err = client.Request(&proto.SetClientName{Props: props}, nil)
	if s.Error(err) {
		return
	}

	var mask proto.SubscriptionMask
	switch m.deviceType {
	case SinkDevice:
		mask |= proto.SubscriptionMaskSink
	case SourceDevice:
		mask |= proto.SubscriptionMaskSource
	}
	err = client.Request(&proto.Subscribe{Mask: mask}, nil)
	if s.Error(err) {
		return
	}

	for {
		if s.SetOrError(getVolume(client, m.deviceName, m.deviceType)) {
			return
		}
		<-ch
	}
}
<commit_msg>Ignore No such entity error in PulseAudio module<commit_after>// Copyright 2018 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 pulseaudio

import (
	"fmt"
	"os"

	"barista.run/base/value"
	"barista.run/modules/volume"

	"github.com/jfreymuth/pulse/proto"
)

type deviceType int

const (
	// SinkDevice represents devices used for audio output, e.g. headphones.
	SinkDevice deviceType = iota
	// SourceDevice represents devices used for audio input, e.g. microphones.
	SourceDevice
)

func (deviceType deviceType) String() string {
	return ([]string{"Sink", "Source"})[deviceType]
}

// PulseAudio implementation.
type paModule struct {
	deviceName string
	deviceType deviceType
}

func openPulseAudio() (*proto.Client, error) {
	client, _, err := proto.Connect("")
	return client, err
}

// Device creates a PulseAduio volume module for a named device that can either be a sink or a source.
func Device(deviceName string, deviceType deviceType) volume.Provider {
	return &paModule{deviceName: deviceName, deviceType: deviceType}
}

// Sink creates a PulseAudio volume module for a named sink.
func Sink(sinkName string) volume.Provider {
	return Device(sinkName, SinkDevice)
}

// DefaultSink creates a PulseAudio volume module that follows the default sink.
func DefaultSink() volume.Provider {
	return Sink("@DEFAULT_SINK@")
}

// Source creates a PulseAudio volume module for a named source.
func Source(sourceName string) volume.Provider {
	return Device(sourceName, SourceDevice)
}

// DefaultSource creates a PulseAudio volume module that follows the default source.
func DefaultSource() volume.Provider {
	return Source("@DEFAULT_SOURCE@")
}

type sinkController struct {
	client     *proto.Client
	deviceName string
}

type sourceController struct {
	client     *proto.Client
	deviceName string
}

func (c *sinkController) SetVolume(newVol int64) (err error) {
	return c.client.Request(&proto.SetSinkVolume{
		SinkIndex:      proto.Undefined,
		SinkName:       c.deviceName,
		ChannelVolumes: proto.ChannelVolumes{uint32(newVol)},
	}, nil)
}

func (c *sourceController) SetVolume(newVol int64) (err error) {
	return c.client.Request(&proto.SetSourceVolume{
		SourceIndex:    proto.Undefined,
		SourceName:     c.deviceName,
		ChannelVolumes: proto.ChannelVolumes{uint32(newVol)},
	}, nil)
}

func (c *sinkController) SetMuted(muted bool) (err error) {
	return c.client.Request(&proto.SetSinkMute{
		SinkIndex: proto.Undefined,
		SinkName:  c.deviceName,
		Mute:      muted,
	}, nil)
}

func (c *sourceController) SetMuted(muted bool) (err error) {
	return c.client.Request(&proto.SetSourceMute{
		SourceIndex: proto.Undefined,
		SourceName:  c.deviceName,
		Mute:        muted,
	}, nil)
}

func getVolume(client *proto.Client, deviceName string, deviceType deviceType) (vol volume.Volume, err error) {
	switch deviceType {
	case SinkDevice:
		return getVolumeSink(client, deviceName)
	case SourceDevice:
		return getVolumeSource(client, deviceName)
	default:
		panic(fmt.Sprintf("unexpected device type %v", int(deviceType)))
	}
}

func getVolumeSink(client *proto.Client, deviceName string) (vol volume.Volume, err error) {
	repl := proto.GetSinkInfoReply{}
	err = client.Request(&proto.GetSinkInfo{SinkIndex: proto.Undefined, SinkName: deviceName}, &repl)
	if err != nil {
		return
	}
	return makeVolume(repl.ChannelVolumes, repl.Mute, &sinkController{client, deviceName}), nil
}

func getVolumeSource(client *proto.Client, deviceName string) (vol volume.Volume, err error) {
	repl := proto.GetSourceInfoReply{}
	err = client.Request(&proto.GetSourceInfo{SourceIndex: proto.Undefined, SourceName: deviceName}, &repl)
	if err != nil {
		return
	}
	return makeVolume(repl.ChannelVolumes, repl.Mute, &sourceController{client, deviceName}), nil
}

func makeVolume(channelVolumes proto.ChannelVolumes, mute bool, controller volume.Controller) volume.Volume {
	// Take the volume as the average across all channels.
	var totalVol int64
	for _, ch := range channelVolumes {
		totalVol += int64(ch)
	}
	currentVol := totalVol / int64(len(channelVolumes))
	return volume.MakeVolume(0, int64(proto.VolumeNorm), currentVol, mute, controller)
}

func (m *paModule) Worker(s *value.ErrorValue) {
	client, conn, err := proto.Connect("")
	if s.Error(err) {
		return
	}
	defer conn.Close()

	ch := make(chan struct{}, 1)

	client.Callback = func(val interface{}) {
		switch val.(type) {
		case *proto.SubscribeEvent:
			// When PulseAudio server notifies us about sink/source change,
			// refresh the volume.
			//
			// It's okay if we lose notification something due to channel
			// being full though: this means that refresh is already pending.
			select {
			case ch <- struct{}{}:
			default:
			}
		}
	}

	props := proto.PropList{
		"application.name":           proto.PropListString("barista"),
		"application.process.binary": proto.PropListString(os.Args[0]),
		"application.process.id":     proto.PropListString(fmt.Sprintf("%d", os.Getpid())),
	}

	err = client.Request(&proto.SetClientName{Props: props}, nil)
	if s.Error(err) {
		return
	}

	var mask proto.SubscriptionMask
	switch m.deviceType {
	case SinkDevice:
		mask |= proto.SubscriptionMaskSink
	case SourceDevice:
		mask |= proto.SubscriptionMaskSource
	}
	err = client.Request(&proto.Subscribe{Mask: mask}, nil)
	if s.Error(err) {
		return
	}

	for {
		vol, err := getVolume(client, m.deviceName, m.deviceType)
		// Ignore ErrNoSuchEntity because devices may easily go away.
		if err != proto.ErrNoSuchEntity {
			if s.SetOrError(vol, err) {
				return
			}
		}
		<-ch
	}
}
<|endoftext|>


<commit_before>/*
                       WARNING WARNING WARNING

                Attention all potential contributors

   This testfile is not in the best state. We've been slowly transitioning
   from the built in "testing" package to using Ginkgo. As you can see, we've
   changed the format, but a lot of the setup, test body, descriptions, etc
   are either hardcoded, completely lacking, or misleading.

   For example:

   Describe("Testing with ginkgo"...)      // This is not a great description
   It("TestDoesSoemthing"...)              // This is a horrible description

   Describe("create-user command"...       // Describe the actual object under test
   It("creates a user when provided ..."   // this is more descriptive

   For good examples of writing Ginkgo tests for the cli, refer to

   src/cf/commands/application/delete_app_test.go
   src/cf/terminal/ui_test.go
   src/github.com/cloudfoundry/loggregator_consumer/consumer_test.go
*/

package application_test

import (
	. "cf/commands/application"
	"cf/errors"
	"cf/models"
	"code.google.com/p/gogoprotobuf/proto"
	"github.com/cloudfoundry/loggregatorlib/logmessage"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	testapi "testhelpers/api"
	testcmd "testhelpers/commands"
	testconfig "testhelpers/configuration"
	testlogs "testhelpers/logs"
	testreq "testhelpers/requirements"
	testterm "testhelpers/terminal"
	"time"

	. "testhelpers/matchers"
)

var _ = Describe("logs command", func() {
	It("fails with usage when called without one argument", func() {
		requirementsFactory, logsRepo := getLogsDependencies()

		ui := callLogs([]string{}, requirementsFactory, logsRepo)
		Expect(ui.FailedWithUsage).To(BeTrue())
	})

	It("fails requirements when not logged in", func() {
		requirementsFactory, logsRepo := getLogsDependencies()
		requirementsFactory.LoginSuccess = false

		callLogs([]string{"my-app"}, requirementsFactory, logsRepo)
		Expect(testcmd.CommandDidPassRequirements).To(BeFalse())
	})

	It("TestLogsOutputsRecentLogs", func() {
		app := models.Application{}
		app.Name = "my-app"
		app.Guid = "my-app-guid"

		currentTime := time.Now()

		recentLogs := []*logmessage.LogMessage{
			testlogs.NewLogMessage("Log Line 1", app.Guid, "DEA", currentTime),
			testlogs.NewLogMessage("Log Line 2", app.Guid, "DEA", currentTime),
		}

		requirementsFactory, logsRepo := getLogsDependencies()
		requirementsFactory.Application = app
		logsRepo.RecentLogs = recentLogs

		ui := callLogs([]string{"--recent", "my-app"}, requirementsFactory, logsRepo)

		Expect(requirementsFactory.ApplicationName).To(Equal("my-app"))
		Expect(app.Guid).To(Equal(logsRepo.AppLoggedGuid))
		Expect(ui.Outputs).To(ContainSubstrings(
			[]string{"Connected, dumping recent logs for app", "my-app", "my-org", "my-space", "my-user"},
			[]string{"Log Line 1"},
			[]string{"Log Line 2"},
		))
	})

	It("TestLogsEscapeFormattingVerbs", func() {
		app := models.Application{}
		app.Name = "my-app"
		app.Guid = "my-app-guid"

		recentLogs := []*logmessage.LogMessage{
			testlogs.NewLogMessage("hello%2Bworld%v", app.Guid, "DEA", time.Now()),
		}

		requirementsFactory, logsRepo := getLogsDependencies()
		requirementsFactory.Application = app
		logsRepo.RecentLogs = recentLogs

		ui := callLogs([]string{"--recent", "my-app"}, requirementsFactory, logsRepo)

		Expect(ui.Outputs).To(ContainSubstrings([]string{"hello%2Bworld%v"}))
	})

	It("TestLogsTailsTheAppLogs", func() {
		app := models.Application{}
		app.Name = "my-app"
		app.Guid = "my-app-guid"

		logs := []*logmessage.LogMessage{
			testlogs.NewLogMessage("Log Line 1", app.Guid, "DEA", time.Now()),
		}

		requirementsFactory, logsRepo := getLogsDependencies()
		requirementsFactory.Application = app
		logsRepo.TailLogMessages = logs

		ui := callLogs([]string{"my-app"}, requirementsFactory, logsRepo)

		Expect(requirementsFactory.ApplicationName).To(Equal("my-app"))
		Expect(app.Guid).To(Equal(logsRepo.AppLoggedGuid))
		Expect(ui.Outputs).To(ContainSubstrings(
			[]string{"Connected, tailing logs for app", "my-app", "my-org", "my-space", "my-user"},
			[]string{"Log Line 1"},
		))
	})

	Context("when the loggregator server has an invalid cert", func() {
		var (
			requirementsFactory *testreq.FakeReqFactory
			logsRepo            *testapi.FakeLogsRepository
		)

		BeforeEach(func() {
			requirementsFactory, logsRepo = getLogsDependencies()
		})

		Context("when the skip-ssl-validation flag is not set", func() {
			It("fails and informs the user about the skip-ssl-validation flag", func() {
				logsRepo.TailLogErr = errors.NewInvalidSSLCert("https://example.com", "it don't work good")
				ui := callLogs([]string{"my-app"}, requirementsFactory, logsRepo)

				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"Received invalid SSL certificate", "https://example.com"},
					[]string{"TIP"},
				))
			})

			It("informs the user of the error when they include the --recent flag", func() {
				logsRepo.RecentLogErr = errors.NewInvalidSSLCert("https://example.com", "how does SSL work???")
				ui := callLogs([]string{"--recent", "my-app"}, requirementsFactory, logsRepo)

				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"Received invalid SSL certificate", "https://example.com"},
					[]string{"TIP"},
				))
			})
		})
	})

	Context("when the loggregator server has a valid cert", func() {
		var (
			flags               []string
			requirementsFactory *testreq.FakeReqFactory
			logsRepo            *testapi.FakeLogsRepository
		)

		BeforeEach(func() {
			requirementsFactory, logsRepo = getLogsDependencies()
			flags = []string{"my-app"}
		})

		It("tails logs", func() {
			ui := callLogs(flags, requirementsFactory, logsRepo)

			Expect(ui.Outputs).To(ContainSubstrings(
				[]string{"Connected, tailing logs for app", "my-org", "my-space", "my-user"},
			))
		})
	})

	Describe("Helpers", func() {
		date := time.Date(2014, 4, 4, 11, 39, 20, 5, time.UTC)

		createMessage := func(sourceId string, sourceName string, msgType logmessage.LogMessage_MessageType, date time.Time) *logmessage.LogMessage {
			timestamp := date.UnixNano()
			return &logmessage.LogMessage{
				Message:     []byte("Hello World!\n\r\n\r"),
				AppId:       proto.String("my-app-guid"),
				MessageType: &msgType,
				SourceId:    &sourceId,
				Timestamp:   &timestamp,
				SourceName:  &sourceName,
			}
		}

		Context("when the message comes from an app", func() {
			It("includes the instance index", func() {
				msg := createMessage("4", "App", logmessage.LogMessage_OUT, date)
				Expect(LogMessageOutput(msg, time.UTC)).To(Equal("2014-04-04T11:39:20.00+0000 [App/4]   OUT Hello World!"))
			})
		})

		Context("when the message comes from a cloudfoundry component", func() {
			It("doesn't include the instance index", func() {
				msg := createMessage("4", "DEA", logmessage.LogMessage_OUT, date)
				Expect(LogMessageOutput(msg, time.UTC)).To(Equal("2014-04-04T11:39:20.00+0000 [DEA]     OUT Hello World!"))
			})
		})

		Context("when the message was written to stderr", func() {
			It("shows the log type as 'ERR'", func() {
				msg := createMessage("4", "DEA", logmessage.LogMessage_ERR, date)
				Expect(LogMessageOutput(msg, time.UTC)).To(Equal("2014-04-04T11:39:20.00+0000 [DEA]     ERR Hello World!"))
			})
		})

		It("formats the time in the given time zone", func() {
			msg := createMessage("4", "DEA", logmessage.LogMessage_ERR, date)
			Expect(LogMessageOutput(msg, time.FixedZone("the-zone", 3*60*60))).To(Equal("2014-04-04T14:39:20.00+0300 [DEA]     ERR Hello World!"))
		})
	})
})

func getLogsDependencies() (requirementsFactory *testreq.FakeReqFactory, logsRepo *testapi.FakeLogsRepository) {
	logsRepo = &testapi.FakeLogsRepository{}
	requirementsFactory = &testreq.FakeReqFactory{LoginSuccess: true}
	return
}

func callLogs(args []string, requirementsFactory *testreq.FakeReqFactory, logsRepo *testapi.FakeLogsRepository) (ui *testterm.FakeUI) {
	ui = new(testterm.FakeUI)
	ctxt := testcmd.NewContext("logs", args)

	configRepo := testconfig.NewRepositoryWithDefaults()
	cmd := NewLogs(ui, configRepo, logsRepo)
	testcmd.RunCommand(cmd, ctxt, requirementsFactory)
	return
}
<commit_msg>Decolorize log messages before asserting on contents<commit_after>/*
                       WARNING WARNING WARNING

                Attention all potential contributors

   This testfile is not in the best state. We've been slowly transitioning
   from the built in "testing" package to using Ginkgo. As you can see, we've
   changed the format, but a lot of the setup, test body, descriptions, etc
   are either hardcoded, completely lacking, or misleading.

   For example:

   Describe("Testing with ginkgo"...)      // This is not a great description
   It("TestDoesSoemthing"...)              // This is a horrible description

   Describe("create-user command"...       // Describe the actual object under test
   It("creates a user when provided ..."   // this is more descriptive

   For good examples of writing Ginkgo tests for the cli, refer to

   src/cf/commands/application/delete_app_test.go
   src/cf/terminal/ui_test.go
   src/github.com/cloudfoundry/loggregator_consumer/consumer_test.go
*/

package application_test

import (
	. "cf/commands/application"
	"cf/errors"
	"cf/models"
	"cf/terminal"
	"code.google.com/p/gogoprotobuf/proto"
	"github.com/cloudfoundry/loggregatorlib/logmessage"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	testapi "testhelpers/api"
	testcmd "testhelpers/commands"
	testconfig "testhelpers/configuration"
	testlogs "testhelpers/logs"
	testreq "testhelpers/requirements"
	testterm "testhelpers/terminal"
	"time"

	. "testhelpers/matchers"
)

var _ = Describe("logs command", func() {
	It("fails with usage when called without one argument", func() {
		requirementsFactory, logsRepo := getLogsDependencies()

		ui := callLogs([]string{}, requirementsFactory, logsRepo)
		Expect(ui.FailedWithUsage).To(BeTrue())
	})

	It("fails requirements when not logged in", func() {
		requirementsFactory, logsRepo := getLogsDependencies()
		requirementsFactory.LoginSuccess = false

		callLogs([]string{"my-app"}, requirementsFactory, logsRepo)
		Expect(testcmd.CommandDidPassRequirements).To(BeFalse())
	})

	It("TestLogsOutputsRecentLogs", func() {
		app := models.Application{}
		app.Name = "my-app"
		app.Guid = "my-app-guid"

		currentTime := time.Now()

		recentLogs := []*logmessage.LogMessage{
			testlogs.NewLogMessage("Log Line 1", app.Guid, "DEA", currentTime),
			testlogs.NewLogMessage("Log Line 2", app.Guid, "DEA", currentTime),
		}

		requirementsFactory, logsRepo := getLogsDependencies()
		requirementsFactory.Application = app
		logsRepo.RecentLogs = recentLogs

		ui := callLogs([]string{"--recent", "my-app"}, requirementsFactory, logsRepo)

		Expect(requirementsFactory.ApplicationName).To(Equal("my-app"))
		Expect(app.Guid).To(Equal(logsRepo.AppLoggedGuid))
		Expect(ui.Outputs).To(ContainSubstrings(
			[]string{"Connected, dumping recent logs for app", "my-app", "my-org", "my-space", "my-user"},
			[]string{"Log Line 1"},
			[]string{"Log Line 2"},
		))
	})

	It("TestLogsEscapeFormattingVerbs", func() {
		app := models.Application{}
		app.Name = "my-app"
		app.Guid = "my-app-guid"

		recentLogs := []*logmessage.LogMessage{
			testlogs.NewLogMessage("hello%2Bworld%v", app.Guid, "DEA", time.Now()),
		}

		requirementsFactory, logsRepo := getLogsDependencies()
		requirementsFactory.Application = app
		logsRepo.RecentLogs = recentLogs

		ui := callLogs([]string{"--recent", "my-app"}, requirementsFactory, logsRepo)

		Expect(ui.Outputs).To(ContainSubstrings([]string{"hello%2Bworld%v"}))
	})

	It("TestLogsTailsTheAppLogs", func() {
		app := models.Application{}
		app.Name = "my-app"
		app.Guid = "my-app-guid"

		logs := []*logmessage.LogMessage{
			testlogs.NewLogMessage("Log Line 1", app.Guid, "DEA", time.Now()),
		}

		requirementsFactory, logsRepo := getLogsDependencies()
		requirementsFactory.Application = app
		logsRepo.TailLogMessages = logs

		ui := callLogs([]string{"my-app"}, requirementsFactory, logsRepo)

		Expect(requirementsFactory.ApplicationName).To(Equal("my-app"))
		Expect(app.Guid).To(Equal(logsRepo.AppLoggedGuid))
		Expect(ui.Outputs).To(ContainSubstrings(
			[]string{"Connected, tailing logs for app", "my-app", "my-org", "my-space", "my-user"},
			[]string{"Log Line 1"},
		))
	})

	Context("when the loggregator server has an invalid cert", func() {
		var (
			requirementsFactory *testreq.FakeReqFactory
			logsRepo            *testapi.FakeLogsRepository
		)

		BeforeEach(func() {
			requirementsFactory, logsRepo = getLogsDependencies()
		})

		Context("when the skip-ssl-validation flag is not set", func() {
			It("fails and informs the user about the skip-ssl-validation flag", func() {
				logsRepo.TailLogErr = errors.NewInvalidSSLCert("https://example.com", "it don't work good")
				ui := callLogs([]string{"my-app"}, requirementsFactory, logsRepo)

				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"Received invalid SSL certificate", "https://example.com"},
					[]string{"TIP"},
				))
			})

			It("informs the user of the error when they include the --recent flag", func() {
				logsRepo.RecentLogErr = errors.NewInvalidSSLCert("https://example.com", "how does SSL work???")
				ui := callLogs([]string{"--recent", "my-app"}, requirementsFactory, logsRepo)

				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"Received invalid SSL certificate", "https://example.com"},
					[]string{"TIP"},
				))
			})
		})
	})

	Context("when the loggregator server has a valid cert", func() {
		var (
			flags               []string
			requirementsFactory *testreq.FakeReqFactory
			logsRepo            *testapi.FakeLogsRepository
		)

		BeforeEach(func() {
			requirementsFactory, logsRepo = getLogsDependencies()
			flags = []string{"my-app"}
		})

		It("tails logs", func() {
			ui := callLogs(flags, requirementsFactory, logsRepo)

			Expect(ui.Outputs).To(ContainSubstrings(
				[]string{"Connected, tailing logs for app", "my-org", "my-space", "my-user"},
			))
		})
	})

	Describe("Helpers", func() {
		date := time.Date(2014, 4, 4, 11, 39, 20, 5, time.UTC)

		createMessage := func(sourceId string, sourceName string, msgType logmessage.LogMessage_MessageType, date time.Time) *logmessage.LogMessage {
			timestamp := date.UnixNano()
			return &logmessage.LogMessage{
				Message:     []byte("Hello World!\n\r\n\r"),
				AppId:       proto.String("my-app-guid"),
				MessageType: &msgType,
				SourceId:    &sourceId,
				Timestamp:   &timestamp,
				SourceName:  &sourceName,
			}
		}

		Context("when the message comes from an app", func() {
			It("includes the instance index", func() {
				msg := createMessage("4", "App", logmessage.LogMessage_OUT, date)
				Expect(terminal.Decolorize(LogMessageOutput(msg, time.UTC))).To(Equal("2014-04-04T11:39:20.00+0000 [App/4]   OUT Hello World!"))
			})
		})

		Context("when the message comes from a cloudfoundry component", func() {
			It("doesn't include the instance index", func() {
				msg := createMessage("4", "DEA", logmessage.LogMessage_OUT, date)
				Expect(terminal.Decolorize(LogMessageOutput(msg, time.UTC))).To(Equal("2014-04-04T11:39:20.00+0000 [DEA]     OUT Hello World!"))
			})
		})

		Context("when the message was written to stderr", func() {
			It("shows the log type as 'ERR'", func() {
				msg := createMessage("4", "DEA", logmessage.LogMessage_ERR, date)
				Expect(terminal.Decolorize(LogMessageOutput(msg, time.UTC))).To(Equal("2014-04-04T11:39:20.00+0000 [DEA]     ERR Hello World!"))
			})
		})

		It("formats the time in the given time zone", func() {
			msg := createMessage("4", "DEA", logmessage.LogMessage_ERR, date)
			Expect(terminal.Decolorize(LogMessageOutput(msg, time.FixedZone("the-zone", 3*60*60)))).To(Equal("2014-04-04T14:39:20.00+0300 [DEA]     ERR Hello World!"))
		})
	})
})

func getLogsDependencies() (requirementsFactory *testreq.FakeReqFactory, logsRepo *testapi.FakeLogsRepository) {
	logsRepo = &testapi.FakeLogsRepository{}
	requirementsFactory = &testreq.FakeReqFactory{LoginSuccess: true}
	return
}

func callLogs(args []string, requirementsFactory *testreq.FakeReqFactory, logsRepo *testapi.FakeLogsRepository) (ui *testterm.FakeUI) {
	ui = new(testterm.FakeUI)
	ctxt := testcmd.NewContext("logs", args)

	configRepo := testconfig.NewRepositoryWithDefaults()
	cmd := NewLogs(ui, configRepo, logsRepo)
	testcmd.RunCommand(cmd, ctxt, requirementsFactory)
	return
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/ec2"
)

func TestAccAWSInstance_normal(t *testing.T) {
	var v ec2.Instance

	testCheck := func(*terraform.State) error {
		if v.AvailZone != "us-west-2a" {
			return fmt.Errorf("bad availability zone: %#v", v.AvailZone)
		}

		if len(v.SecurityGroups) == 0 {
			return fmt.Errorf("no security groups: %#v", v.SecurityGroups)
		}
		if v.SecurityGroups[0].Name != "tf_test_foo" {
			return fmt.Errorf("no security groups: %#v", v.SecurityGroups)
		}

		return nil
	}

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckInstanceDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccInstanceConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckInstanceExists(
						"aws_instance.foo", &v),
					testCheck,
					resource.TestCheckResourceAttr(
						"aws_instance.foo",
						"user_data",
						"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"),
				),
			},

			// We repeat the exact same test so that we can be sure
			// that the user data hash stuff is working without generating
			// an incorrect diff.
			resource.TestStep{
				Config: testAccInstanceConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckInstanceExists(
						"aws_instance.foo", &v),
					testCheck,
					resource.TestCheckResourceAttr(
						"aws_instance.foo",
						"user_data",
						"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"),
				),
			},
		},
	})
}

func TestAccAWSInstance_sourceDestCheck(t *testing.T) {
	var v ec2.Instance

	testCheck := func(enabled bool) resource.TestCheckFunc {
		return func(*terraform.State) error {
			if v.SourceDestCheck != enabled {
				return fmt.Errorf("bad source_dest_check: %#v", v.SourceDestCheck)
			}

			return nil
		}
	}

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckInstanceDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccInstanceConfigSourceDest,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckInstanceExists(
						"aws_instance.foo", &v),
					testCheck(true),
				),
			},

			resource.TestStep{
				Config: testAccInstanceConfigSourceDestDisable,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckInstanceExists(
						"aws_instance.foo", &v),
					testCheck(false),
				),
			},
		},
	})
}

func TestAccAWSInstance_vpc(t *testing.T) {
	var v ec2.Instance

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckInstanceDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccInstanceConfigVPC,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckInstanceExists(
						"aws_instance.foo", &v),
				),
			},
		},
	})
}

func TestAccInstance_tags(t *testing.T) {
	var v ec2.Instance

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckInstanceDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckInstanceConfigTags,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckInstanceExists("aws_instance.foo", &v),
					testAccCheckTags(&v.Tags, "foo", "bar"),
				),
			},

			resource.TestStep{
				Config: testAccCheckInstanceConfigTagsUpdate,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckInstanceExists("aws_instance.foo", &v),
					testAccCheckTags(&v.Tags, "foo", ""),
					testAccCheckTags(&v.Tags, "bar", "baz"),
				),
			},
		},
	})
}

func testAccCheckInstanceDestroy(s *terraform.State) error {
	conn := testAccProvider.ec2conn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_instance" {
			continue
		}

		// Try to find the resource
		resp, err := conn.Instances(
			[]string{rs.Primary.ID}, ec2.NewFilter())
		if err == nil {
			if len(resp.Reservations) > 0 {
				return fmt.Errorf("still exist.")
			}

			return nil
		}

		// Verify the error is what we want
		ec2err, ok := err.(*ec2.Error)
		if !ok {
			return err
		}
		if ec2err.Code != "InvalidInstanceID.NotFound" {
			return err
		}
	}

	return nil
}

func testAccCheckInstanceExists(n string, i *ec2.Instance) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}

		conn := testAccProvider.ec2conn
		resp, err := conn.Instances(
			[]string{rs.Primary.ID}, ec2.NewFilter())
		if err != nil {
			return err
		}
		if len(resp.Reservations) == 0 {
			return fmt.Errorf("Instance not found")
		}

		*i = resp.Reservations[0].Instances[0]

		return nil
	}
}

const testAccInstanceConfig = `
resource "aws_security_group" "tf_test_foo" {
	name = "tf_test_foo"
	description = "foo"

	ingress {
		protocol = "icmp"
		from_port = -1
		to_port = -1
		cidr_blocks = ["0.0.0.0/0"]
	}
}

resource "aws_instance" "foo" {
	# us-west-2
	ami = "ami-4fccb37f"
	availability_zone = "us-west-2a"

	instance_type = "m1.small"
	security_groups = ["${aws_security_group.tf_test_foo.name}"]
	user_data = "foo"
}
`

const testAccInstanceConfigSourceDest = `
resource "aws_vpc" "foo" {
	cidr_block = "10.1.0.0/16"
}

resource "aws_subnet" "foo" {
	cidr_block = "10.1.1.0/24"
	vpc_id = "${aws_vpc.foo.id}"
}

resource "aws_instance" "foo" {
	# us-west-2
	ami = "ami-4fccb37f"
	instance_type = "m1.small"
	subnet_id = "${aws_subnet.foo.id}"
	source_dest_check = true
}
`

const testAccInstanceConfigSourceDestDisable = `
resource "aws_vpc" "foo" {
	cidr_block = "10.1.0.0/16"
}

resource "aws_subnet" "foo" {
	cidr_block = "10.1.1.0/24"
	vpc_id = "${aws_vpc.foo.id}"
}

resource "aws_instance" "foo" {
	# us-west-2
	ami = "ami-4fccb37f"
	instance_type = "m1.small"
	subnet_id = "${aws_subnet.foo.id}"
	source_dest_check = false
}
`

const testAccInstanceConfigVPC = `
resource "aws_vpc" "foo" {
	cidr_block = "10.1.0.0/16"
}

resource "aws_subnet" "foo" {
	cidr_block = "10.1.1.0/24"
	vpc_id = "${aws_vpc.foo.id}"
}

resource "aws_instance" "foo" {
	# us-west-2
	ami = "ami-4fccb37f"
	instance_type = "m1.small"
	subnet_id = "${aws_subnet.foo.id}"
	associate_public_ip_address = true
}
`

const testAccCheckInstanceConfigTags = `
resource "aws_instance" "foo" {
	tags {
		foo = "bar"
	}
}
`

const testAccCheckInstanceConfigTagsUpdate = `
resource "aws_vpc" "foo" {
	tags {
		bar = "baz"
	}
}
<commit_msg>providers/aws: fix test<commit_after>package aws

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/ec2"
)

func TestAccAWSInstance_normal(t *testing.T) {
	var v ec2.Instance

	testCheck := func(*terraform.State) error {
		if v.AvailZone != "us-west-2a" {
			return fmt.Errorf("bad availability zone: %#v", v.AvailZone)
		}

		if len(v.SecurityGroups) == 0 {
			return fmt.Errorf("no security groups: %#v", v.SecurityGroups)
		}
		if v.SecurityGroups[0].Name != "tf_test_foo" {
			return fmt.Errorf("no security groups: %#v", v.SecurityGroups)
		}

		return nil
	}

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckInstanceDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccInstanceConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckInstanceExists(
						"aws_instance.foo", &v),
					testCheck,
					resource.TestCheckResourceAttr(
						"aws_instance.foo",
						"user_data",
						"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"),
				),
			},

			// We repeat the exact same test so that we can be sure
			// that the user data hash stuff is working without generating
			// an incorrect diff.
			resource.TestStep{
				Config: testAccInstanceConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckInstanceExists(
						"aws_instance.foo", &v),
					testCheck,
					resource.TestCheckResourceAttr(
						"aws_instance.foo",
						"user_data",
						"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"),
				),
			},
		},
	})
}

func TestAccAWSInstance_sourceDestCheck(t *testing.T) {
	var v ec2.Instance

	testCheck := func(enabled bool) resource.TestCheckFunc {
		return func(*terraform.State) error {
			if v.SourceDestCheck != enabled {
				return fmt.Errorf("bad source_dest_check: %#v", v.SourceDestCheck)
			}

			return nil
		}
	}

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckInstanceDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccInstanceConfigSourceDest,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckInstanceExists(
						"aws_instance.foo", &v),
					testCheck(true),
				),
			},

			resource.TestStep{
				Config: testAccInstanceConfigSourceDestDisable,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckInstanceExists(
						"aws_instance.foo", &v),
					testCheck(false),
				),
			},
		},
	})
}

func TestAccAWSInstance_vpc(t *testing.T) {
	var v ec2.Instance

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckInstanceDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccInstanceConfigVPC,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckInstanceExists(
						"aws_instance.foo", &v),
				),
			},
		},
	})
}

func TestAccInstance_tags(t *testing.T) {
	var v ec2.Instance

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckInstanceDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckInstanceConfigTags,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckInstanceExists("aws_instance.foo", &v),
					testAccCheckTags(&v.Tags, "foo", "bar"),
				),
			},

			resource.TestStep{
				Config: testAccCheckInstanceConfigTagsUpdate,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckInstanceExists("aws_instance.foo", &v),
					testAccCheckTags(&v.Tags, "foo", ""),
					testAccCheckTags(&v.Tags, "bar", "baz"),
				),
			},
		},
	})
}

func testAccCheckInstanceDestroy(s *terraform.State) error {
	conn := testAccProvider.ec2conn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_instance" {
			continue
		}

		// Try to find the resource
		resp, err := conn.Instances(
			[]string{rs.Primary.ID}, ec2.NewFilter())
		if err == nil {
			if len(resp.Reservations) > 0 {
				return fmt.Errorf("still exist.")
			}

			return nil
		}

		// Verify the error is what we want
		ec2err, ok := err.(*ec2.Error)
		if !ok {
			return err
		}
		if ec2err.Code != "InvalidInstanceID.NotFound" {
			return err
		}
	}

	return nil
}

func testAccCheckInstanceExists(n string, i *ec2.Instance) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}

		conn := testAccProvider.ec2conn
		resp, err := conn.Instances(
			[]string{rs.Primary.ID}, ec2.NewFilter())
		if err != nil {
			return err
		}
		if len(resp.Reservations) == 0 {
			return fmt.Errorf("Instance not found")
		}

		*i = resp.Reservations[0].Instances[0]

		return nil
	}
}

const testAccInstanceConfig = `
resource "aws_security_group" "tf_test_foo" {
	name = "tf_test_foo"
	description = "foo"

	ingress {
		protocol = "icmp"
		from_port = -1
		to_port = -1
		cidr_blocks = ["0.0.0.0/0"]
	}
}

resource "aws_instance" "foo" {
	# us-west-2
	ami = "ami-4fccb37f"
	availability_zone = "us-west-2a"

	instance_type = "m1.small"
	security_groups = ["${aws_security_group.tf_test_foo.name}"]
	user_data = "foo"
}
`

const testAccInstanceConfigSourceDest = `
resource "aws_vpc" "foo" {
	cidr_block = "10.1.0.0/16"
}

resource "aws_subnet" "foo" {
	cidr_block = "10.1.1.0/24"
	vpc_id = "${aws_vpc.foo.id}"
}

resource "aws_instance" "foo" {
	# us-west-2
	ami = "ami-4fccb37f"
	instance_type = "m1.small"
	subnet_id = "${aws_subnet.foo.id}"
	source_dest_check = true
}
`

const testAccInstanceConfigSourceDestDisable = `
resource "aws_vpc" "foo" {
	cidr_block = "10.1.0.0/16"
}

resource "aws_subnet" "foo" {
	cidr_block = "10.1.1.0/24"
	vpc_id = "${aws_vpc.foo.id}"
}

resource "aws_instance" "foo" {
	# us-west-2
	ami = "ami-4fccb37f"
	instance_type = "m1.small"
	subnet_id = "${aws_subnet.foo.id}"
	source_dest_check = false
}
`

const testAccInstanceConfigVPC = `
resource "aws_vpc" "foo" {
	cidr_block = "10.1.0.0/16"
}

resource "aws_subnet" "foo" {
	cidr_block = "10.1.1.0/24"
	vpc_id = "${aws_vpc.foo.id}"
}

resource "aws_instance" "foo" {
	# us-west-2
	ami = "ami-4fccb37f"
	instance_type = "m1.small"
	subnet_id = "${aws_subnet.foo.id}"
	associate_public_ip_address = true
}
`

const testAccCheckInstanceConfigTags = `
resource "aws_instance" "foo" {
	tags {
		foo = "bar"
	}
}
`

const testAccCheckInstanceConfigTagsUpdate = `
resource "aws_instance" "foo" {
	tags {
		bar = "baz"
	}
}
<|endoftext|>


<commit_before>package publisher

import (
	"encoding/json"
	"log"
	"time"

	"gopkg.in/Shopify/sarama.v1"

	"github.com/justsocialapps/holmes/tracker"
	"github.com/justsocialapps/justlib"
)

// Publish creates a Kafka producer and provides it with every TrackingObject
// received via the given trackingChannel. If the producer cannot be started
// the program is quit.
func Publish(trackingChannel <-chan *tracker.TrackingObject, kafkaHost *string, kafkaTopic string) {
	kafkaConfig := sarama.NewConfig()
	kafkaConfig.Producer.Return.Errors = true
	kafkaConfig.Producer.Return.Successes = true
	kafkaConfig.Producer.RequiredAcks = sarama.WaitForLocal
	kafkaConfig.Version = sarama.V0_10_0_0
	var producer sarama.AsyncProducer
	err := justlib.Try(0, 10*time.Second, func() error {
		var err error
		producer, err = sarama.NewAsyncProducer([]string{*kafkaHost}, kafkaConfig)
		if err != nil {
			log.Printf("Connection attempt to Kafka broker failed; trying again...\n")
		}
		return err
	})
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Kafka producer up and running with broker %s", *kafkaHost)

	var object *tracker.TrackingObject
	for {
		select {
		case successMsg := <-producer.Successes():
			log.Printf("successfully delivered msg to offset %d and partition %d\n", successMsg.Offset, successMsg.Partition)
		case errorMsg := <-producer.Errors():
			log.Printf("error delivering message: %v\n", *errorMsg)
		case object = <-trackingChannel:
			stringifiedObject, err := json.Marshal(object)
			if err == nil {
				log.Printf("publishing %s", stringifiedObject)
				producer.Input() <- &sarama.ProducerMessage{Topic: kafkaTopic, Key: nil, Value: sarama.ByteEncoder(stringifiedObject), Timestamp: time.Now()}
			}
		}
	}
}
<commit_msg>Update publisher.go<commit_after>package publisher

import (
	"encoding/json"
	"log"
	"time"

	"gopkg.in/Shopify/sarama.v1"

	"github.com/justsocialapps/holmes/tracker"
	"github.com/justsocialapps/justlib"
)

// Publish creates a Kafka producer and provides it with every TrackingObject
// received via the given trackingChannel. If the producer cannot be started
// the program exits.
func Publish(trackingChannel <-chan *tracker.TrackingObject, kafkaHost *string, kafkaTopic string) {
	kafkaConfig := sarama.NewConfig()
	kafkaConfig.Producer.Return.Errors = true
	kafkaConfig.Producer.Return.Successes = true
	kafkaConfig.Producer.RequiredAcks = sarama.WaitForLocal
	kafkaConfig.Version = sarama.V0_10_0_0
	var producer sarama.AsyncProducer
	err := justlib.Try(0, 10*time.Second, func() error {
		var err error
		producer, err = sarama.NewAsyncProducer([]string{*kafkaHost}, kafkaConfig)
		if err != nil {
			log.Printf("Connection attempt to Kafka broker failed; trying again...\n")
		}
		return err
	})
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Kafka producer up and running with broker %s", *kafkaHost)

	var object *tracker.TrackingObject
	for {
		select {
		case successMsg := <-producer.Successes():
			log.Printf("successfully delivered msg to offset %d and partition %d\n", successMsg.Offset, successMsg.Partition)
		case errorMsg := <-producer.Errors():
			log.Printf("error delivering message: %v\n", *errorMsg)
		case object = <-trackingChannel:
			stringifiedObject, err := json.Marshal(object)
			if err == nil {
				log.Printf("publishing %s", stringifiedObject)
				producer.Input() <- &sarama.ProducerMessage{Topic: kafkaTopic, Key: nil, Value: sarama.ByteEncoder(stringifiedObject), Timestamp: time.Now()}
			}
		}
	}
}
<|endoftext|>