<commit_before>package isolation_segments

import (
	"fmt"
	"io/ioutil"

	"github.com/cloudfoundry/cf-smoke-tests/smoke"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	"github.com/cloudfoundry-incubator/cf-test-helpers/workflowhelpers"
)

const (
	binaryHi          = "Hello from a binary"
	binaryAppBitsPath = "../../assets/binary"
)

var (
	testConfig *smoke.Config
	testSetup  *workflowhelpers.ReproducibleTestSuiteSetup
)

var _ = Describe("RoutingIsolationSegments", func() {
	var appsDomain string
	var orgGUID, orgName string
	var spaceName string
	var isoSpaceGUID, isoSpaceName string
	var isoSegGUID string
	var isoSegName, isoSegDomain string
	var appName string

	BeforeEach(func() {
		if testConfig.EnableIsolationSegmentTests != true {
			Skip("Skipping because EnableIsolationSegmentTests flag is set to false")
		}

		appsDomain = testConfig.GetAppsDomains()

		orgName = testSetup.RegularUserContext().Org
		spaceName = testSetup.RegularUserContext().Space
		orgGUID = GetOrgGUIDFromName(orgName, testConfig.GetDefaultTimeout())

		isoSpaceName = testSetup.RegularUserContext().Space
		isoSpaceGUID = GetSpaceGUIDFromName(isoSpaceName, testConfig.GetDefaultTimeout())

		appName = generator.PrefixedRandomName("SMOKES", "APP")

		isoSegName = testConfig.GetIsolationSegmentName()
		isoSegDomain = testConfig.GetIsolationSegmentDomain()

		if testConfig.GetUseExistingOrganization() && testConfig.GetUseExistingSpace() {
			if !OrgEntitledToIsolationSegment(orgGUID, isoSegName, testConfig.GetDefaultTimeout()) {
				Fail(fmt.Sprintf("Pre-existing org %s is not entitled to isolation segment %s", orgName, isoSegName))
			}
			isoSpaceName = testConfig.GetIsolationSegmentSpace()
			isoSpaceGUID = GetSpaceGUIDFromName(isoSpaceName, testConfig.GetDefaultTimeout())
			if !IsolationSegmentAssignedToSpace(isoSpaceGUID, testConfig.GetDefaultTimeout()) {
				Fail(fmt.Sprintf("No isolation segment assigned  to pre-existing space %s", isoSpaceName))
			}
		}

		session := cf.Cf("curl", fmt.Sprintf("/v3/organizations?names=%s", orgName))
		bytes := session.Wait(testConfig.GetDefaultTimeout()).Out.Contents()
		orgGUID = GetGUIDFromResponse(bytes)
	})

	AfterEach(func() {
		if testConfig.Cleanup {
			Expect(cf.Cf("delete", appName, "-f", "-r").Wait(testConfig.GetDefaultTimeout())).To(Exit(0))
		}
	})

	Context("When an app is pushed to a space that has been assigned the shared isolation segment", func() {
		BeforeEach(func() {
			if testConfig.GetUseExistingOrganization() {
				Expect(orgDefaultIsolationSegmentIsShared(orgGUID, testConfig.GetDefaultTimeout())).To(BeTrue(), "Org's default isolation segment is not the shared isolation segment")
			}

			if testConfig.GetUseExistingSpace() {
				spaceSession := cf.Cf("space", testConfig.GetExistingSpace()).Wait(testConfig.GetDefaultTimeout())
				Expect(spaceSession).NotTo(Say(testConfig.GetIsolationSegmentName()), "Space should be assigned to the shared isolation segment")
			}

			Eventually(cf.Cf(
				"push", appName,
				"-p", binaryAppBitsPath,
				"-b", "binary_buildpack",
				"-d", appsDomain,
				"-c", "./app"),
				testConfig.GetPushTimeout()).Should(Exit(0))
		})

		It("is reachable from the shared router", func() {
			resp := SendRequestWithSpoofedHeader(fmt.Sprintf("%s.%s", appName, appsDomain), appsDomain, testConfig.SkipSSLValidation)
			defer resp.Body.Close()

			Expect(resp.StatusCode).To(Equal(200))
			htmlData, err := ioutil.ReadAll(resp.Body)
			Expect(err).NotTo(HaveOccurred())
			Expect(string(htmlData)).To(ContainSubstring(binaryHi))
		})

		It("is not reachable from the isolation segment router", func() {
			//send a request to app in the shared domain, but through the isolation segment router
			resp := SendRequestWithSpoofedHeader(fmt.Sprintf("%s.%s", appName, appsDomain), isoSegDomain, testConfig.SkipSSLValidation)
			defer resp.Body.Close()

			Expect(resp.StatusCode).To(Equal(404))
		})
	})

	Context("When an app is pushed to a space that has been assigned an Isolation Segment", func() {
		var appName string

		BeforeEach(func() {
			CreateOrGetIsolationSegment(isoSegName, testConfig.GetDefaultTimeout())
			isoSegGUID = GetIsolationSegmentGUID(isoSegName, testConfig.GetDefaultTimeout())
			if !testConfig.GetUseExistingOrganization() {
				EntitleOrgToIsolationSegment(orgGUID, isoSegGUID, testConfig.GetDefaultTimeout())
			}

			if !testConfig.GetUseExistingSpace() {
				AssignIsolationSegmentToSpace(isoSpaceGUID, isoSegGUID, testConfig.GetDefaultTimeout())
			}
			appName = generator.PrefixedRandomName("SMOKES", "APP")
			Eventually(cf.Cf("target", "-s", isoSpaceName), testConfig.GetDefaultTimeout()).Should(Exit(0))
			Eventually(cf.Cf(
				"push", appName,
				"-p", binaryAppBitsPath,
				"-b", "binary_buildpack",
				"-d", isoSegDomain,
				"-c", "./app"),
				testConfig.GetPushTimeout()).Should(Exit(0))
		})

		AfterEach(func() {
			if !testConfig.GetUseExistingSpace() {
				ResetSpaceIsolationSegment(spaceName, isoSegName, testConfig.GetDefaultTimeout())
			}
			if !testConfig.GetUseExistingOrganization() {
				DisableOrgIsolationSegment(orgName, isoSegName, testConfig.GetDefaultTimeout())
			}
		})

		It("the app is reachable from the isolated router", func() {
			resp := SendRequestWithSpoofedHeader(fmt.Sprintf("%s.%s", appName, isoSegDomain), isoSegDomain, testConfig.SkipSSLValidation)
			defer resp.Body.Close()

			Expect(resp.StatusCode).To(Equal(200))
			htmlData, err := ioutil.ReadAll(resp.Body)
			Expect(err).NotTo(HaveOccurred())
			Expect(string(htmlData)).To(ContainSubstring(binaryHi))
		})

		It("the app is not reachable from the shared router", func() {

			resp := SendRequestWithSpoofedHeader(fmt.Sprintf("%s.%s", appName, isoSegDomain), appsDomain, testConfig.SkipSSLValidation)
			defer resp.Body.Close()

			Expect(resp.StatusCode).To(Equal(404))
		})
	})
})
<commit_msg>don't redefine appName, causes problems during cleanup<commit_after>package isolation_segments

import (
	"fmt"
	"io/ioutil"

	"github.com/cloudfoundry/cf-smoke-tests/smoke"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	"github.com/cloudfoundry-incubator/cf-test-helpers/workflowhelpers"
)

const (
	binaryHi          = "Hello from a binary"
	binaryAppBitsPath = "../../assets/binary"
)

var (
	testConfig *smoke.Config
	testSetup  *workflowhelpers.ReproducibleTestSuiteSetup
)

var _ = Describe("RoutingIsolationSegments", func() {
	var appsDomain string
	var orgGUID, orgName string
	var spaceName string
	var isoSpaceGUID, isoSpaceName string
	var isoSegGUID string
	var isoSegName, isoSegDomain string
	var appName string

	BeforeEach(func() {
		if testConfig.EnableIsolationSegmentTests != true {
			Skip("Skipping because EnableIsolationSegmentTests flag is set to false")
		}

		appsDomain = testConfig.GetAppsDomains()

		orgName = testSetup.RegularUserContext().Org
		spaceName = testSetup.RegularUserContext().Space
		orgGUID = GetOrgGUIDFromName(orgName, testConfig.GetDefaultTimeout())

		isoSpaceName = testSetup.RegularUserContext().Space
		isoSpaceGUID = GetSpaceGUIDFromName(isoSpaceName, testConfig.GetDefaultTimeout())

		appName = generator.PrefixedRandomName("SMOKES", "APP")

		isoSegName = testConfig.GetIsolationSegmentName()
		isoSegDomain = testConfig.GetIsolationSegmentDomain()

		if testConfig.GetUseExistingOrganization() && testConfig.GetUseExistingSpace() {
			if !OrgEntitledToIsolationSegment(orgGUID, isoSegName, testConfig.GetDefaultTimeout()) {
				Fail(fmt.Sprintf("Pre-existing org %s is not entitled to isolation segment %s", orgName, isoSegName))
			}
			isoSpaceName = testConfig.GetIsolationSegmentSpace()
			isoSpaceGUID = GetSpaceGUIDFromName(isoSpaceName, testConfig.GetDefaultTimeout())
			if !IsolationSegmentAssignedToSpace(isoSpaceGUID, testConfig.GetDefaultTimeout()) {
				Fail(fmt.Sprintf("No isolation segment assigned  to pre-existing space %s", isoSpaceName))
			}
		}

		session := cf.Cf("curl", fmt.Sprintf("/v3/organizations?names=%s", orgName))
		bytes := session.Wait(testConfig.GetDefaultTimeout()).Out.Contents()
		orgGUID = GetGUIDFromResponse(bytes)
	})

	AfterEach(func() {
		if testConfig.Cleanup {
			Expect(cf.Cf("delete", appName, "-f", "-r").Wait(testConfig.GetDefaultTimeout())).To(Exit(0))
		}
	})

	Context("When an app is pushed to a space that has been assigned the shared isolation segment", func() {
		BeforeEach(func() {
			if testConfig.GetUseExistingOrganization() {
				Expect(orgDefaultIsolationSegmentIsShared(orgGUID, testConfig.GetDefaultTimeout())).To(BeTrue(), "Org's default isolation segment is not the shared isolation segment")
			}

			if testConfig.GetUseExistingSpace() {
				spaceSession := cf.Cf("space", testConfig.GetExistingSpace()).Wait(testConfig.GetDefaultTimeout())
				Expect(spaceSession).NotTo(Say(testConfig.GetIsolationSegmentName()), "Space should be assigned to the shared isolation segment")
			}

			Eventually(cf.Cf(
				"push", appName,
				"-p", binaryAppBitsPath,
				"-b", "binary_buildpack",
				"-d", appsDomain,
				"-c", "./app"),
				testConfig.GetPushTimeout()).Should(Exit(0))
		})

		It("is reachable from the shared router", func() {
			resp := SendRequestWithSpoofedHeader(fmt.Sprintf("%s.%s", appName, appsDomain), appsDomain, testConfig.SkipSSLValidation)
			defer resp.Body.Close()

			Expect(resp.StatusCode).To(Equal(200))
			htmlData, err := ioutil.ReadAll(resp.Body)
			Expect(err).NotTo(HaveOccurred())
			Expect(string(htmlData)).To(ContainSubstring(binaryHi))
		})

		It("is not reachable from the isolation segment router", func() {
			//send a request to app in the shared domain, but through the isolation segment router
			resp := SendRequestWithSpoofedHeader(fmt.Sprintf("%s.%s", appName, appsDomain), isoSegDomain, testConfig.SkipSSLValidation)
			defer resp.Body.Close()

			Expect(resp.StatusCode).To(Equal(404))
		})
	})

	Context("When an app is pushed to a space that has been assigned an Isolation Segment", func() {
		BeforeEach(func() {
			CreateOrGetIsolationSegment(isoSegName, testConfig.GetDefaultTimeout())
			isoSegGUID = GetIsolationSegmentGUID(isoSegName, testConfig.GetDefaultTimeout())
			if !testConfig.GetUseExistingOrganization() {
				EntitleOrgToIsolationSegment(orgGUID, isoSegGUID, testConfig.GetDefaultTimeout())
			}

			if !testConfig.GetUseExistingSpace() {
				AssignIsolationSegmentToSpace(isoSpaceGUID, isoSegGUID, testConfig.GetDefaultTimeout())
			}
			Eventually(cf.Cf("target", "-s", isoSpaceName), testConfig.GetDefaultTimeout()).Should(Exit(0))
			Eventually(cf.Cf(
				"push", appName,
				"-p", binaryAppBitsPath,
				"-b", "binary_buildpack",
				"-d", isoSegDomain,
				"-c", "./app"),
				testConfig.GetPushTimeout()).Should(Exit(0))
		})

		AfterEach(func() {
			if !testConfig.GetUseExistingSpace() {
				ResetSpaceIsolationSegment(spaceName, isoSegName, testConfig.GetDefaultTimeout())
			}
			if !testConfig.GetUseExistingOrganization() {
				DisableOrgIsolationSegment(orgName, isoSegName, testConfig.GetDefaultTimeout())
			}
		})

		It("the app is reachable from the isolated router", func() {
			resp := SendRequestWithSpoofedHeader(fmt.Sprintf("%s.%s", appName, isoSegDomain), isoSegDomain, testConfig.SkipSSLValidation)
			defer resp.Body.Close()

			Expect(resp.StatusCode).To(Equal(200))
			htmlData, err := ioutil.ReadAll(resp.Body)
			Expect(err).NotTo(HaveOccurred())
			Expect(string(htmlData)).To(ContainSubstring(binaryHi))
		})

		It("the app is not reachable from the shared router", func() {

			resp := SendRequestWithSpoofedHeader(fmt.Sprintf("%s.%s", appName, isoSegDomain), appsDomain, testConfig.SkipSSLValidation)
			defer resp.Body.Close()

			Expect(resp.StatusCode).To(Equal(404))
		})
	})
})
<|endoftext|>


<commit_before>package view

import (
	docklistener "github.com/byrnedo/dockdash/docklistener"
	. "github.com/byrnedo/dockdash/logger"
	goDocker "github.com/fsouza/go-dockerclient"
	ui "github.com/gizak/termui"
	"sort"
	"strconv"
	"strings"
	"time"
)

type UIEvent int

const (
	KeyArrowUp UIEvent = 1 << iota
	KeyArrowDown
	KeyArrowLeft
	KeyArrowRight
	KeyCtrlC
	KeyCtrlD
	KeyQ
	Resize
	KeyI
)

type DockerInfoType int

const (
	ImageInfo DockerInfoType = iota
	Names
	PortInfo
	BindInfo
	CommandInfo
	EntrypointInfo
	EnvInfo
	VolumesInfo
	TimeInfo
)

var InfoHeaders map[DockerInfoType]string = map[DockerInfoType]string{
	ImageInfo:      "Image",
	Names:          "Names",
	PortInfo:       "Ports",
	BindInfo:       "Mounts",
	CommandInfo:    "Command",
	EntrypointInfo: "Entrypoint",
	EnvInfo:        "Envs",
	VolumesInfo:    "Volumes",
	TimeInfo:       "Created At",
}

const MaxContainers = 1000
const MaxHorizPosition = int(TimeInfo)

type View struct {
	Header   *ui.Par
	InfoBar  *ui.Par
	CpuChart *ui.BarChart
	MemChart *ui.BarChart
	NameList *ui.List
	InfoList *ui.List
}

func createContainerList() *ui.List {
	list := ui.NewList()
	list.ItemFgColor = ui.ColorCyan
	list.BorderFg = ui.ColorBlack
	list.Border = true
	return list
}

type ContainerSlice []*goDocker.Container

func (p ContainerSlice) Len() int {
	return len(p)
}

func (p ContainerSlice) Less(i, j int) bool {
	return p[i].State.StartedAt.After(p[j].State.StartedAt)
}

func (p ContainerSlice) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func createDockerLineChart() *ui.LineChart {
	lc := ui.NewLineChart()
	lc.BorderLabel = "Container Numbers"
	lc.Height = 10
	lc.AxesColor = ui.ColorWhite
	lc.LineColor = ui.ColorRed | ui.AttrBold
	lc.Mode = "line"
	return lc
}

func NewView() *View {

	var view = View{}

	view.Header = ui.NewPar("Containers")
	view.Header.Border = false
	view.Header.Text = " Dockdash - Interactive realtime container inspector"
	view.Header.Height = 2

	view.InfoBar = ui.NewPar("InfoBar")
	view.InfoBar.Border = false
	view.InfoBar.Text = ""
	view.InfoBar.Height = 2

	view.NameList = createContainerList()
	view.NameList.BorderLabel = "Name"

	view.InfoList = createContainerList()
	view.InfoList.BorderLabel = "Image"

	view.CpuChart = ui.NewBarChart()
	view.CpuChart.Border = true
	view.CpuChart.BorderLabel = "%CPU"
	view.CpuChart.BorderFg = ui.ColorBlack
	view.CpuChart.Height = 8

	view.MemChart = ui.NewBarChart()
	view.MemChart.Border = true
	view.MemChart.BorderLabel = "%MEM"
	view.MemChart.BorderFg = ui.ColorBlack
	view.MemChart.Height = 8
	return &view
}

func (v *View) SetLayout() {
	ui.Body.AddRows(
		ui.NewRow(
			ui.NewCol(12, 0, v.Header),
		),

		ui.NewRow(
			ui.NewCol(12, 0, v.InfoBar),
		),
		ui.NewRow(
			ui.NewCol(12, 0, v.CpuChart),
		),
		ui.NewRow(
			ui.NewCol(12, 0, v.MemChart),
		),
		ui.NewRow(
			ui.NewCol(3, 0, v.NameList),
			ui.NewCol(9, 0, v.InfoList),
		),
	)
}

func (v *View) Align() {
	ui.Body.Align()
}

func (v *View) ResetSize() {
	if ui.TermWidth() > 20 {
		ui.Body.Width = ui.TermWidth()
		ui.Body.Align()
	}
}

func (v *View) Render() {
	ui.Clear()
	ui.Render(ui.Body)
}

func (v *View) UpdateStats(statsCharts *docklistener.StatsMsg, offset int) {
	v.CpuChart.Data = statsCharts.CpuChart.Data[offset:]
	v.CpuChart.DataLabels = statsCharts.CpuChart.DataLabels[offset:]
	v.MemChart.Data = statsCharts.MemChart.Data[offset:]
	v.MemChart.DataLabels = statsCharts.MemChart.DataLabels[offset:]
	//v.Render()
}

func (v *View) RenderContainers(containers map[string]*goDocker.Container, infoType DockerInfoType, listOffset int, inspectMode bool) {
	names, info := getNameAndInfoOfContainers(containers, listOffset, infoType, inspectMode)
	v.NameList.Height = len(names) + 2
	v.NameList.Items = names
	v.InfoList.Height = len(info) + 2
	v.InfoList.Items = info
	v.InfoList.BorderLabel = InfoHeaders[infoType]
	v.Render()
}

func getNameAndInfoOfContainers(containers map[string]*goDocker.Container, offset int, infoType DockerInfoType, inspectMode bool) ([]string, []string) {
	var numContainers = len(containers)
	if offset > numContainers {
		offset = numContainers - 1
	}

	var (
		info                []string
		numContainersSubset = numContainers - offset
		names               = make([]string, numContainersSubset)
		containersSorted    = mapValuesSorted(containers)
		nameStr             = ""
		containerNumber     = 0
	)

	if !inspectMode {
		info = make([]string, numContainersSubset)
	}

	for index, cont := range containersSorted {
		if index < offset {
			continue
		}

		containerNumber = numContainers - index
		nameStr = strconv.Itoa(containerNumber) + ". " + cont.ID[:12] + " " + strings.TrimLeft(cont.Name, "/")

		if inspectMode && index == offset {
			names[index-offset] = "*" + nameStr
			info = createInspectModeData(index, offset, infoType, cont)
		} else {
			names[index-offset] = " " + nameStr
			if !inspectMode {
				info[index-offset] = createRegularModeData(index, offset, infoType, cont)
			}
		}

	}
	return names, info
}

func createInspectModeData(index int, offset int, infoType DockerInfoType, cont *goDocker.Container) (info []string) {
	switch infoType {
	case ImageInfo:
		info = []string{cont.Config.Image}
	case Names:
		info = []string{cont.Name}
	case PortInfo:
		info = createPortsSlice(cont.NetworkSettings.Ports)
	case BindInfo:
		info = make([]string, len(cont.HostConfig.Binds))
		for i, binding := range cont.HostConfig.Binds {
			info[i] = binding
		}
	case CommandInfo:
		info = make([]string, len(cont.Args))
		for i, arg := range cont.Args {
			info[i] = arg
		}
	case EnvInfo:
		info = make([]string, len(cont.Config.Env))
		for i, env := range cont.Config.Env {
			info[i] = env
		}
	case EntrypointInfo:
		info = make([]string, len(cont.Config.Entrypoint))
		for i, entrypoint := range cont.Config.Entrypoint {
			info[i] = entrypoint
		}
	case VolumesInfo:
		info = make([]string, len(cont.Volumes))
		i := 0
		for intVol, hostVol := range cont.Volumes {
			info[i] = intVol + ":" + hostVol + ""
			i++
		}
	case TimeInfo:
		info = []string{cont.State.StartedAt.Format(time.RubyDate)}
	default:
		Error.Println("Unhandled info type", infoType)
	}
	return
}

func createRegularModeData(index int, offset int, infoType DockerInfoType, cont *goDocker.Container) (info string) {

	switch infoType {
	case ImageInfo:
		info = cont.Config.Image
	case Names:
		info = cont.Name
		if cont.Node != nil {
			info = cont.Node.Name + info
		}
	case PortInfo:
		info = createPortsString(cont.NetworkSettings.Ports, ",")
	case BindInfo:
		info = strings.TrimRight(strings.Join(cont.HostConfig.Binds, ","), ",")
	case CommandInfo:
		info = cont.Path + " " + strings.Join(cont.Args, " ")
	case EnvInfo:
		info = strings.TrimRight(strings.Join(cont.Config.Env, ","), ",")
	case EntrypointInfo:
		info = strings.Join(cont.Config.Entrypoint, " ")
	case VolumesInfo:
		volStr := ""
		for intVol, hostVol := range cont.Volumes {
			volStr += intVol + ":" + hostVol + ","
		}
		info = strings.TrimRight(volStr, ",")
	case TimeInfo:
		info = cont.State.StartedAt.Format(time.RubyDate)
	default:
		Error.Println("Unhandled info type", infoType)
	}
	return
}

func mapValuesSorted(mapToSort map[string]*goDocker.Container) (sorted ContainerSlice) {

	sorted = make(ContainerSlice, len(mapToSort))
	var i = 0
	for _, val := range mapToSort {
		sorted[i] = val
		i++
	}
	sort.Sort(sorted)
	return
}

func createPortsString(ports map[goDocker.Port][]goDocker.PortBinding, sep string) (portsStr string) {

	for intPort, extHostPortList := range ports {
		if len(extHostPortList) == 0 {
			portsStr += intPort.Port() + "->N/A" + sep
		}
		for _, extHostPort := range extHostPortList {
			portsStr += intPort.Port() + "->" + extHostPort.HostIP + ":" + extHostPort.HostPort + sep
		}
	}
	return strings.TrimRight(portsStr, sep)
}

func createPortsSlice(ports map[goDocker.Port][]goDocker.PortBinding) (portsSlice []string) {

	portsSlice = make([]string, len(ports))
	i := 0
	for intPort, extHostPortList := range ports {
		if len(extHostPortList) == 0 {
			portsSlice[i] = intPort.Port() + "->N/A"
		}
		for _, extHostPort := range extHostPortList {
			portsSlice[i] = intPort.Port() + "->" + extHostPort.HostIP + ":" + extHostPort.HostPort
		}
		i++
	}
	return
}

func InitUIHandlers(uiEventChan chan<- UIEvent) {

	ui.Handle("/sys/kbd", func(e ui.Event) {
		Info.Printf("%+v\n", e)
	})
	ui.Handle("/sys/kbd/q", func(ui.Event) {
		uiEventChan <- KeyQ
	})

	ui.Handle("/sys/kbd/C-c", func(ui.Event) {
		uiEventChan <- KeyCtrlC
	})

	ui.Handle("/sys/kbd/C-d", func(ui.Event) {
		uiEventChan <- KeyCtrlD
	})

	ui.Handle("/sys/kbd/<left>", func(ui.Event) {
		uiEventChan <- KeyArrowLeft
	})

	ui.Handle("/sys/kbd/<right>", func(ui.Event) {
		uiEventChan <- KeyArrowRight
	})

	ui.Handle("/sys/kbd/<down>", func(ui.Event) {
		uiEventChan <- KeyArrowDown
	})

	ui.Handle("/sys/kbd/<up>", func(ui.Event) {
		uiEventChan <- KeyArrowUp
	})

	ui.Handle("sys/wnd/resize", func(ui.Event) {
		uiEventChan <- Resize
	})

	ui.Handle("/sys/kbd/i", func(ui.Event) {
		uiEventChan <- KeyI
	})

}
<commit_msg>Fixed mixup with names tab for reg and interactive mode<commit_after>package view

import (
	docklistener "github.com/byrnedo/dockdash/docklistener"
	. "github.com/byrnedo/dockdash/logger"
	goDocker "github.com/fsouza/go-dockerclient"
	ui "github.com/gizak/termui"
	"sort"
	"strconv"
	"strings"
	"time"
)

type UIEvent int

const (
	KeyArrowUp UIEvent = 1 << iota
	KeyArrowDown
	KeyArrowLeft
	KeyArrowRight
	KeyCtrlC
	KeyCtrlD
	KeyQ
	Resize
	KeyI
)

type DockerInfoType int

const (
	ImageInfo DockerInfoType = iota
	Names
	PortInfo
	BindInfo
	CommandInfo
	EntrypointInfo
	EnvInfo
	VolumesInfo
	TimeInfo
)

var InfoHeaders map[DockerInfoType]string = map[DockerInfoType]string{
	ImageInfo:      "Image",
	Names:          "Names",
	PortInfo:       "Ports",
	BindInfo:       "Mounts",
	CommandInfo:    "Command",
	EntrypointInfo: "Entrypoint",
	EnvInfo:        "Envs",
	VolumesInfo:    "Volumes",
	TimeInfo:       "Created At",
}

const MaxContainers = 1000
const MaxHorizPosition = int(TimeInfo)

type View struct {
	Header   *ui.Par
	InfoBar  *ui.Par
	CpuChart *ui.BarChart
	MemChart *ui.BarChart
	NameList *ui.List
	InfoList *ui.List
}

func createContainerList() *ui.List {
	list := ui.NewList()
	list.ItemFgColor = ui.ColorCyan
	list.BorderFg = ui.ColorBlack
	list.Border = true
	return list
}

type ContainerSlice []*goDocker.Container

func (p ContainerSlice) Len() int {
	return len(p)
}

func (p ContainerSlice) Less(i, j int) bool {
	return p[i].State.StartedAt.After(p[j].State.StartedAt)
}

func (p ContainerSlice) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func createDockerLineChart() *ui.LineChart {
	lc := ui.NewLineChart()
	lc.BorderLabel = "Container Numbers"
	lc.Height = 10
	lc.AxesColor = ui.ColorWhite
	lc.LineColor = ui.ColorRed | ui.AttrBold
	lc.Mode = "line"
	return lc
}

func NewView() *View {

	var view = View{}

	view.Header = ui.NewPar("Containers")
	view.Header.Border = false
	view.Header.Text = " Dockdash - Interactive realtime container inspector"
	view.Header.Height = 2

	view.InfoBar = ui.NewPar("InfoBar")
	view.InfoBar.Border = false
	view.InfoBar.Text = ""
	view.InfoBar.Height = 2

	view.NameList = createContainerList()
	view.NameList.BorderLabel = "Name"

	view.InfoList = createContainerList()
	view.InfoList.BorderLabel = "Image"

	view.CpuChart = ui.NewBarChart()
	view.CpuChart.Border = true
	view.CpuChart.BorderLabel = "%CPU"
	view.CpuChart.BorderFg = ui.ColorBlack
	view.CpuChart.Height = 8

	view.MemChart = ui.NewBarChart()
	view.MemChart.Border = true
	view.MemChart.BorderLabel = "%MEM"
	view.MemChart.BorderFg = ui.ColorBlack
	view.MemChart.Height = 8
	return &view
}

func (v *View) SetLayout() {
	ui.Body.AddRows(
		ui.NewRow(
			ui.NewCol(12, 0, v.Header),
		),

		ui.NewRow(
			ui.NewCol(12, 0, v.InfoBar),
		),
		ui.NewRow(
			ui.NewCol(12, 0, v.CpuChart),
		),
		ui.NewRow(
			ui.NewCol(12, 0, v.MemChart),
		),
		ui.NewRow(
			ui.NewCol(3, 0, v.NameList),
			ui.NewCol(9, 0, v.InfoList),
		),
	)
}

func (v *View) Align() {
	ui.Body.Align()
}

func (v *View) ResetSize() {
	if ui.TermWidth() > 20 {
		ui.Body.Width = ui.TermWidth()
		ui.Body.Align()
	}
}

func (v *View) Render() {
	ui.Clear()
	ui.Render(ui.Body)
}

func (v *View) UpdateStats(statsCharts *docklistener.StatsMsg, offset int) {
	v.CpuChart.Data = statsCharts.CpuChart.Data[offset:]
	v.CpuChart.DataLabels = statsCharts.CpuChart.DataLabels[offset:]
	v.MemChart.Data = statsCharts.MemChart.Data[offset:]
	v.MemChart.DataLabels = statsCharts.MemChart.DataLabels[offset:]
	//v.Render()
}

func (v *View) RenderContainers(containers map[string]*goDocker.Container, infoType DockerInfoType, listOffset int, inspectMode bool) {
	names, info := getNameAndInfoOfContainers(containers, listOffset, infoType, inspectMode)
	v.NameList.Height = len(names) + 2
	v.NameList.Items = names
	v.InfoList.Height = len(info) + 2
	v.InfoList.Items = info
	v.InfoList.BorderLabel = InfoHeaders[infoType]
	v.Render()
}

func getNameAndInfoOfContainers(containers map[string]*goDocker.Container, offset int, infoType DockerInfoType, inspectMode bool) ([]string, []string) {
	var numContainers = len(containers)
	if offset > numContainers {
		offset = numContainers - 1
	}

	var (
		info                []string
		numContainersSubset = numContainers - offset
		names               = make([]string, numContainersSubset)
		containersSorted    = mapValuesSorted(containers)
		nameStr             = ""
		containerNumber     = 0
	)

	if !inspectMode {
		info = make([]string, numContainersSubset)
	}

	for index, cont := range containersSorted {
		if index < offset {
			continue
		}

		containerNumber = numContainers - index
		nameStr = strconv.Itoa(containerNumber) + ". " + cont.ID[:12] + " " + strings.TrimLeft(cont.Name, "/")

		if inspectMode && index == offset {
			names[index-offset] = "*" + nameStr
			info = createInspectModeData(index, offset, infoType, cont)
		} else {
			names[index-offset] = " " + nameStr
			if !inspectMode {
				info[index-offset] = createRegularModeData(index, offset, infoType, cont)
			}
		}

	}
	return names, info
}

func createInspectModeData(index int, offset int, infoType DockerInfoType, cont *goDocker.Container) (info []string) {
	switch infoType {
	case ImageInfo:
		info = []string{cont.Config.Image}
	case Names:
		if cont.Node != nil {
			info = []string{cont.Node.Name, cont.Name}
		} else {
			info = []string{cont.Name}
		}
	case PortInfo:
		info = createPortsSlice(cont.NetworkSettings.Ports)
	case BindInfo:
		info = make([]string, len(cont.HostConfig.Binds))
		for i, binding := range cont.HostConfig.Binds {
			info[i] = binding
		}
	case CommandInfo:
		info = make([]string, len(cont.Args))
		for i, arg := range cont.Args {
			info[i] = arg
		}
	case EnvInfo:
		info = make([]string, len(cont.Config.Env))
		for i, env := range cont.Config.Env {
			info[i] = env
		}
	case EntrypointInfo:
		info = make([]string, len(cont.Config.Entrypoint))
		for i, entrypoint := range cont.Config.Entrypoint {
			info[i] = entrypoint
		}
	case VolumesInfo:
		info = make([]string, len(cont.Volumes))
		i := 0
		for intVol, hostVol := range cont.Volumes {
			info[i] = intVol + ":" + hostVol + ""
			i++
		}
	case TimeInfo:
		info = []string{cont.State.StartedAt.Format(time.RubyDate)}
	default:
		Error.Println("Unhandled info type", infoType)
	}
	return
}

func createRegularModeData(index int, offset int, infoType DockerInfoType, cont *goDocker.Container) (info string) {

	switch infoType {
	case ImageInfo:
		info = cont.Config.Image
	case Names:
		info = cont.Name
		if cont.Node != nil {
			info = cont.Node.Name + info
		}
	case PortInfo:
		info = createPortsString(cont.NetworkSettings.Ports, ",")
	case BindInfo:
		info = strings.TrimRight(strings.Join(cont.HostConfig.Binds, ","), ",")
	case CommandInfo:
		info = cont.Path + " " + strings.Join(cont.Args, " ")
	case EnvInfo:
		info = strings.TrimRight(strings.Join(cont.Config.Env, ","), ",")
	case EntrypointInfo:
		info = strings.Join(cont.Config.Entrypoint, " ")
	case VolumesInfo:
		volStr := ""
		for intVol, hostVol := range cont.Volumes {
			volStr += intVol + ":" + hostVol + ","
		}
		info = strings.TrimRight(volStr, ",")
	case TimeInfo:
		info = cont.State.StartedAt.Format(time.RubyDate)
	default:
		Error.Println("Unhandled info type", infoType)
	}
	return
}

func mapValuesSorted(mapToSort map[string]*goDocker.Container) (sorted ContainerSlice) {

	sorted = make(ContainerSlice, len(mapToSort))
	var i = 0
	for _, val := range mapToSort {
		sorted[i] = val
		i++
	}
	sort.Sort(sorted)
	return
}

func createPortsString(ports map[goDocker.Port][]goDocker.PortBinding, sep string) (portsStr string) {

	for intPort, extHostPortList := range ports {
		if len(extHostPortList) == 0 {
			portsStr += intPort.Port() + "->N/A" + sep
		}
		for _, extHostPort := range extHostPortList {
			portsStr += intPort.Port() + "->" + extHostPort.HostIP + ":" + extHostPort.HostPort + sep
		}
	}
	return strings.TrimRight(portsStr, sep)
}

func createPortsSlice(ports map[goDocker.Port][]goDocker.PortBinding) (portsSlice []string) {

	portsSlice = make([]string, len(ports))
	i := 0
	for intPort, extHostPortList := range ports {
		if len(extHostPortList) == 0 {
			portsSlice[i] = intPort.Port() + "->N/A"
		}
		for _, extHostPort := range extHostPortList {
			portsSlice[i] = intPort.Port() + "->" + extHostPort.HostIP + ":" + extHostPort.HostPort
		}
		i++
	}
	return
}

func InitUIHandlers(uiEventChan chan<- UIEvent) {

	ui.Handle("/sys/kbd", func(e ui.Event) {
		Info.Printf("%+v\n", e)
	})
	ui.Handle("/sys/kbd/q", func(ui.Event) {
		uiEventChan <- KeyQ
	})

	ui.Handle("/sys/kbd/C-c", func(ui.Event) {
		uiEventChan <- KeyCtrlC
	})

	ui.Handle("/sys/kbd/C-d", func(ui.Event) {
		uiEventChan <- KeyCtrlD
	})

	ui.Handle("/sys/kbd/<left>", func(ui.Event) {
		uiEventChan <- KeyArrowLeft
	})

	ui.Handle("/sys/kbd/<right>", func(ui.Event) {
		uiEventChan <- KeyArrowRight
	})

	ui.Handle("/sys/kbd/<down>", func(ui.Event) {
		uiEventChan <- KeyArrowDown
	})

	ui.Handle("/sys/kbd/<up>", func(ui.Event) {
		uiEventChan <- KeyArrowUp
	})

	ui.Handle("sys/wnd/resize", func(ui.Event) {
		uiEventChan <- Resize
	})

	ui.Handle("/sys/kbd/i", func(ui.Event) {
		uiEventChan <- KeyI
	})

}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
// 	https://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 xsrf_test

import (
	"github.com/google/go-cmp/cmp"
	"github.com/google/go-safeweb/safehttp"
	"github.com/google/go-safeweb/safehttp/plugins/xsrf"
	"github.com/google/safehtml"
	"github.com/google/safehtml/template"
	"io"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

type testDispatcher struct{}

func (testDispatcher) Write(rw http.ResponseWriter, resp safehttp.Response) error {
	switch x := resp.(type) {
	case safehtml.HTML:
		_, err := rw.Write([]byte(x.String()))
		return err
	default:
		panic("not a safe response type")
	}
}

func (testDispatcher) ExecuteTemplate(rw http.ResponseWriter, t safehttp.Template, data interface{}) error {
	switch x := t.(type) {
	case *template.Template:
		return x.Execute(rw, data)
	default:
		panic("not a safe response type")
	}
}

type responseRecorder struct {
	header http.Header
	writer io.Writer
	status int
}

func newResponseRecorder(w io.Writer) *responseRecorder {
	return &responseRecorder{
		header: http.Header{},
		writer: w,
		status: http.StatusOK,
	}
}

func (r *responseRecorder) Header() http.Header {
	return r.header
}

func (r *responseRecorder) WriteHeader(statusCode int) {
	r.status = statusCode
}

func (r *responseRecorder) Write(data []byte) (int, error) {
	return r.writer.Write(data)
}

type testUserIDStorage struct{}

func (testUserIDStorage) GetUserID() (string, error) {
	return "potato", nil
}

func TestXSRFTokenPost(t *testing.T) {
	tests := []struct {
		name       string
		target     string
		host       string
		path       string
		wantStatus int
		wantHeader map[string][]string
		wantBody   string
	}{
		{
			name:       "Valid token",
			target:     "http://foo.com/pizza",
			host:       "foo.com",
			path:       "/pizza",
			wantStatus: 200,
			wantHeader: map[string][]string{},
			wantBody:   "",
		},
		{
			name:       "Invalid host in token generation",
			target:     "http://foo.com/pizza",
			host:       "bar.com",
			path:       "/pizza",
			wantStatus: 403,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		{
			name:       "Invalid path in token generation",
			target:     "http://foo.com/pizza",
			host:       "foo.com",
			path:       "/spaghetti",
			wantStatus: 403,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		//TODO(@mihalimara22): Add tests for invalid user ID once
		//UserIDStorage.GetUserID receives a parameter
	}
	for _, test := range tests {
		p := xsrf.NewPlugin("1234", testUserIDStorage{})
		tok, err := p.GenerateToken(test.host, test.path)
		if err != nil {
			t.Fatalf("p.GenerateToken: got %v, want nil", err)
		}
		req := httptest.NewRequest("POST", test.target, strings.NewReader(xsrf.TokenKey+"="+tok))
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		m := safehttp.NewMachinery(p.Before, &testDispatcher{})
		b := strings.Builder{}
		rec := newResponseRecorder(&b)
		m.HandleRequest(rec, req)
		if rec.status != test.wantStatus {
			t.Errorf("response status: got %v, want %v", rec.status, test.wantStatus)
		}
		if diff := cmp.Diff(test.wantHeader, map[string][]string(rec.Header())); diff != "" {
			t.Errorf("rec.Header() mismatch (-want +got):\n%s", diff)
		}
		if got := b.String(); got != test.wantBody {
			t.Errorf("response body: got %q want %q", got, test.wantBody)
		}
	}
}

func TestXSRFTokenMultipart(t *testing.T) {
	tests := []struct {
		name       string
		target     string
		host       string
		path       string
		wantStatus int
		wantHeader map[string][]string
		wantBody   string
	}{
		{
			name:       "Valid token",
			target:     "http://foo.com/pizza",
			host:       "foo.com",
			path:       "/pizza",
			wantStatus: 200,
			wantHeader: map[string][]string{},
			wantBody:   "",
		},
		{
			name:       "Invalid host in token generation",
			target:     "http://foo.com/pizza",
			host:       "bar.com",
			path:       "/pizza",
			wantStatus: 403,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		{
			name:       "Invalid path in token generation",
			target:     "http://foo.com/pizza",
			host:       "foo.com",
			path:       "/spaghetti",
			wantStatus: 403,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		//TODO(@mihalimara22): Add tests for invalid user ID once
		//UserIDStorage.GetUserID receives a parameter
	}
	for _, test := range tests {
		p := xsrf.NewPlugin("1234", testUserIDStorage{})
		tok, err := p.GenerateToken(test.host, test.path)
		if err != nil {
			t.Fatalf("p.GenerateToken: got %v, want nil", err)
		}
		multipartReqBody := "--123\r\n" +
			"Content-Disposition: form-data; name=\"xsrf-token\"\r\n" +
			"\r\n" +
			tok + "\r\n" +
			"--123--\r\n"
		multipartReq := httptest.NewRequest("POST", test.target, strings.NewReader(multipartReqBody))
		multipartReq.Header.Set("Content-Type", `multipart/form-data; boundary="123"`)
		m := safehttp.NewMachinery(p.Before, &testDispatcher{})
		b := strings.Builder{}
		rec := newResponseRecorder(&b)
		m.HandleRequest(rec, multipartReq)
		if rec.status != test.wantStatus {
			t.Errorf("response status: got %v, want %v", rec.status, test.wantStatus)
		}
		if diff := cmp.Diff(test.wantHeader, map[string][]string(rec.Header())); diff != "" {
			t.Errorf("rw.header mismatch (-want +got):\n%s", diff)
		}
		if got := b.String(); got != test.wantBody {
			t.Errorf("response body: got %q want %q", got, test.wantBody)
		}
	}
}

func TestXSRFMissingToken(t *testing.T) {
	tests := []struct {
		name       string
		req        *http.Request
		wantStatus int
		wantHeader map[string][]string
		wantBody   string
	}{
		{
			name: "Missing token in POST request",
			req: func() *http.Request {
				req := httptest.NewRequest("POST", "/", strings.NewReader("foo=bar"))
				req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
				return req
			}(),
			wantStatus: 401,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Unauthorized\n",
		},
		{
			name: "Missing token in multipart request",
			req: func() *http.Request {
				b := "--123\r\n" +
					"Content-Disposition: form-data; name=\"foo\"\r\n" +
					"\r\n" +
					"bar\r\n" +
					"--123--\r\n"
				req := httptest.NewRequest("POST", "/", strings.NewReader(b))
				req.Header.Set("Content-Type", `multipart/form-data; boundary="123"`)
				return req
			}(),
			wantStatus: 401,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Unauthorized\n",
		},
	}
	for _, test := range tests {
		p := xsrf.NewPlugin("1234", testUserIDStorage{})
		m := safehttp.NewMachinery(p.Before, &testDispatcher{})
		b := strings.Builder{}
		rec := newResponseRecorder(&b)
		m.HandleRequest(rec, test.req)
		if rec.status != test.wantStatus {
			t.Errorf("response status: got %v, want %v", rec.status, test.wantStatus)
		}
		if diff := cmp.Diff(test.wantHeader, map[string][]string(rec.Header())); diff != "" {
			t.Errorf("rw.header mismatch (-want +got):\n%s", diff)
		}
		if got := b.String(); got != test.wantBody {
			t.Errorf("response body: got %q want %q", got, test.wantBody)
		}
	}
}
<commit_msg>Refactor tests to use the safehttptest API<commit_after>// Copyright 2020 Google LLC
//
// 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
//
// 	https://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 xsrf_test

import (
	"github.com/google/go-cmp/cmp"
	"github.com/google/go-safeweb/safehttp"
	"github.com/google/go-safeweb/safehttp/plugins/xsrf"
	"github.com/google/go-safeweb/safehttp/safehttptest"
	"strings"
	"testing"
)

type testUserIDStorage struct{}

func (testUserIDStorage) GetUserID() (string, error) {
	return "potato", nil
}

func TestXSRFTokenPost(t *testing.T) {
	tests := []struct {
		name       string
		target     string
		host       string
		path       string
		wantStatus int
		wantHeader map[string][]string
		wantBody   string
	}{
		{
			name:       "Valid token",
			target:     "http://foo.com/pizza",
			host:       "foo.com",
			path:       "/pizza",
			wantStatus: 200,
			wantHeader: map[string][]string{},
			wantBody:   "",
		},
		{
			name:       "Invalid host in token generation",
			target:     "http://foo.com/pizza",
			host:       "bar.com",
			path:       "/pizza",
			wantStatus: 403,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		{
			name:       "Invalid path in token generation",
			target:     "http://foo.com/pizza",
			host:       "foo.com",
			path:       "/spaghetti",
			wantStatus: 403,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		//TODO(@mihalimara22): Add tests for invalid user ID once
		//UserIDStorage.GetUserID receives a parameter
	}
	for _, test := range tests {
		p := xsrf.NewPlugin("1234", testUserIDStorage{})
		tok, err := p.GenerateToken(test.host, test.path)
		if err != nil {
			t.Fatalf("p.GenerateToken: got %v, want nil", err)
		}
		req := safehttptest.NewRequest("POST", test.target, strings.NewReader(xsrf.TokenKey+"="+tok))
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		rec := safehttptest.NewResponseRecorder()
		p.Before(rec.ResponseWriter, req)
		if rec.Status() != test.wantStatus {
			t.Errorf("response status: got %v, want %v", rec.Status(), test.wantStatus)
		}
		if diff := cmp.Diff(test.wantHeader, map[string][]string(rec.Header())); diff != "" {
			t.Errorf("rec.Header() mismatch (-want +got):\n%s", diff)
		}
		if got := rec.Body(); got != test.wantBody {
			t.Errorf("response body: got %q want %q", got, test.wantBody)
		}
	}
}

func TestXSRFTokenMultipart(t *testing.T) {
	tests := []struct {
		name       string
		target     string
		host       string
		path       string
		wantStatus int
		wantHeader map[string][]string
		wantBody   string
	}{
		{
			name:       "Valid token",
			target:     "http://foo.com/pizza",
			host:       "foo.com",
			path:       "/pizza",
			wantStatus: 200,
			wantHeader: map[string][]string{},
			wantBody:   "",
		},
		{
			name:       "Invalid host in token generation",
			target:     "http://foo.com/pizza",
			host:       "bar.com",
			path:       "/pizza",
			wantStatus: 403,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		{
			name:       "Invalid path in token generation",
			target:     "http://foo.com/pizza",
			host:       "foo.com",
			path:       "/spaghetti",
			wantStatus: 403,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		//TODO(@mihalimara22): Add tests for invalid user ID once
		//UserIDStorage.GetUserID receives a parameter
	}
	for _, test := range tests {
		p := xsrf.NewPlugin("1234", testUserIDStorage{})
		tok, err := p.GenerateToken(test.host, test.path)
		if err != nil {
			t.Fatalf("p.GenerateToken: got %v, want nil", err)
		}
		reqBody := "--123\r\n" +
			"Content-Disposition: form-data; name=\"xsrf-token\"\r\n" +
			"\r\n" +
			tok + "\r\n" +
			"--123--\r\n"
		req := safehttptest.NewRequest("POST", test.target, strings.NewReader(reqBody))
		req.Header.Set("Content-Type", `multipart/form-data; boundary="123"`)
		rec := safehttptest.NewResponseRecorder()
		p.Before(rec.ResponseWriter, req)
		if rec.Status() != test.wantStatus {
			t.Errorf("response status: got %v, want %v", rec.Status(), test.wantStatus)
		}
		if diff := cmp.Diff(test.wantHeader, map[string][]string(rec.Header())); diff != "" {
			t.Errorf("rw.header mismatch (-want +got):\n%s", diff)
		}
		if got := rec.Body(); got != test.wantBody {
			t.Errorf("response body: got %q want %q", got, test.wantBody)
		}
	}
}

func TestXSRFMissingToken(t *testing.T) {
	tests := []struct {
		name       string
		req        *safehttp.IncomingRequest
		wantStatus int
		wantHeader map[string][]string
		wantBody   string
	}{
		{
			name: "Missing token in POST request",
			req: func() *safehttp.IncomingRequest {
				req := safehttptest.NewRequest("POST", "/", strings.NewReader("foo=bar"))
				req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
				return req
			}(),
			wantStatus: 401,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Unauthorized\n",
		},
		{
			name: "Missing token in multipart request",
			req: func() *safehttp.IncomingRequest {
				b := "--123\r\n" +
					"Content-Disposition: form-data; name=\"foo\"\r\n" +
					"\r\n" +
					"bar\r\n" +
					"--123--\r\n"
				req := safehttptest.NewRequest("POST", "/", strings.NewReader(b))
				req.Header.Set("Content-Type", `multipart/form-data; boundary="123"`)
				return req
			}(),
			wantStatus: 401,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Unauthorized\n",
		},
	}
	for _, test := range tests {
		p := xsrf.NewPlugin("1234", testUserIDStorage{})
		rec := safehttptest.NewResponseRecorder()
		p.Before(rec.ResponseWriter, test.req)
		if rec.Status() != test.wantStatus {
			t.Errorf("response status: got %v, want %v", rec.Status(), test.wantStatus)
		}
		if diff := cmp.Diff(test.wantHeader, map[string][]string(rec.Header())); diff != "" {
			t.Errorf("rw.header mismatch (-want +got):\n%s", diff)
		}
		if got := rec.Body(); got != test.wantBody {
			t.Errorf("response body: got %q want %q", got, test.wantBody)
		}
	}
}
<|endoftext|>


<commit_before>// HTTP router
//
// Basic example:
//
//  package main
//
//  import (
//     "fmt"
//     "github.com/nbari/violetear"
//     "log"
//     "net/http"
//  )
//
//  func catchAll(w http.ResponseWriter, r *http.Request) {
//      fmt.Fprintf(w, r.URL.Path[1:])
//  }
//
//  func helloWorld(w http.ResponseWriter, r *http.Request) {
//      fmt.Fprintf(w, r.URL.Path[1:])
//  }
//
//  func handleUUID(w http.ResponseWriter, r *http.Request) {
//      fmt.Fprintf(w, r.URL.Path[1:])
//  }
//
//  func main() {
//      router := violetear.New()
//		router.LogRequests = true
//      router.Request_ID = "REQUEST_LOG_ID"
//
//      router.AddRegex(":uuid", `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}`)
//
//      router.HandleFunc("*", catchAll)
//      router.HandleFunc("/hello/", helloWorld, "GET,HEAD")
//      router.HandleFunc("/root/:uuid/item", handleUUID, "POST,PUT")
//
//      log.Fatal(http.ListenAndServe(":8080", router))
//  }
//
package violetear

import (
	"fmt"
	"log"
	"net/http"
	"regexp"
	"strings"
	"sync/atomic"
	"time"
)

type Router struct {
	// Routes to be matched
	routes *Trie

	// dynamicRoutes map of dynamic routes and regular expresions
	dynamicRoutes dynamicSet

	// LogRequests yes or no
	LogRequests bool

	// NotFoundHandler configurable http.Handler which is called when no matching
	// route is found. If it is not set, http.NotFound is used.
	NotFoundHandler http.Handler

	// NotAllowedHandler configurable http.Handler which is called when method not allowed.
	NotAllowedHandler http.Handler

	// PanicHandler function to handle panics.
	PanicHandler http.HandlerFunc

	// Request_ID name of the header to use or create.
	Request_ID string

	// count counter for hits, used only if Request_ID is created.
	count int64
}

var split_path_rx = regexp.MustCompile(`[^/ ]+`)

// New returns a new initialized router.
func New() *Router {
	return &Router{
		routes:        NewTrie(),
		dynamicRoutes: make(dynamicSet),
	}
}

// Handle registers the handler for the given pattern (path, http.Handler, methods).
func (v *Router) Handle(path string, handler http.Handler, http_methods ...string) error {
	path_parts := v.splitPath(path)

	// search for dynamic routes
	for _, p := range path_parts {
		if strings.HasPrefix(p, ":") {
			if _, ok := v.dynamicRoutes[p]; !ok {
				return fmt.Errorf("[%s] not found, need to add it using AddRegex(\"%s\", `your regex`)", p, p)
			}
		}
	}

	// if no methods, accept ALL
	methods := "ALL"
	if len(http_methods) > 0 {
		methods = http_methods[0]
	}

	log.Printf("Adding path: %s [%s]", path, methods)

	if err := v.routes.Set(path_parts, handler, methods); err != nil {
		return err
	}
	return nil
}

// HandleFunc add a route to the router (path, http.HandlerFunc, methods)
func (v *Router) HandleFunc(path string, handler http.HandlerFunc, http_methods ...string) error {
	return v.Handle(path, handler, http_methods...)
}

// AddRegex adds a ":named" regular expression to the dynamicRoutes
func (v *Router) AddRegex(name string, regex string) error {
	return v.dynamicRoutes.Set(name, regex)
}

// MethodNotAllowed default handler for 405
func (v *Router) MethodNotAllowed() http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w,
			http.StatusText(http.StatusMethodNotAllowed),
			http.StatusMethodNotAllowed,
		)
	})
}

// ServerHTTP dispatches the handler registered in the matched path
func (v *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	start := time.Now()
	lw := NewResponseWriter(w)

	// panic handler
	defer func() {
		if err := recover(); err != nil {
			if v.PanicHandler != nil {
				v.PanicHandler(w, r)
			} else {
				http.Error(w, http.StatusText(500), http.StatusInternalServerError)
			}
		}
	}()

	// _ path never empty, defaults to ("/")
	node, path, leaf, _ := v.routes.Get(v.splitPath(r.URL.Path))

	// checkMethod check if method is allowed or not
	checkMethod := func(node *Trie, method string) http.Handler {
		if h, ok := node.Handler[method]; ok {
			return h
		} else if h, ok := node.Handler["ALL"]; ok {
			return h
		}
		if v.NotAllowedHandler != nil {
			return v.NotAllowedHandler
		} else {
			return v.MethodNotAllowed()
		}
	}

	var match func(node *Trie, path []string, leaf bool) http.Handler

	// match find a handler for the request
	match = func(node *Trie, path []string, leaf bool) http.Handler {
		if len(node.Handler) > 0 && leaf {
			return checkMethod(node, r.Method)
		} else if node.HasRegex {
			for k, _ := range node.Node {
				if strings.HasPrefix(k, ":") {
					rx := v.dynamicRoutes[k]
					if rx.MatchString(path[0]) {
						path[0] = k
						node, path, leaf, _ := node.Get(path)
						return match(node, path, leaf)
					}
				}
			}
			if node.HasCatchall {
				return checkMethod(node.Node["*"], r.Method)
			}
		} else if node.HasCatchall {
			return checkMethod(node.Node["*"], r.Method)
		}
		// NotFound
		if v.NotFoundHandler != nil {
			return v.NotFoundHandler
		}
		return http.NotFoundHandler()
	}

	// Request-ID
	if v.Request_ID != "" {
		if rid := r.Header.Get(v.Request_ID); rid != "" {
			lw.Header().Set(v.Request_ID, rid)
		} else {
			atomic.AddInt64(&v.count, 1)
			rid = fmt.Sprintf("%s-%d-%d", r.Method, time.Now().UnixNano(), atomic.LoadInt64(&v.count))
			lw.Header().Set(v.Request_ID, rid)
		}
	}

	//h http.Handler
	h := match(node, path, leaf)

	// dispatch request
	h.ServeHTTP(lw, r)

	if v.LogRequests {
		log.Printf("%s [%s] %d %d %v %s",
			r.RemoteAddr,
			r.URL,
			lw.Status(),
			lw.Size(),
			time.Since(start),
			lw.Header().Get(v.Request_ID))
	}
	return
}

// splitPath returns an slice of the path
func (v *Router) splitPath(p string) []string {
	path_parts := split_path_rx.FindAllString(p, -1)

	// root (empty slice)
	if len(path_parts) == 0 {
		path_parts = append(path_parts, "/")
	}

	return path_parts
}
<commit_msg>	modified:   violetear.go<commit_after>// HTTP router
//
// Basic example:
//
//  package main
//
//  import (
//     "fmt"
//     "github.com/nbari/violetear"
//     "log"
//     "net/http"
//  )
//
//  func catchAll(w http.ResponseWriter, r *http.Request) {
//      fmt.Fprintf(w, r.URL.Path[1:])
//  }
//
//  func helloWorld(w http.ResponseWriter, r *http.Request) {
//      fmt.Fprintf(w, r.URL.Path[1:])
//  }
//
//  func handleUUID(w http.ResponseWriter, r *http.Request) {
//      fmt.Fprintf(w, r.URL.Path[1:])
//  }
//
//  func main() {
//      router := violetear.New()
//		router.LogRequests = true
//      router.RequestID = "REQUEST_LOG_ID"
//
//      router.AddRegex(":uuid", `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}`)
//
//      router.HandleFunc("*", catchAll)
//      router.HandleFunc("/hello/", helloWorld, "GET,HEAD")
//      router.HandleFunc("/root/:uuid/item", handleUUID, "POST,PUT")
//
//      log.Fatal(http.ListenAndServe(":8080", router))
//  }
//
package violetear

import (
	"fmt"
	"log"
	"net/http"
	"regexp"
	"strings"
	"sync/atomic"
	"time"
)

type Router struct {
	// Routes to be matched
	routes *Trie

	// dynamicRoutes map of dynamic routes and regular expresions
	dynamicRoutes dynamicSet

	// LogRequests yes or no
	LogRequests bool

	// NotFoundHandler configurable http.Handler which is called when no matching
	// route is found. If it is not set, http.NotFound is used.
	NotFoundHandler http.Handler

	// NotAllowedHandler configurable http.Handler which is called when method not allowed.
	NotAllowedHandler http.Handler

	// PanicHandler function to handle panics.
	PanicHandler http.HandlerFunc

	// RequestID name of the header to use or create.
	RequestID string

	// count counter for hits, used only if RequestID is created.
	count int64
}

var split_path_rx = regexp.MustCompile(`[^/ ]+`)

// New returns a new initialized router.
func New() *Router {
	return &Router{
		routes:        NewTrie(),
		dynamicRoutes: make(dynamicSet),
	}
}

// Handle registers the handler for the given pattern (path, http.Handler, methods).
func (v *Router) Handle(path string, handler http.Handler, http_methods ...string) error {
	path_parts := v.splitPath(path)

	// search for dynamic routes
	for _, p := range path_parts {
		if strings.HasPrefix(p, ":") {
			if _, ok := v.dynamicRoutes[p]; !ok {
				return fmt.Errorf("[%s] not found, need to add it using AddRegex(\"%s\", `your regex`)", p, p)
			}
		}
	}

	// if no methods, accept ALL
	methods := "ALL"
	if len(http_methods) > 0 {
		methods = http_methods[0]
	}

	log.Printf("Adding path: %s [%s]", path, methods)

	if err := v.routes.Set(path_parts, handler, methods); err != nil {
		return err
	}
	return nil
}

// HandleFunc add a route to the router (path, http.HandlerFunc, methods)
func (v *Router) HandleFunc(path string, handler http.HandlerFunc, http_methods ...string) error {
	return v.Handle(path, handler, http_methods...)
}

// AddRegex adds a ":named" regular expression to the dynamicRoutes
func (v *Router) AddRegex(name string, regex string) error {
	return v.dynamicRoutes.Set(name, regex)
}

// MethodNotAllowed default handler for 405
func (v *Router) MethodNotAllowed() http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w,
			http.StatusText(http.StatusMethodNotAllowed),
			http.StatusMethodNotAllowed,
		)
	})
}

// ServerHTTP dispatches the handler registered in the matched path
func (v *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	start := time.Now()
	lw := NewResponseWriter(w)

	// panic handler
	defer func() {
		if err := recover(); err != nil {
			if v.PanicHandler != nil {
				v.PanicHandler(w, r)
			} else {
				http.Error(w, http.StatusText(500), http.StatusInternalServerError)
			}
		}
	}()

	// _ path never empty, defaults to ("/")
	node, path, leaf, _ := v.routes.Get(v.splitPath(r.URL.Path))

	// checkMethod check if method is allowed or not
	checkMethod := func(node *Trie, method string) http.Handler {
		if h, ok := node.Handler[method]; ok {
			return h
		} else if h, ok := node.Handler["ALL"]; ok {
			return h
		}
		if v.NotAllowedHandler != nil {
			return v.NotAllowedHandler
		} else {
			return v.MethodNotAllowed()
		}
	}

	var match func(node *Trie, path []string, leaf bool) http.Handler

	// match find a handler for the request
	match = func(node *Trie, path []string, leaf bool) http.Handler {
		if len(node.Handler) > 0 && leaf {
			return checkMethod(node, r.Method)
		} else if node.HasRegex {
			for k, _ := range node.Node {
				if strings.HasPrefix(k, ":") {
					rx := v.dynamicRoutes[k]
					if rx.MatchString(path[0]) {
						path[0] = k
						node, path, leaf, _ := node.Get(path)
						return match(node, path, leaf)
					}
				}
			}
			if node.HasCatchall {
				return checkMethod(node.Node["*"], r.Method)
			}
		} else if node.HasCatchall {
			return checkMethod(node.Node["*"], r.Method)
		}
		// NotFound
		if v.NotFoundHandler != nil {
			return v.NotFoundHandler
		}
		return http.NotFoundHandler()
	}

	// Request-ID
	if v.RequestID != "" {
		if rid := r.Header.Get(v.RequestID); rid != "" {
			lw.Header().Set(v.RequestID, rid)
		} else {
			atomic.AddInt64(&v.count, 1)
			rid = fmt.Sprintf("%s-%d-%d", r.Method, time.Now().UnixNano(), atomic.LoadInt64(&v.count))
			lw.Header().Set(v.RequestID, rid)
		}
	}

	//h http.Handler
	h := match(node, path, leaf)

	// dispatch request
	h.ServeHTTP(lw, r)

	if v.LogRequests {
		log.Printf("%s [%s] %d %d %v %s",
			r.RemoteAddr,
			r.URL,
			lw.Status(),
			lw.Size(),
			time.Since(start),
			lw.Header().Get(v.RequestID))
	}
	return
}

// splitPath returns an slice of the path
func (v *Router) splitPath(p string) []string {
	path_parts := split_path_rx.FindAllString(p, -1)

	// root (empty slice)
	if len(path_parts) == 0 {
		path_parts = append(path_parts, "/")
	}

	return path_parts
}
<|endoftext|>


<commit_before>// Copyright 2013 The go-instagram AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package instagram

import (
	"fmt"
	"net/url"
)

// CommentsService handles communication with the comments related
// methods of the Instagram API.
//
// Instagram API docs: http://instagram.com/developer/endpoints/comments/
type CommentsService struct {
	client *Client
}

// Comment represents a comment on Instagram's media.
type Comment struct {
	CreatedTime int64  `json:"created_time,string,omitempty"`
	Text        string `json:"text,omitempty"`
	From        *User  `json:"from,omitempty"`
	ID          string `json:"id,omitempty"`
}

// MediaComments gets a full list of comments on a media.
//
// Instagram API docs: http://instagram.com/developer/endpoints/comments/#get_media_comments
func (s *CommentsService) MediaComments(mediaId string) ([]Comment, error) {
	u := fmt.Sprintf("media/%v/comments", mediaId)
	req, err := s.client.NewRequest("GET", u, "")
	if err != nil {
		return nil, err
	}

	comments := new([]Comment)
	_, err = s.client.Do(req, comments)
	return *comments, err
}

// Add a comment on a media.
//
// Instagram API docs: http://instagram.com/developer/endpoints/comments/#post_media_comments
func (s *CommentsService) Add(mediaId string, text []string) error {
	u := fmt.Sprintf("media/%v/comments", mediaId)
	params := url.Values{
		"text": text,
	}
	u += params.Encode()

	req, err := s.client.NewRequest("POST", u, "")
	if err != nil {
		return err
	}

	_, err = s.client.Do(req, nil)
	return err
}

// Delete a comment either on the authenticated user's media or authored by
// the authenticated user.
//
// Instagram API docs: http://instagram.com/developer/endpoints/comments/#delete_media_comments
func (s *CommentsService) Delete(mediaId, commentId string) error {
	u := fmt.Sprintf("media/%v/comments/%v", mediaId, commentId)
	req, err := s.client.NewRequest("DELETE", u, "")
	if err != nil {
		return err
	}

	_, err = s.client.Do(req, nil)
	return err
}
<commit_msg>Move 'text' param to body of the request.<commit_after>// Copyright 2013 The go-instagram AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package instagram

import (
	"fmt"
	"net/url"
)

// CommentsService handles communication with the comments related
// methods of the Instagram API.
//
// Instagram API docs: http://instagram.com/developer/endpoints/comments/
type CommentsService struct {
	client *Client
}

// Comment represents a comment on Instagram's media.
type Comment struct {
	CreatedTime int64  `json:"created_time,string,omitempty"`
	Text        string `json:"text,omitempty"`
	From        *User  `json:"from,omitempty"`
	ID          string `json:"id,omitempty"`
}

// MediaComments gets a full list of comments on a media.
//
// Instagram API docs: http://instagram.com/developer/endpoints/comments/#get_media_comments
func (s *CommentsService) MediaComments(mediaId string) ([]Comment, error) {
	u := fmt.Sprintf("media/%v/comments", mediaId)
	req, err := s.client.NewRequest("GET", u, "")
	if err != nil {
		return nil, err
	}

	comments := new([]Comment)
	_, err = s.client.Do(req, comments)
	return *comments, err
}

// Add a comment on a media.
//
// Instagram API docs: http://instagram.com/developer/endpoints/comments/#post_media_comments
func (s *CommentsService) Add(mediaId string, text []string) error {
	u := fmt.Sprintf("media/%v/comments", mediaId)
	params := url.Values{
		"text": text,
	}

	req, err := s.client.NewRequest("POST", u, params.Encode())
	if err != nil {
		return err
	}

	_, err = s.client.Do(req, nil)
	return err
}

// Delete a comment either on the authenticated user's media or authored by
// the authenticated user.
//
// Instagram API docs: http://instagram.com/developer/endpoints/comments/#delete_media_comments
func (s *CommentsService) Delete(mediaId, commentId string) error {
	u := fmt.Sprintf("media/%v/comments/%v", mediaId, commentId)
	req, err := s.client.NewRequest("DELETE", u, "")
	if err != nil {
		return err
	}

	_, err = s.client.Do(req, nil)
	return err
}
<|endoftext|>


<commit_before>package experiments

import (
	"bytes"
	"encoding/gob"
	"github.com/yaricom/goNEAT/neat"
	"github.com/yaricom/goNEAT/neat/genetics"
	"github.com/yaricom/goNEAT/neat/network"
	"strings"
	"testing"
	"time"
	"reflect"
)

// Tests encoding/decoding of generation
func TestGeneration_Encode_Decode(t *testing.T) {
	genome_id, fitness := 10, 23.0
	gen := buildTestGeneration(genome_id, fitness)

	var buff bytes.Buffer
	enc := gob.NewEncoder(&buff)

	// encode generation
	err := gen.Encode(enc)
	if err != nil {
		t.Error("failed to encode generation", err)
		return
	}

	// decode generation
	data := buff.Bytes()
	dec := gob.NewDecoder(bytes.NewBuffer(data))
	dgen := &Generation{}
	err = dgen.Decode(dec)
	if err != nil {
		t.Error("failed to dencode generation", err)
		return
	}

	//  and test fields
	deepCompareGenerations(gen, dgen, t)
}

func deepCompareGenerations(first, second *Generation, t *testing.T) {
	if first.Id != second.Id {
		t.Error("first.Id != second.Id")
	}
	if first.Executed != second.Executed {
		t.Errorf("first.Executed != second.Executed, %s != %s\n", first.Executed, second.Executed)
	}
	if first.Solved != second.Solved {
		t.Error("first.Solved != second.Solved")
	}

	if !reflect.DeepEqual(first.Fitness, second.Fitness) {
		t.Error("Fitness values mismatch")
	}
	if !reflect.DeepEqual(first.Age, second.Age) {
		t.Error("Age values mismatch")
	}
	if !reflect.DeepEqual(first.Compexity, second.Compexity) {
		t.Error("Compexity values mismatch")
	}

	if first.Diversity != second.Diversity {
		t.Error("first.Diversity != second.Diversity")
	}
	if first.WinnerEvals != second.WinnerEvals {
		t.Error("first.WinnerEvals != second.WinnerEvals")
	}
	if first.WinnerNodes != second.WinnerNodes {
		t.Error("first.WinnerNodes != second.WinnerNodes ")
	}
	if first.WinnerGenes != second.WinnerGenes {
		t.Error("first.WinnerGenes != second.WinnerGenes")
	}

	if first.Best.Fitness != second.Best.Fitness {
		t.Error("first.Best.Fitness != second.Best.Fitness")
	}
	if first.Best.Genotype.Id != second.Best.Genotype.Id {
		t.Error("first.Best.Genotype.Id != second.Best.Genotype.Id")
	}

	for i, tr := range second.Best.Genotype.Traits {
		if !reflect.DeepEqual(tr, first.Best.Genotype.Traits[i]) {
			t.Error("Wrong trait found in new genome")
		}
	}
	for i, nd := range second.Best.Genotype.Nodes {
		if !reflect.DeepEqual(nd, first.Best.Genotype.Nodes[i]) {
			t.Error("Wrong node found", nd, first.Best.Genotype.Nodes[i])
		}
	}

	for i, g := range second.Best.Genotype.Genes {
		if !reflect.DeepEqual(g, first.Best.Genotype.Genes[i]) {
			t.Error("Wrong gene found", g, first.Best.Genotype.Genes[i])
		}
	}
}

func buildTestGeneration(gen_id int, fitness float64) *Generation {
	epoch := Generation{}
	epoch.Id = gen_id
	epoch.Executed = time.Now().Round(time.Second)
	epoch.Solved = true
	epoch.Fitness = Floats{10.0, 30.0, 40.0, fitness}
	epoch.Age = Floats{1.0, 3.0, 4.0, 10.0}
	epoch.Compexity = Floats{34.0, 21.0, 56.0, 15.0}
	epoch.Diversity = 32
	epoch.WinnerEvals = 12423
	epoch.WinnerNodes = 7
	epoch.WinnerGenes = 5

	genome := buildTestGenome(gen_id)
	org := genetics.Organism{Fitness:fitness, Genotype:genome, Generation:gen_id}
	epoch.Best = &org

	return &epoch
}

func buildTestGenome(id int) *genetics.Genome {
	traits := []*neat.Trait{
		neat.ReadTrait(strings.NewReader("1 0.1 0 0 0 0 0 0 0")),
		neat.ReadTrait(strings.NewReader("2 0.2 0 0 0 0 0 0 0")),
		neat.ReadTrait(strings.NewReader("3 0.3 0 0 0 0 0 0 0")),
	}

	nodes := []*network.NNode{
		network.ReadNNode(strings.NewReader("1 0 1 1"), traits),
		network.ReadNNode(strings.NewReader("2 0 1 1"), traits),
		network.ReadNNode(strings.NewReader("3 0 1 3"), traits),
		network.ReadNNode(strings.NewReader("4 0 0 2"), traits),
	}

	genes := []*genetics.Gene{
		genetics.ReadGene(strings.NewReader("1 1 4 1.5 false 1 0 true"), traits, nodes),
		genetics.ReadGene(strings.NewReader("2 2 4 2.5 false 2 0 true"), traits, nodes),
		genetics.ReadGene(strings.NewReader("3 3 4 3.5 false 3 0 true"), traits, nodes),
	}

	return genetics.NewGenome(id, traits, nodes, genes)
}
<commit_msg>Fixed test genome building routine to match new genetics API<commit_after>package experiments

import (
	"bytes"
	"encoding/gob"
	"github.com/yaricom/goNEAT/neat"
	"github.com/yaricom/goNEAT/neat/genetics"
	"github.com/yaricom/goNEAT/neat/network"
	"testing"
	"time"
	"reflect"
)

// Tests encoding/decoding of generation
func TestGeneration_Encode_Decode(t *testing.T) {
	genome_id, fitness := 10, 23.0
	gen := buildTestGeneration(genome_id, fitness)

	var buff bytes.Buffer
	enc := gob.NewEncoder(&buff)

	// encode generation
	err := gen.Encode(enc)
	if err != nil {
		t.Error("failed to encode generation", err)
		return
	}

	// decode generation
	data := buff.Bytes()
	dec := gob.NewDecoder(bytes.NewBuffer(data))
	dgen := &Generation{}
	err = dgen.Decode(dec)
	if err != nil {
		t.Error("failed to dencode generation", err)
		return
	}

	//  and test fields
	deepCompareGenerations(gen, dgen, t)
}

func deepCompareGenerations(first, second *Generation, t *testing.T) {
	if first.Id != second.Id {
		t.Error("first.Id != second.Id")
	}
	if first.Executed != second.Executed {
		t.Errorf("first.Executed != second.Executed, %s != %s\n", first.Executed, second.Executed)
	}
	if first.Solved != second.Solved {
		t.Error("first.Solved != second.Solved")
	}

	if !reflect.DeepEqual(first.Fitness, second.Fitness) {
		t.Error("Fitness values mismatch")
	}
	if !reflect.DeepEqual(first.Age, second.Age) {
		t.Error("Age values mismatch")
	}
	if !reflect.DeepEqual(first.Compexity, second.Compexity) {
		t.Error("Compexity values mismatch")
	}

	if first.Diversity != second.Diversity {
		t.Error("first.Diversity != second.Diversity")
	}
	if first.WinnerEvals != second.WinnerEvals {
		t.Error("first.WinnerEvals != second.WinnerEvals")
	}
	if first.WinnerNodes != second.WinnerNodes {
		t.Error("first.WinnerNodes != second.WinnerNodes ")
	}
	if first.WinnerGenes != second.WinnerGenes {
		t.Error("first.WinnerGenes != second.WinnerGenes")
	}

	if first.Best.Fitness != second.Best.Fitness {
		t.Error("first.Best.Fitness != second.Best.Fitness")
	}
	if first.Best.Genotype.Id != second.Best.Genotype.Id {
		t.Error("first.Best.Genotype.Id != second.Best.Genotype.Id")
	}

	for i, tr := range second.Best.Genotype.Traits {
		if !reflect.DeepEqual(tr, first.Best.Genotype.Traits[i]) {
			t.Error("Wrong trait found in new genome")
		}
	}
	for i, nd := range second.Best.Genotype.Nodes {
		if !reflect.DeepEqual(nd, first.Best.Genotype.Nodes[i]) {
			t.Error("Wrong node found", nd, first.Best.Genotype.Nodes[i])
		}
	}

	for i, g := range second.Best.Genotype.Genes {
		if !reflect.DeepEqual(g, first.Best.Genotype.Genes[i]) {
			t.Error("Wrong gene found", g, first.Best.Genotype.Genes[i])
		}
	}
}

func buildTestGeneration(gen_id int, fitness float64) *Generation {
	epoch := Generation{}
	epoch.Id = gen_id
	epoch.Executed = time.Now().Round(time.Second)
	epoch.Solved = true
	epoch.Fitness = Floats{10.0, 30.0, 40.0, fitness}
	epoch.Age = Floats{1.0, 3.0, 4.0, 10.0}
	epoch.Compexity = Floats{34.0, 21.0, 56.0, 15.0}
	epoch.Diversity = 32
	epoch.WinnerEvals = 12423
	epoch.WinnerNodes = 7
	epoch.WinnerGenes = 5

	genome := buildTestGenome(gen_id)
	org := genetics.Organism{Fitness:fitness, Genotype:genome, Generation:gen_id}
	epoch.Best = &org

	return &epoch
}

func buildTestGenome(id int) *genetics.Genome {
	traits := []*neat.Trait{
		{Id:1, Params:[]float64{0.1, 0, 0, 0, 0, 0, 0, 0}},
		{Id:3, Params:[]float64{0.3, 0, 0, 0, 0, 0, 0, 0}},
		{Id:2, Params:[]float64{0.2, 0, 0, 0, 0, 0, 0, 0}},
	}

	nodes := []*network.NNode{
		{Id:1, NeuronType: network.InputNeuron, ActivationType: network.NullActivation, Incoming:make([]*network.Link, 0), Outgoing:make([]*network.Link, 0)},
		{Id:2, NeuronType: network.InputNeuron, ActivationType: network.NullActivation, Incoming:make([]*network.Link, 0), Outgoing:make([]*network.Link, 0)},
		{Id:3, NeuronType: network.BiasNeuron, ActivationType: network.SigmoidSteepenedActivation, Incoming:make([]*network.Link, 0), Outgoing:make([]*network.Link, 0)},
		{Id:4, NeuronType: network.OutputNeuron, ActivationType: network.SigmoidSteepenedActivation, Incoming:make([]*network.Link, 0), Outgoing:make([]*network.Link, 0)},
	}

	genes := []*genetics.Gene{
		genetics.NewGeneWithTrait(traits[0], 1.5, nodes[0], nodes[3], false, 1, 0),
		genetics.NewGeneWithTrait(traits[2], 2.5, nodes[1], nodes[3], false, 2, 0),
		genetics.NewGeneWithTrait(traits[1], 3.5, nodes[2], nodes[3], false, 3, 0),
	}

	return genetics.NewGenome(id, traits, nodes, genes)
}
<|endoftext|>


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

package jaeger

import (
	"fmt"
	"reflect"
	"testing"
	"time"

	gen "go.opencensus.io/exporter/jaeger/internal/gen-go/jaeger"
	"go.opencensus.io/trace"
)

// TODO(jbd): Test export.

func Test_bytesToInt64(t *testing.T) {
	type args struct {
	}
	tests := []struct {
		buf  []byte
		want int64
	}{
		{
			buf:  []byte{255, 0, 0, 0, 0, 0, 0, 0},
			want: -72057594037927936,
		},
		{
			buf:  []byte{0, 0, 0, 0, 0, 0, 0, 1},
			want: 1,
		},
		{
			buf:  []byte{0, 0, 0, 0, 0, 0, 0, 0},
			want: 0,
		},
	}
	for _, tt := range tests {
		t.Run(fmt.Sprintf("%d", tt.want), func(t *testing.T) {
			if got := bytesToInt64(tt.buf); got != tt.want {
				t.Errorf("bytesToInt64() = %v, want %v", got, tt.want)
			}
		})
	}
}

func Test_spanDataToThrift(t *testing.T) {
	now := time.Now()

	answerValue := int64(42)
	resultValue := true
	keyValue := "value"
	statusCodeValue := int64(2)
	statusMessage := "error"

	tests := []struct {
		name string
		data *trace.SpanData
		want *gen.Span
	}{
		{
			name: "no parent",
			data: &trace.SpanData{
				SpanContext: trace.SpanContext{
					TraceID: trace.TraceID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
					SpanID:  trace.SpanID{1, 2, 3, 4, 5, 6, 7, 8},
				},
				Name:      "/foo",
				StartTime: now,
				EndTime:   now,
				Attributes: map[string]interface{}{
					"answer": answerValue,
					"key":    keyValue,
					"result": resultValue,
				},
				Annotations: []trace.Annotation{
					{
						Time:    now,
						Message: statusMessage,
						Attributes: map[string]interface{}{
							"answer": answerValue,
						},
					},
				},
				Status: trace.Status{Code: 2, Message: "error"},
			},
			want: &gen.Span{
				TraceIdLow:    651345242494996240,
				TraceIdHigh:   72623859790382856,
				SpanId:        72623859790382856,
				OperationName: "/foo",
				StartTime:     now.UnixNano() / 1000,
				Duration:      0,
				Tags: []*gen.Tag{
					{Key: "answer", VType: gen.TagType_LONG, VLong: &answerValue},
					{Key: "key", VType: gen.TagType_STRING, VStr: &keyValue},
					{Key: "result", VType: gen.TagType_BOOL, VBool: &resultValue},
					{Key: "status.code", VType: gen.TagType_LONG, VLong: &statusCodeValue},
					{Key: "status.message", VType: gen.TagType_STRING, VStr: &statusMessage},
				},
				Logs: []*gen.Log{
					{Timestamp: now.UnixNano() / 1000, Fields: []*gen.Tag{
						{Key: "answer", VType: gen.TagType_LONG, VLong: &answerValue},
						{Key: "message", VType: gen.TagType_STRING, VStr: &statusMessage},
					}},
				},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := spanDataToThrift(tt.data); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("spanDataToThrift() = %v, want %v", got, tt.want)
			}
		})
	}
}
<commit_msg>Fix the flaky Jaeger exporter test<commit_after>// Copyright 2018, OpenCensus Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package jaeger

import (
	"fmt"
	"reflect"
	"testing"
	"time"

	gen "go.opencensus.io/exporter/jaeger/internal/gen-go/jaeger"
	"go.opencensus.io/trace"
)

// TODO(jbd): Test export.

func Test_bytesToInt64(t *testing.T) {
	type args struct {
	}
	tests := []struct {
		buf  []byte
		want int64
	}{
		{
			buf:  []byte{255, 0, 0, 0, 0, 0, 0, 0},
			want: -72057594037927936,
		},
		{
			buf:  []byte{0, 0, 0, 0, 0, 0, 0, 1},
			want: 1,
		},
		{
			buf:  []byte{0, 0, 0, 0, 0, 0, 0, 0},
			want: 0,
		},
	}
	for _, tt := range tests {
		t.Run(fmt.Sprintf("%d", tt.want), func(t *testing.T) {
			if got := bytesToInt64(tt.buf); got != tt.want {
				t.Errorf("bytesToInt64() = %v, want %v", got, tt.want)
			}
		})
	}
}

func Test_spanDataToThrift(t *testing.T) {
	now := time.Now()

	answerValue := int64(42)
	keyValue := "value"
	resultValue := true
	statusCodeValue := int64(2)
	statusMessage := "error"

	tests := []struct {
		name string
		data *trace.SpanData
		want *gen.Span
	}{
		{
			name: "no parent",
			data: &trace.SpanData{
				SpanContext: trace.SpanContext{
					TraceID: trace.TraceID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
					SpanID:  trace.SpanID{1, 2, 3, 4, 5, 6, 7, 8},
				},
				Name:      "/foo",
				StartTime: now,
				EndTime:   now,
				Attributes: map[string]interface{}{
					"key": keyValue,
				},
				Annotations: []trace.Annotation{
					{
						Time:    now,
						Message: statusMessage,
						Attributes: map[string]interface{}{
							"answer": answerValue,
						},
					},
					{
						Time:    now,
						Message: statusMessage,
						Attributes: map[string]interface{}{
							"result": resultValue,
						},
					},
				},
				Status: trace.Status{Code: 2, Message: "error"},
			},
			want: &gen.Span{
				TraceIdLow:    651345242494996240,
				TraceIdHigh:   72623859790382856,
				SpanId:        72623859790382856,
				OperationName: "/foo",
				StartTime:     now.UnixNano() / 1000,
				Duration:      0,
				Tags: []*gen.Tag{
					{Key: "key", VType: gen.TagType_STRING, VStr: &keyValue},
					{Key: "status.code", VType: gen.TagType_LONG, VLong: &statusCodeValue},
					{Key: "status.message", VType: gen.TagType_STRING, VStr: &statusMessage},
				},
				Logs: []*gen.Log{
					{Timestamp: now.UnixNano() / 1000, Fields: []*gen.Tag{
						{Key: "answer", VType: gen.TagType_LONG, VLong: &answerValue},
						{Key: "message", VType: gen.TagType_STRING, VStr: &statusMessage},
					}},
					{Timestamp: now.UnixNano() / 1000, Fields: []*gen.Tag{
						{Key: "result", VType: gen.TagType_BOOL, VBool: &resultValue},
						{Key: "message", VType: gen.TagType_STRING, VStr: &statusMessage},
					}},
				},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := spanDataToThrift(tt.data); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("spanDataToThrift() = %v, want %v", got, tt.want)
			}
		})
	}
}
<|endoftext|>


<commit_before>// (c) 2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package health

import (
	"net/http"
	"time"

	health "github.com/AppsFlyer/go-sundheit"

	"github.com/gorilla/rpc/v2"

	"github.com/ava-labs/gecko/snow/engine/common"
	"github.com/ava-labs/gecko/utils/json"
	"github.com/ava-labs/gecko/utils/logging"
)

// defaultCheckOpts is a Check whose properties represent a default Check
var defaultCheckOpts = Check{ExecutionPeriod: time.Minute}

// Health observes a set of vital signs and makes them available through an HTTP
// API.
type Health struct {
	log    logging.Logger
	health health.Health
}

// NewService creates a new Health service
func NewService(log logging.Logger) *Health {
	return &Health{log, health.New()}
}

// Handler returns an HTTPHandler providing RPC access to the Health service
func (h *Health) Handler() *common.HTTPHandler {
	newServer := rpc.NewServer()
	codec := json.NewCodec()
	newServer.RegisterCodec(codec, "application/json")
	newServer.RegisterCodec(codec, "application/json;charset=UTF-8")
	newServer.RegisterService(h, "health")
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodGet { // GET request --> return 200 if getLiveness returns true, else 500
			if _, healthy := h.health.Results(); healthy {
				w.WriteHeader(http.StatusOK)
			} else {
				w.WriteHeader(http.StatusInternalServerError)
			}
		} else {
			newServer.ServeHTTP(w, r) // Other request --> use JSON RPC
		}
	})
	return &common.HTTPHandler{LockOptions: common.NoLock, Handler: handler}
}

// RegisterHeartbeat adds a check with default options and a CheckFn that checks
// the given heartbeater for a recent heartbeat
func (h *Health) RegisterHeartbeat(name string, hb Heartbeater, max time.Duration) error {
	return h.RegisterCheckFunc(name, HeartbeatCheckFn(hb, max))
}

// RegisterCheckFunc adds a Check with default options and the given CheckFn
func (h *Health) RegisterCheckFunc(name string, checkFn CheckFn) error {
	check := defaultCheckOpts
	check.Name = name
	check.CheckFn = checkFn
	return h.RegisterCheck(check)
}

// RegisterCheck adds the given Check
func (h *Health) RegisterCheck(c Check) error {
	return h.health.RegisterCheck(&health.Config{
		InitialDelay:     c.InitialDelay,
		ExecutionPeriod:  c.ExecutionPeriod,
		InitiallyPassing: c.InitiallyPassing,
		Check:            gosundheitCheck{c.Name, c.CheckFn},
	})
}

// GetLivenessArgs are the arguments for GetLiveness
type GetLivenessArgs struct{}

// GetLivenessReply is the response for GetLiveness
type GetLivenessReply struct {
	Checks  map[string]health.Result `json:"checks"`
	Healthy bool                     `json:"healthy"`
}

// GetLiveness returns a summation of the health of the node
func (h *Health) GetLiveness(_ *http.Request, _ *GetLivenessArgs, reply *GetLivenessReply) error {
	h.log.Info("Health: GetLiveness called")
	reply.Checks, reply.Healthy = h.health.Results()
	return nil
}
<commit_msg>return 503 rather than 500 when unhealthy<commit_after>// (c) 2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package health

import (
	"net/http"
	"time"

	health "github.com/AppsFlyer/go-sundheit"

	"github.com/gorilla/rpc/v2"

	"github.com/ava-labs/gecko/snow/engine/common"
	"github.com/ava-labs/gecko/utils/json"
	"github.com/ava-labs/gecko/utils/logging"
)

// defaultCheckOpts is a Check whose properties represent a default Check
var defaultCheckOpts = Check{ExecutionPeriod: time.Minute}

// Health observes a set of vital signs and makes them available through an HTTP
// API.
type Health struct {
	log    logging.Logger
	health health.Health
}

// NewService creates a new Health service
func NewService(log logging.Logger) *Health {
	return &Health{log, health.New()}
}

// Handler returns an HTTPHandler providing RPC access to the Health service
func (h *Health) Handler() *common.HTTPHandler {
	newServer := rpc.NewServer()
	codec := json.NewCodec()
	newServer.RegisterCodec(codec, "application/json")
	newServer.RegisterCodec(codec, "application/json;charset=UTF-8")
	newServer.RegisterService(h, "health")
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodGet { // GET request --> return 200 if getLiveness returns true, else 503
			if _, healthy := h.health.Results(); healthy {
				w.WriteHeader(http.StatusOK)
			} else {
				w.WriteHeader(http.StatusServiceUnavailable)
			}
		} else {
			newServer.ServeHTTP(w, r) // Other request --> use JSON RPC
		}
	})
	return &common.HTTPHandler{LockOptions: common.NoLock, Handler: handler}
}

// RegisterHeartbeat adds a check with default options and a CheckFn that checks
// the given heartbeater for a recent heartbeat
func (h *Health) RegisterHeartbeat(name string, hb Heartbeater, max time.Duration) error {
	return h.RegisterCheckFunc(name, HeartbeatCheckFn(hb, max))
}

// RegisterCheckFunc adds a Check with default options and the given CheckFn
func (h *Health) RegisterCheckFunc(name string, checkFn CheckFn) error {
	check := defaultCheckOpts
	check.Name = name
	check.CheckFn = checkFn
	return h.RegisterCheck(check)
}

// RegisterCheck adds the given Check
func (h *Health) RegisterCheck(c Check) error {
	return h.health.RegisterCheck(&health.Config{
		InitialDelay:     c.InitialDelay,
		ExecutionPeriod:  c.ExecutionPeriod,
		InitiallyPassing: c.InitiallyPassing,
		Check:            gosundheitCheck{c.Name, c.CheckFn},
	})
}

// GetLivenessArgs are the arguments for GetLiveness
type GetLivenessArgs struct{}

// GetLivenessReply is the response for GetLiveness
type GetLivenessReply struct {
	Checks  map[string]health.Result `json:"checks"`
	Healthy bool                     `json:"healthy"`
}

// GetLiveness returns a summation of the health of the node
func (h *Health) GetLiveness(_ *http.Request, _ *GetLivenessArgs, reply *GetLivenessReply) error {
	h.log.Info("Health: GetLiveness called")
	reply.Checks, reply.Healthy = h.health.Results()
	return nil
}
<|endoftext|>