<commit_before>package world

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"path"
	"strconv"
	"time"

	"github.com/cloudfoundry-incubator/inigo/fake_cc"
	wardenrunner "github.com/cloudfoundry-incubator/warden-linux/integration/runner"
	gorouterconfig "github.com/cloudfoundry/gorouter/config"
	"github.com/fraenkel/candiedyaml"
	"github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
)

type BuiltExecutables map[string]string
type BuiltCircuses map[string]string

const CircusFilename = "some-circus.zip"
const DockerCircusFilename = "docker-circus.zip"

type BuiltArtifacts struct {
	Executables  BuiltExecutables
	Circuses     BuiltCircuses
	DockerCircus string
}

type ComponentAddresses struct {
	NATS           string
	Etcd           string
	EtcdPeer       string
	LoggregatorIn  string
	LoggregatorOut string
	Executor       string
	Rep            string
	FakeCC         string
	FileServer     string
	Router         string
	TPS            string
	WardenLinux    string
}

type ComponentMaker struct {
	Artifacts BuiltArtifacts
	Addresses ComponentAddresses

	ExternalAddress string

	Stack string

	WardenBinPath    string
	WardenRootFSPath string
	WardenGraphPath  string
}

type LoggregatorConfig struct {
	LegacyIncomingMessagesPort int
	OutgoingPort               int
	WSMessageBufferSize        int
	MaxRetainedLogMessages     int
	SharedSecret               string

	NatsHost string
	NatsPort int
}

func (maker ComponentMaker) NATS(argv ...string) ifrit.Runner {
	host, port, err := net.SplitHostPort(maker.Addresses.NATS)
	Ω(err).ShouldNot(HaveOccurred())

	return &ginkgomon.Runner{
		Name:              "gnatsd",
		AnsiColorCode:     "30m",
		StartCheck:        "gnatsd is ready",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			"gnatsd",
			append([]string{
				"--addr", host,
				"--port", port,
			}, argv...)...,
		),
	}
}

func (maker ComponentMaker) Etcd(argv ...string) ifrit.Runner {
	nodeName := fmt.Sprintf("etcd_%d", ginkgo.GinkgoParallelNode())
	dataDir := path.Join(os.TempDir(), nodeName)

	return &ginkgomon.Runner{
		Name:              "etcd",
		AnsiColorCode:     "31m",
		StartCheck:        "leader changed",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			"etcd",
			append([]string{
				"-data-dir", dataDir,
				"-addr", maker.Addresses.Etcd,
				"-peer-addr", maker.Addresses.EtcdPeer,
				"-name", nodeName,
			}, argv...)...,
		),
		Cleanup: func() {
			err := os.RemoveAll(dataDir)
			Ω(err).ShouldNot(HaveOccurred())
		},
	}
}

func (maker ComponentMaker) WardenLinux(argv ...string) *wardenrunner.Runner {
	return wardenrunner.New(
		"tcp",
		maker.Addresses.WardenLinux,
		maker.Artifacts.Executables["warden-linux"],
		maker.WardenBinPath,
		maker.WardenRootFSPath,
		maker.WardenGraphPath,
		argv...,
	)
}

func (maker ComponentMaker) Executor(argv ...string) *ginkgomon.Runner {
	tmpPath := path.Join(os.TempDir(), fmt.Sprintf("executor_%d", ginkgo.GinkgoParallelNode()))
	cachePath := path.Join(tmpPath, "cache")

	return &ginkgomon.Runner{
		Name:          "executor",
		AnsiColorCode: "91m",
		StartCheck:    "executor.started",
		// executor may destroy containers on start, which can take a bit
		StartCheckTimeout: 30 * time.Second,
		BufferChan:        make(chan *gbytes.Buffer),
		Command: exec.Command(
			maker.Artifacts.Executables["exec"],
			append([]string{
				"-listenAddr", maker.Addresses.Executor,
				"-wardenNetwork", "tcp",
				"-wardenAddr", maker.Addresses.WardenLinux,
				"-loggregatorServer", maker.Addresses.LoggregatorIn,
				"-loggregatorSecret", "loggregator-secret",
				"-containerMaxCpuShares", "1024",
				"-cachePath", cachePath,
				"-tempDir", tmpPath,
			}, argv...)...,
		),
	}
}

func (maker ComponentMaker) Rep(argv ...string) ifrit.Runner {
	return &ginkgomon.Runner{
		Name:          "rep",
		AnsiColorCode: "92m",
		StartCheck:    "rep.started",
		// rep is not started until it can ping an executor; executor can take a
		// bit to start, so account for it
		StartCheckTimeout: 30 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["rep"],
			append(
				[]string{
					"-stack", maker.Stack,
					"-lrpHost", maker.ExternalAddress,
					"-listenAddr", maker.Addresses.Rep,
					"-etcdCluster", "http://" + maker.Addresses.Etcd,
					"-natsAddresses", maker.Addresses.NATS,
					"-executorID", "the-executor-id-" + strconv.Itoa(ginkgo.GinkgoParallelNode()),
					"-executorURL", "http://" + maker.Addresses.Executor,
					"-heartbeatInterval", "1s",
				},
				argv...,
			)...,
		),
	}
}

func (maker ComponentMaker) Converger(argv ...string) ifrit.Runner {
	return &ginkgomon.Runner{
		Name:              "converger",
		AnsiColorCode:     "93m",
		StartCheck:        "converger.started",
		StartCheckTimeout: 5 * time.Second,

		Command: exec.Command(
			maker.Artifacts.Executables["converger"],
			append([]string{
				"-etcdCluster", "http://" + maker.Addresses.Etcd,
			}, argv...)...,
		),
	}
}

func (maker ComponentMaker) Auctioneer(argv ...string) ifrit.Runner {
	return &ginkgomon.Runner{
		Name:              "auctioneer",
		AnsiColorCode:     "94m",
		StartCheck:        "auctioneer.started",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["auctioneer"],
			append([]string{
				"-etcdCluster", "http://" + maker.Addresses.Etcd,
				"-natsAddresses", maker.Addresses.NATS,

				// inigo runs everything on the same machine, so there will be more
				// load; this timeout is a bit sensitive to that.
				"-natsAuctionTimeout", "5s",

				// we limit this to prevent overwhelming numbers of auctioneer logs.  it
				// should not impact the behavior of the tests.
				"-maxRounds", "3",
			}, argv...)...,
		),
	}
}

func (maker ComponentMaker) RouteEmitter(argv ...string) ifrit.Runner {
	return &ginkgomon.Runner{
		Name:              "route-emitter",
		AnsiColorCode:     "95m",
		StartCheck:        "route-emitter.started",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["route-emitter"],
			append([]string{
				"-etcdCluster", "http://" + maker.Addresses.Etcd,
				"-natsAddresses", maker.Addresses.NATS,
			}, argv...)...,
		),
	}
}

func (maker ComponentMaker) TPS(argv ...string) ifrit.Runner {
	return &ginkgomon.Runner{
		Name:              "tps",
		AnsiColorCode:     "96m",
		StartCheck:        "tps.started",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["tps"],
			append([]string{
				"-etcdCluster", "http://" + maker.Addresses.Etcd,
				"-natsAddresses", maker.Addresses.NATS,
				"-listenAddr", maker.Addresses.TPS,
			}, argv...)...,
		),
	}
}

func (maker ComponentMaker) NsyncListener(argv ...string) ifrit.Runner {
	return &ginkgomon.Runner{
		Name:              "nsync-listener",
		AnsiColorCode:     "97m",
		StartCheck:        "nsync.listener.started",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["nsync-listener"],
			append([]string{
				"-etcdCluster", "http://" + maker.Addresses.Etcd,
				"-natsAddresses", maker.Addresses.NATS,
				"-repAddrRelativeToExecutor", maker.Addresses.Rep,
				"-circuses", fmt.Sprintf(`{"%s": "%s"}`, maker.Stack, CircusFilename),
				"-dockerCircusPath", DockerCircusFilename,
			}, argv...)...,
		),
	}
}

func (maker ComponentMaker) FileServer(argv ...string) (ifrit.Runner, string) {
	servedFilesDir, err := ioutil.TempDir("", "file-server-files")
	Ω(err).ShouldNot(HaveOccurred())

	host, port, err := net.SplitHostPort(maker.Addresses.FileServer)
	Ω(err).ShouldNot(HaveOccurred())

	return &ginkgomon.Runner{
		Name:              "file-server",
		AnsiColorCode:     "90m",
		StartCheck:        "file-server.ready",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["file-server"],
			append([]string{
				"-address", host,
				"-port", port,
				"-etcdCluster", "http://" + maker.Addresses.Etcd,
				"-ccAddress", "http://" + maker.Addresses.FakeCC,
				"-ccJobPollingInterval", "100ms",
				"-ccUsername", fake_cc.CC_USERNAME,
				"-ccPassword", fake_cc.CC_PASSWORD,
				"-staticDirectory", servedFilesDir,
			}, argv...)...,
		),
		Cleanup: func() {
			err := os.RemoveAll(servedFilesDir)
			Ω(err).ShouldNot(HaveOccurred())
		},
	}, servedFilesDir
}

func (maker ComponentMaker) Router() ifrit.Runner {
	_, routerPort, err := net.SplitHostPort(maker.Addresses.Router)
	Ω(err).ShouldNot(HaveOccurred())

	routerPortInt, err := strconv.Atoi(routerPort)
	Ω(err).ShouldNot(HaveOccurred())

	natsHost, natsPort, err := net.SplitHostPort(maker.Addresses.NATS)
	Ω(err).ShouldNot(HaveOccurred())

	natsPortInt, err := strconv.Atoi(natsPort)
	Ω(err).ShouldNot(HaveOccurred())

	routerConfig := &gorouterconfig.Config{
		Port: uint16(routerPortInt),

		PruneStaleDropletsIntervalInSeconds: 5,
		DropletStaleThresholdInSeconds:      10,
		PublishActiveAppsIntervalInSeconds:  0,
		StartResponseDelayIntervalInSeconds: 1,

		Nats: []gorouterconfig.NatsConfig{
			{
				Host: natsHost,
				Port: uint16(natsPortInt),
			},
		},
		Logging: gorouterconfig.LoggingConfig{
			File:  "/dev/stdout",
			Level: "info",
		},
	}

	configFile, err := ioutil.TempFile(os.TempDir(), "router-config")
	Ω(err).ShouldNot(HaveOccurred())

	defer configFile.Close()

	err = candiedyaml.NewEncoder(configFile).Encode(routerConfig)
	Ω(err).ShouldNot(HaveOccurred())

	return &ginkgomon.Runner{
		Name:              "router",
		AnsiColorCode:     "32m",
		StartCheck:        "router.started",
		StartCheckTimeout: 5 * time.Second, // it waits 1 second before listening. yep.
		Command: exec.Command(
			maker.Artifacts.Executables["router"],
			"-c", configFile.Name(),
		),
		Cleanup: func() {
			err := os.Remove(configFile.Name())
			Ω(err).ShouldNot(HaveOccurred())
		},
	}
}

func (maker ComponentMaker) Loggregator() ifrit.Runner {
	_, inPort, err := net.SplitHostPort(maker.Addresses.LoggregatorIn)
	Ω(err).ShouldNot(HaveOccurred())

	_, outPort, err := net.SplitHostPort(maker.Addresses.LoggregatorOut)
	Ω(err).ShouldNot(HaveOccurred())

	inPortInt, err := strconv.Atoi(inPort)
	Ω(err).ShouldNot(HaveOccurred())

	outPortInt, err := strconv.Atoi(outPort)
	Ω(err).ShouldNot(HaveOccurred())

	natsHost, natsPort, err := net.SplitHostPort(maker.Addresses.NATS)
	Ω(err).ShouldNot(HaveOccurred())

	natsPortInt, err := strconv.Atoi(natsPort)
	Ω(err).ShouldNot(HaveOccurred())

	loggregatorConfig := LoggregatorConfig{
		LegacyIncomingMessagesPort: inPortInt,
		OutgoingPort:               outPortInt,
		MaxRetainedLogMessages:     1000,
		WSMessageBufferSize:        100,
		SharedSecret:               "loggregator-secret",
		NatsHost:                   natsHost,
		NatsPort:                   natsPortInt,
	}

	configFile, err := ioutil.TempFile(os.TempDir(), "loggregator-config")
	Ω(err).ShouldNot(HaveOccurred())

	defer configFile.Close()

	err = json.NewEncoder(configFile).Encode(loggregatorConfig)
	Ω(err).ShouldNot(HaveOccurred())

	return &ginkgomon.Runner{
		Name:              "loggregator",
		AnsiColorCode:     "33m",
		StartCheck:        "Listening on port",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["loggregator"],
			"-config", configFile.Name(),
		),
		Cleanup: func() {
			err := os.Remove(configFile.Name())
			Ω(err).ShouldNot(HaveOccurred())
		},
	}
}

func (maker ComponentMaker) FakeCC() *fake_cc.FakeCC {
	return fake_cc.New(maker.Addresses.FakeCC)
}

func (maker ComponentMaker) Stager(argv ...string) ifrit.Runner {
	return &ginkgomon.Runner{
		Name:              "stager",
		AnsiColorCode:     "94m",
		StartCheck:        "Listening for staging requests!",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["stager"],
			append([]string{
				"-etcdCluster", "http://" + maker.Addresses.Etcd,
				"-natsAddresses", maker.Addresses.NATS,
				"-circuses", fmt.Sprintf(`{"%s": "%s"}`, maker.Stack, CircusFilename),
			}, argv...)...,
		),
	}
}
<commit_msg>default converger hearbeat interval to 1s<commit_after>package world

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"path"
	"strconv"
	"time"

	"github.com/cloudfoundry-incubator/inigo/fake_cc"
	wardenrunner "github.com/cloudfoundry-incubator/warden-linux/integration/runner"
	gorouterconfig "github.com/cloudfoundry/gorouter/config"
	"github.com/fraenkel/candiedyaml"
	"github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
)

type BuiltExecutables map[string]string
type BuiltCircuses map[string]string

const CircusFilename = "some-circus.zip"
const DockerCircusFilename = "docker-circus.zip"

type BuiltArtifacts struct {
	Executables  BuiltExecutables
	Circuses     BuiltCircuses
	DockerCircus string
}

type ComponentAddresses struct {
	NATS           string
	Etcd           string
	EtcdPeer       string
	LoggregatorIn  string
	LoggregatorOut string
	Executor       string
	Rep            string
	FakeCC         string
	FileServer     string
	Router         string
	TPS            string
	WardenLinux    string
}

type ComponentMaker struct {
	Artifacts BuiltArtifacts
	Addresses ComponentAddresses

	ExternalAddress string

	Stack string

	WardenBinPath    string
	WardenRootFSPath string
	WardenGraphPath  string
}

type LoggregatorConfig struct {
	LegacyIncomingMessagesPort int
	OutgoingPort               int
	WSMessageBufferSize        int
	MaxRetainedLogMessages     int
	SharedSecret               string

	NatsHost string
	NatsPort int
}

func (maker ComponentMaker) NATS(argv ...string) ifrit.Runner {
	host, port, err := net.SplitHostPort(maker.Addresses.NATS)
	Ω(err).ShouldNot(HaveOccurred())

	return &ginkgomon.Runner{
		Name:              "gnatsd",
		AnsiColorCode:     "30m",
		StartCheck:        "gnatsd is ready",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			"gnatsd",
			append([]string{
				"--addr", host,
				"--port", port,
			}, argv...)...,
		),
	}
}

func (maker ComponentMaker) Etcd(argv ...string) ifrit.Runner {
	nodeName := fmt.Sprintf("etcd_%d", ginkgo.GinkgoParallelNode())
	dataDir := path.Join(os.TempDir(), nodeName)

	return &ginkgomon.Runner{
		Name:              "etcd",
		AnsiColorCode:     "31m",
		StartCheck:        "leader changed",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			"etcd",
			append([]string{
				"-data-dir", dataDir,
				"-addr", maker.Addresses.Etcd,
				"-peer-addr", maker.Addresses.EtcdPeer,
				"-name", nodeName,
			}, argv...)...,
		),
		Cleanup: func() {
			err := os.RemoveAll(dataDir)
			Ω(err).ShouldNot(HaveOccurred())
		},
	}
}

func (maker ComponentMaker) WardenLinux(argv ...string) *wardenrunner.Runner {
	return wardenrunner.New(
		"tcp",
		maker.Addresses.WardenLinux,
		maker.Artifacts.Executables["warden-linux"],
		maker.WardenBinPath,
		maker.WardenRootFSPath,
		maker.WardenGraphPath,
		argv...,
	)
}

func (maker ComponentMaker) Executor(argv ...string) *ginkgomon.Runner {
	tmpPath := path.Join(os.TempDir(), fmt.Sprintf("executor_%d", ginkgo.GinkgoParallelNode()))
	cachePath := path.Join(tmpPath, "cache")

	return &ginkgomon.Runner{
		Name:          "executor",
		AnsiColorCode: "91m",
		StartCheck:    "executor.started",
		// executor may destroy containers on start, which can take a bit
		StartCheckTimeout: 30 * time.Second,
		BufferChan:        make(chan *gbytes.Buffer),
		Command: exec.Command(
			maker.Artifacts.Executables["exec"],
			append([]string{
				"-listenAddr", maker.Addresses.Executor,
				"-wardenNetwork", "tcp",
				"-wardenAddr", maker.Addresses.WardenLinux,
				"-loggregatorServer", maker.Addresses.LoggregatorIn,
				"-loggregatorSecret", "loggregator-secret",
				"-containerMaxCpuShares", "1024",
				"-cachePath", cachePath,
				"-tempDir", tmpPath,
			}, argv...)...,
		),
	}
}

func (maker ComponentMaker) Rep(argv ...string) ifrit.Runner {
	return &ginkgomon.Runner{
		Name:          "rep",
		AnsiColorCode: "92m",
		StartCheck:    "rep.started",
		// rep is not started until it can ping an executor; executor can take a
		// bit to start, so account for it
		StartCheckTimeout: 30 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["rep"],
			append(
				[]string{
					"-stack", maker.Stack,
					"-lrpHost", maker.ExternalAddress,
					"-listenAddr", maker.Addresses.Rep,
					"-etcdCluster", "http://" + maker.Addresses.Etcd,
					"-natsAddresses", maker.Addresses.NATS,
					"-executorID", "the-executor-id-" + strconv.Itoa(ginkgo.GinkgoParallelNode()),
					"-executorURL", "http://" + maker.Addresses.Executor,
					"-heartbeatInterval", "1s",
				},
				argv...,
			)...,
		),
	}
}

func (maker ComponentMaker) Converger(argv ...string) ifrit.Runner {
	return &ginkgomon.Runner{
		Name:              "converger",
		AnsiColorCode:     "93m",
		StartCheck:        "converger.started",
		StartCheckTimeout: 5 * time.Second,

		Command: exec.Command(
			maker.Artifacts.Executables["converger"],
			append([]string{
				"-etcdCluster", "http://" + maker.Addresses.Etcd,
				"-heartbeatInterval", "1s",
			}, argv...)...,
		),
	}
}

func (maker ComponentMaker) Auctioneer(argv ...string) ifrit.Runner {
	return &ginkgomon.Runner{
		Name:              "auctioneer",
		AnsiColorCode:     "94m",
		StartCheck:        "auctioneer.started",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["auctioneer"],
			append([]string{
				"-etcdCluster", "http://" + maker.Addresses.Etcd,
				"-natsAddresses", maker.Addresses.NATS,

				// inigo runs everything on the same machine, so there will be more
				// load; this timeout is a bit sensitive to that.
				"-natsAuctionTimeout", "5s",

				// we limit this to prevent overwhelming numbers of auctioneer logs.  it
				// should not impact the behavior of the tests.
				"-maxRounds", "3",
			}, argv...)...,
		),
	}
}

func (maker ComponentMaker) RouteEmitter(argv ...string) ifrit.Runner {
	return &ginkgomon.Runner{
		Name:              "route-emitter",
		AnsiColorCode:     "95m",
		StartCheck:        "route-emitter.started",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["route-emitter"],
			append([]string{
				"-etcdCluster", "http://" + maker.Addresses.Etcd,
				"-natsAddresses", maker.Addresses.NATS,
			}, argv...)...,
		),
	}
}

func (maker ComponentMaker) TPS(argv ...string) ifrit.Runner {
	return &ginkgomon.Runner{
		Name:              "tps",
		AnsiColorCode:     "96m",
		StartCheck:        "tps.started",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["tps"],
			append([]string{
				"-etcdCluster", "http://" + maker.Addresses.Etcd,
				"-natsAddresses", maker.Addresses.NATS,
				"-listenAddr", maker.Addresses.TPS,
			}, argv...)...,
		),
	}
}

func (maker ComponentMaker) NsyncListener(argv ...string) ifrit.Runner {
	return &ginkgomon.Runner{
		Name:              "nsync-listener",
		AnsiColorCode:     "97m",
		StartCheck:        "nsync.listener.started",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["nsync-listener"],
			append([]string{
				"-etcdCluster", "http://" + maker.Addresses.Etcd,
				"-natsAddresses", maker.Addresses.NATS,
				"-repAddrRelativeToExecutor", maker.Addresses.Rep,
				"-circuses", fmt.Sprintf(`{"%s": "%s"}`, maker.Stack, CircusFilename),
				"-dockerCircusPath", DockerCircusFilename,
			}, argv...)...,
		),
	}
}

func (maker ComponentMaker) FileServer(argv ...string) (ifrit.Runner, string) {
	servedFilesDir, err := ioutil.TempDir("", "file-server-files")
	Ω(err).ShouldNot(HaveOccurred())

	host, port, err := net.SplitHostPort(maker.Addresses.FileServer)
	Ω(err).ShouldNot(HaveOccurred())

	return &ginkgomon.Runner{
		Name:              "file-server",
		AnsiColorCode:     "90m",
		StartCheck:        "file-server.ready",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["file-server"],
			append([]string{
				"-address", host,
				"-port", port,
				"-etcdCluster", "http://" + maker.Addresses.Etcd,
				"-ccAddress", "http://" + maker.Addresses.FakeCC,
				"-ccJobPollingInterval", "100ms",
				"-ccUsername", fake_cc.CC_USERNAME,
				"-ccPassword", fake_cc.CC_PASSWORD,
				"-staticDirectory", servedFilesDir,
			}, argv...)...,
		),
		Cleanup: func() {
			err := os.RemoveAll(servedFilesDir)
			Ω(err).ShouldNot(HaveOccurred())
		},
	}, servedFilesDir
}

func (maker ComponentMaker) Router() ifrit.Runner {
	_, routerPort, err := net.SplitHostPort(maker.Addresses.Router)
	Ω(err).ShouldNot(HaveOccurred())

	routerPortInt, err := strconv.Atoi(routerPort)
	Ω(err).ShouldNot(HaveOccurred())

	natsHost, natsPort, err := net.SplitHostPort(maker.Addresses.NATS)
	Ω(err).ShouldNot(HaveOccurred())

	natsPortInt, err := strconv.Atoi(natsPort)
	Ω(err).ShouldNot(HaveOccurred())

	routerConfig := &gorouterconfig.Config{
		Port: uint16(routerPortInt),

		PruneStaleDropletsIntervalInSeconds: 5,
		DropletStaleThresholdInSeconds:      10,
		PublishActiveAppsIntervalInSeconds:  0,
		StartResponseDelayIntervalInSeconds: 1,

		Nats: []gorouterconfig.NatsConfig{
			{
				Host: natsHost,
				Port: uint16(natsPortInt),
			},
		},
		Logging: gorouterconfig.LoggingConfig{
			File:  "/dev/stdout",
			Level: "info",
		},
	}

	configFile, err := ioutil.TempFile(os.TempDir(), "router-config")
	Ω(err).ShouldNot(HaveOccurred())

	defer configFile.Close()

	err = candiedyaml.NewEncoder(configFile).Encode(routerConfig)
	Ω(err).ShouldNot(HaveOccurred())

	return &ginkgomon.Runner{
		Name:              "router",
		AnsiColorCode:     "32m",
		StartCheck:        "router.started",
		StartCheckTimeout: 5 * time.Second, // it waits 1 second before listening. yep.
		Command: exec.Command(
			maker.Artifacts.Executables["router"],
			"-c", configFile.Name(),
		),
		Cleanup: func() {
			err := os.Remove(configFile.Name())
			Ω(err).ShouldNot(HaveOccurred())
		},
	}
}

func (maker ComponentMaker) Loggregator() ifrit.Runner {
	_, inPort, err := net.SplitHostPort(maker.Addresses.LoggregatorIn)
	Ω(err).ShouldNot(HaveOccurred())

	_, outPort, err := net.SplitHostPort(maker.Addresses.LoggregatorOut)
	Ω(err).ShouldNot(HaveOccurred())

	inPortInt, err := strconv.Atoi(inPort)
	Ω(err).ShouldNot(HaveOccurred())

	outPortInt, err := strconv.Atoi(outPort)
	Ω(err).ShouldNot(HaveOccurred())

	natsHost, natsPort, err := net.SplitHostPort(maker.Addresses.NATS)
	Ω(err).ShouldNot(HaveOccurred())

	natsPortInt, err := strconv.Atoi(natsPort)
	Ω(err).ShouldNot(HaveOccurred())

	loggregatorConfig := LoggregatorConfig{
		LegacyIncomingMessagesPort: inPortInt,
		OutgoingPort:               outPortInt,
		MaxRetainedLogMessages:     1000,
		WSMessageBufferSize:        100,
		SharedSecret:               "loggregator-secret",
		NatsHost:                   natsHost,
		NatsPort:                   natsPortInt,
	}

	configFile, err := ioutil.TempFile(os.TempDir(), "loggregator-config")
	Ω(err).ShouldNot(HaveOccurred())

	defer configFile.Close()

	err = json.NewEncoder(configFile).Encode(loggregatorConfig)
	Ω(err).ShouldNot(HaveOccurred())

	return &ginkgomon.Runner{
		Name:              "loggregator",
		AnsiColorCode:     "33m",
		StartCheck:        "Listening on port",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["loggregator"],
			"-config", configFile.Name(),
		),
		Cleanup: func() {
			err := os.Remove(configFile.Name())
			Ω(err).ShouldNot(HaveOccurred())
		},
	}
}

func (maker ComponentMaker) FakeCC() *fake_cc.FakeCC {
	return fake_cc.New(maker.Addresses.FakeCC)
}

func (maker ComponentMaker) Stager(argv ...string) ifrit.Runner {
	return &ginkgomon.Runner{
		Name:              "stager",
		AnsiColorCode:     "94m",
		StartCheck:        "Listening for staging requests!",
		StartCheckTimeout: 5 * time.Second,
		Command: exec.Command(
			maker.Artifacts.Executables["stager"],
			append([]string{
				"-etcdCluster", "http://" + maker.Addresses.Etcd,
				"-natsAddresses", maker.Addresses.NATS,
				"-circuses", fmt.Sprintf(`{"%s": "%s"}`, maker.Stack, CircusFilename),
			}, argv...)...,
		),
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

const (
	// DefaultHeight is the default height of an Image
	DefaultHeight = 500
	// DefaultWidth is the default width of an Image
	DefaultWidth = 500
)

var (
	Black = NewColor(0, 0, 0)
	White = NewColor(255, 255, 255)
)

type Color struct {
	r byte
	b byte
	g byte
}

func NewColor(r, g, b byte) Color {
	return Color{r, g, b}
}

// Image represents an image
type Image struct {
	frame  [][]Color
	height int
	width  int
}

// NewImage returns a new Image with the given height and width
func NewImage(height, width int) *Image {
	frame := make([][]Color, height)
	for i := 0; i < height; i++ {
		frame[i] = make([]Color, width)
	}
	image := &Image{
		frame:  frame,
		height: height,
		width:  width,
	}
	image.Fill(Black)
	return image
}

// DrawLines draws all lines onto the Image
func (image *Image) DrawLines(em *Matrix, c Color) error {
	if em.cols < 2 {
		return errors.New("2 or more points are required for drawing")
	}
	for i := 0; i < em.cols-1; i += 2 {
		p0 := em.GetColumn(i)
		p1 := em.GetColumn(i + 1)
		image.DrawLine(int(p0[0]), int(p0[1]), int(p1[0]), int(p1[1]), c)
	}
	return nil
}

// DrawPolygons draws all polygons onto the Image
func (image *Image) DrawPolygons(em *Matrix, c Color) error {
	if em.cols < 3 {
		return errors.New("3 or more points are required for drawing")
	}
	for i := 0; i < em.cols-2; i += 3 {
		p0 := em.GetColumn(i)
		p1 := em.GetColumn(i + 1)
		p2 := em.GetColumn(i + 2)
		if isVisible(p0, p1, p2) {
			image.DrawLine(int(p0[0]), int(p0[1]), int(p1[0]), int(p1[1]), c)
			image.DrawLine(int(p1[0]), int(p1[1]), int(p2[0]), int(p2[1]), c)
			image.DrawLine(int(p2[0]), int(p2[1]), int(p0[0]), int(p0[1]), c)
		}
	}
	return nil
}

// DrawLine draws a single line onto the Image
func (image *Image) DrawLine(x1, y1, x2, y2 int, c Color) {
	if x1 > x2 {
		x1, x2 = x2, x1
		y1, y2 = y2, y1
	}

	A := 2 * (y2 - y1)
	B := 2 * -(x2 - x1)
	m := float32(A) / float32(-B)
	if m >= 0 {
		if m <= 1 {
			image.drawOctant1(x1, y1, x2, y2, A, B, c)
		} else {
			image.drawOctant2(x1, y1, x2, y2, A, B, c)
		}
	} else {
		if m < -1 {
			image.drawOctant7(x1, y1, x2, y2, A, B, c)
		} else {
			image.drawOctant8(x1, y1, x2, y2, A, B, c)
		}
	}
}

func (image *Image) drawOctant1(x1, y1, x2, y2, A, B int, c Color) {
	d := A + B/2
	for x1 <= x2 {
		image.set(x1, y1, c)
		if d > 0 {
			y1++
			d += B
		}
		x1++
		d += A
	}
}

func (image *Image) drawOctant2(x1, y1, x2, y2, A, B int, c Color) {
	d := A/2 + B
	for y1 <= y2 {
		image.set(x1, y1, c)
		if d < 0 {
			x1++
			d += A
		}
		y1++
		d += B
	}
}

func (image *Image) drawOctant7(x1, y1, x2, y2, A, B int, c Color) {
	d := A/2 + B
	for y1 >= y2 {
		image.set(x1, y1, c)
		if d > 0 {
			x1++
			d += A
		}
		y1--
		d -= B
	}
}

func (image *Image) drawOctant8(x1, y1, x2, y2, A, B int, c Color) {
	d := A - B/2
	for x1 <= x2 {
		image.set(x1, y1, c)
		if d < 0 {
			y1--
			d -= B
		}
		x1++
		d += A
	}
}

// Fill completely fills the Image with a single color
func (image *Image) Fill(c Color) {
	for y := 0; y < image.height; y++ {
		for x := 0; x < image.width; x++ {
			image.set(x, y, c)
		}
	}
}

func (image *Image) set(x, y int, c Color) {
	if (x < 0 || x >= image.width) || (y < 0 || y >= image.height) {
		return
	}
	// Plot so that the y coodinate is the row, and the x coordinate is the column
	image.frame[y][x] = c
}

// SavePpm will save the Image as a ppm
func (image *Image) SavePpm(name string) error {
	f, err := os.Create(name)
	if err != nil {
		return err
	}
	defer f.Close()

	w := bufio.NewWriter(f)
	defer w.Flush()

	fmt.Fprintln(w, "P3", image.width, image.height, 255)
	for y := 0; y < image.height; y++ {
		// Adjust y coordinate that the origin is the bottom left
		adjustedY := image.height - y - 1
		for x := 0; x < image.width; x++ {
			color := image.frame[adjustedY][x]
			fmt.Fprintln(w, color.r, color.b, color.g)
		}
	}
	return nil
}

// Save will save an Image into a given format
func (image *Image) Save(name string) error {
	index := strings.Index(name, ".")
	extension := ".ppm"
	if index == -1 {
		extension = ".png"
	} else {
		extension = name[index:]
		name = name[:index]
	}

	if extension == ".ppm" {
		// save as ppm without converting
		err := image.SavePpm(fmt.Sprint(name, ".ppm"))
		return err
	}

	ppm := fmt.Sprint(name, "-tmp.ppm")
	err := image.SavePpm(ppm)
	if err != nil {
		return err
	}
	defer os.Remove(ppm)
	err = exec.Command("convert", ppm, fmt.Sprint(name, extension)).Run()
	return err
}

// Display displays the Image
func (image *Image) Display() error {
	filename := "tmp.ppm"
	err := image.SavePpm(filename)
	if err != nil {
		return err
	}
	defer os.Remove(filename)

	err = exec.Command("display", filename).Run()
	return err
}

// MakeAnimation converts individual frames to a gif
func MakeAnimation(basename string) error {
	path := fmt.Sprintf("%s/%s*", FramesDirectory, basename)
	gif := fmt.Sprintf("%s.gif", basename)
	err := exec.Command("convert", "-delay", "3", path, gif).Run()
	return err
}

func isVisible(p0, p1, p2 []float64) bool {
	a := []float64{p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]}
	b := []float64{p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]}
	normal := CrossProduct(a, b)
	return normal[2] > 0
}
<commit_msg>Delay int casts to coordinates<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

const (
	// DefaultHeight is the default height of an Image
	DefaultHeight = 500
	// DefaultWidth is the default width of an Image
	DefaultWidth = 500
)

var (
	Black = NewColor(0, 0, 0)
	White = NewColor(255, 255, 255)
)

type Color struct {
	r byte
	b byte
	g byte
}

func NewColor(r, g, b byte) Color {
	return Color{r, g, b}
}

// Image represents an image
type Image struct {
	frame  [][]Color
	height int
	width  int
}

// NewImage returns a new Image with the given height and width
func NewImage(height, width int) *Image {
	frame := make([][]Color, height)
	for i := 0; i < height; i++ {
		frame[i] = make([]Color, width)
	}
	image := &Image{
		frame:  frame,
		height: height,
		width:  width,
	}
	image.Fill(Black)
	return image
}

// DrawLines draws all lines onto the Image
func (image *Image) DrawLines(em *Matrix, c Color) error {
	if em.cols < 2 {
		return errors.New("2 or more points are required for drawing")
	}
	for i := 0; i < em.cols-1; i += 2 {
		p0 := em.GetColumn(i)
		p1 := em.GetColumn(i + 1)
		image.DrawLine(p0[0], p0[1], p1[0], p1[1], c)
	}
	return nil
}

// DrawPolygons draws all polygons onto the Image
func (image *Image) DrawPolygons(em *Matrix, c Color) error {
	if em.cols < 3 {
		return errors.New("3 or more points are required for drawing")
	}
	for i := 0; i < em.cols-2; i += 3 {
		p0 := em.GetColumn(i)
		p1 := em.GetColumn(i + 1)
		p2 := em.GetColumn(i + 2)
		if isVisible(p0, p1, p2) {
			image.DrawLine(p0[0], p0[1], p1[0], p1[1], c)
			image.DrawLine(p1[0], p1[1], p2[0], p2[1], c)
			image.DrawLine(p2[0], p2[1], p0[0], p0[1], c)
		}
	}
	return nil
}

// DrawLine draws a single line onto the Image
func (image *Image) DrawLine(x1, y1, x2, y2 float64, c Color) {
	if x1 > x2 {
		x1, x2 = x2, x1
		y1, y2 = y2, y1
	}

	A := 2 * (y2 - y1)
	B := 2 * -(x2 - x1)
	m := A / -B
	if m >= 0 {
		if m <= 1 {
			image.drawOctant1(x1, y1, x2, y2, A, B, c)
		} else {
			image.drawOctant2(x1, y1, x2, y2, A, B, c)
		}
	} else {
		if m < -1 {
			image.drawOctant7(x1, y1, x2, y2, A, B, c)
		} else {
			image.drawOctant8(x1, y1, x2, y2, A, B, c)
		}
	}
}

func (image *Image) drawOctant1(x1, y1, x2, y2, A, B float64, c Color) {
	d := A + B/2
	for x1 <= x2 {
		image.set(int(x1), int(y1), c)
		if d > 0 {
			y1++
			d += B
		}
		x1++
		d += A
	}
}

func (image *Image) drawOctant2(x1, y1, x2, y2, A, B float64, c Color) {
	d := A/2 + B
	for y1 <= y2 {
		image.set(int(x1), int(y1), c)
		if d < 0 {
			x1++
			d += A
		}
		y1++
		d += B
	}
}

func (image *Image) drawOctant7(x1, y1, x2, y2, A, B float64, c Color) {
	d := A/2 + B
	for y1 >= y2 {
		image.set(int(x1), int(y1), c)
		if d > 0 {
			x1++
			d += A
		}
		y1--
		d -= B
	}
}

func (image *Image) drawOctant8(x1, y1, x2, y2, A, B float64, c Color) {
	d := A - B/2
	for x1 <= x2 {
		image.set(int(x1), int(y1), c)
		if d < 0 {
			y1--
			d -= B
		}
		x1++
		d += A
	}
}

// Fill completely fills the Image with a single color
func (image *Image) Fill(c Color) {
	for y := 0; y < image.height; y++ {
		for x := 0; x < image.width; x++ {
			image.set(x, y, c)
		}
	}
}

func (image *Image) set(x, y int, c Color) {
	if (x < 0 || x >= image.width) || (y < 0 || y >= image.height) {
		return
	}
	// Plot so that the y coodinate is the row, and the x coordinate is the column
	image.frame[y][x] = c
}

// SavePpm will save the Image as a ppm
func (image *Image) SavePpm(name string) error {
	f, err := os.Create(name)
	if err != nil {
		return err
	}
	defer f.Close()

	w := bufio.NewWriter(f)
	defer w.Flush()

	fmt.Fprintln(w, "P3", image.width, image.height, 255)
	for y := 0; y < image.height; y++ {
		// Adjust y coordinate that the origin is the bottom left
		adjustedY := image.height - y - 1
		for x := 0; x < image.width; x++ {
			color := image.frame[adjustedY][x]
			fmt.Fprintln(w, color.r, color.b, color.g)
		}
	}
	return nil
}

// Save will save an Image into a given format
func (image *Image) Save(name string) error {
	index := strings.Index(name, ".")
	extension := ".ppm"
	if index == -1 {
		extension = ".png"
	} else {
		extension = name[index:]
		name = name[:index]
	}

	if extension == ".ppm" {
		// save as ppm without converting
		err := image.SavePpm(fmt.Sprint(name, ".ppm"))
		return err
	}

	ppm := fmt.Sprint(name, "-tmp.ppm")
	err := image.SavePpm(ppm)
	if err != nil {
		return err
	}
	defer os.Remove(ppm)
	err = exec.Command("convert", ppm, fmt.Sprint(name, extension)).Run()
	return err
}

// Display displays the Image
func (image *Image) Display() error {
	filename := "tmp.ppm"
	err := image.SavePpm(filename)
	if err != nil {
		return err
	}
	defer os.Remove(filename)

	err = exec.Command("display", filename).Run()
	return err
}

// MakeAnimation converts individual frames to a gif
func MakeAnimation(basename string) error {
	path := fmt.Sprintf("%s/%s*", FramesDirectory, basename)
	gif := fmt.Sprintf("%s.gif", basename)
	err := exec.Command("convert", "-delay", "3", path, gif).Run()
	return err
}

func isVisible(p0, p1, p2 []float64) bool {
	a := []float64{p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]}
	b := []float64{p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]}
	normal := CrossProduct(a, b)
	return normal[2] > 0
}
<|endoftext|>


<commit_before>package zego

import (
	"encoding/json"
	"fmt"
	"net/url"
)

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

type SingleUser struct {
	User *User `json:"user"`
}

type User struct {
	Id                    uint32         `json:"id,omitempty"`
	Url                   string         `json:"url,omitempty"`
	Name                  string         `json:"name,omitempty"`
	External_id           string         `json:"external_id,omitempty"`
	Alias                 string         `json:"alias,omitempty"`
	Created_at            string         `json:"created_at,omitempty"`
	Updated_at            string         `json:"updated_at,omitempty"`
	Active                bool           `json:"active,omitempty"`
	Verified              bool           `json:"verified,omitempty"`
	Shared                bool           `json:"shared,omitempty"`
	Shared_agent          bool           `json:"shared_agent,omitempty"`
	Locale                string         `json:"locale,omitempty"`
	Locale_id             uint32         `json:"locale_id,omitempty"`
	Time_zone             string         `json:"time_zone,omitempty"`
	Last_login_at         string         `json:"last_login_at,omitempty"`
	Email                 string         `json:"email,omitempty"`
	Phone                 string         `json:"phone,omitempty"`
	Signature             string         `json:"signature,omitempty"`
	Details               string         `json:"details,omitempty"`
	Notes                 string         `json:"notes,omitempty"`
	Organization_id       uint32         `json:"organization_id,omitempty"`
	Role                  string         `json:"role,omitempty"`
	Customer_role_id      uint32         `json:"custom_role_id,omitempty"`
	Moderator             bool           `json:"moderator,omitempty"`
	Ticket_restriction    string         `json:"ticket_restriction,omitempty"`
	Only_private_comments bool           `json:"only_private_comments,omitempty"`
	Tags                  []string       `json:"tags,omitempty"`
	Restricted_agent      bool           `json:"restricted_agent,omitempty"`
	Suspended             bool           `json:"suspended,omitempty"`
	Photo                 []*Users_Photo `json:"photo,omitempty"`
	User_fields           []*User_Field  `json:"user_fields,omitempty"`
}

type Users_Photo struct {
	Id          int    `json:"id"`
	Name        string `json:"name"`
	ContentUrl  string `json:"content_url"`
	ContentType string `json:"content_type"`
	Size        int    `json:"size"`
}

type User_Field struct {
	UserDecimal  float32 `json:"user_decimal"`
	UserDropdown string  `json:"user_dropdown"`
	UserDate     string  `json:"user_date"`
}

func parseUsers(resource *Resource) (*[]User, error) {
	users := &UserArray{}
	json.Unmarshal([]byte(resource.Raw), users)
	return &users.Users, nil
}

func (a Auth) ListUsers() (*[]User, error) {
	path := "/users.json"
	resource, err := api(a, "GET", path, "")
	if err != nil {
		return nil, err
	}

	return parseUsers(resource)
}

func (a Auth) ShowUser(user_id string) (*User, error) {
	UserStruct := &SingleUser{}

	path := "/users/" + user_id + ".json"
	resource, err := api(a, "GET", path, "")
	if err != nil {
		return nil, err
	}

	json.Unmarshal([]byte(resource.Raw), UserStruct)

	return UserStruct.User, nil
}

func (a Auth) CreateUser(user *User) (*User, error) {
	path := "/users.json"
	bytes, err := json.Marshal(SingleUser{user})
	if err != nil {
		return nil, err
	}
	resource, err := api(a, "POST", path, string(bytes))
	if err != nil {
		return nil, err
	}
	singleUser := &SingleUser{}
	json.Unmarshal([]byte(resource.Raw), singleUser)

	return singleUser.User, nil
}

func (a Auth) UpdateUser(user *User) (*User, error) {
	path := fmt.Sprintf("/users/%d.json", user.Id)
	bytes, err := json.Marshal(SingleUser{user})
	if err != nil {
		return nil, err
	}
	resource, err := api(a, "PUT", path, string(bytes))
	if err != nil {
		return nil, err
	}

	singleUser := &SingleUser{}
	json.Unmarshal([]byte(resource.Raw), singleUser)

	return singleUser.User, nil
}

func (a Auth) DeleteUser(user_id uint32) error {
	path := fmt.Sprintf("/users/%d.json", user_id)
	_, err := api(a, "DELETE", path, "")
	if err != nil {
		return err
	}
	return nil
}

func (a Auth) SearchUserByExternalId(external_id string) (*[]User, error) {
	data := url.Values{}
	data.Set("external_id", external_id)
	path := fmt.Sprintf("/users/search.json?%s", data.Encode())
	resource, err := api(a, "GET", path, "")
	if err != nil {
		return nil, err
	}

	return parseUsers(resource)
}

func (a Auth) ShowUserRelated(user_id string) (*Resource, error) {

	path := "/users/" + user_id + "/related.json"
	resource, err := api(a, "GET", path, "")
	if err != nil {
		return nil, err
	}

	return resource, nil

}

func (a Auth) ListCollaborators(ticket_id string) (*Resource, error) {

	path := "/tickets/" + ticket_id + "/collaborators.json"
	resource, err := api(a, "GET", path, "")
	if err != nil {
		return nil, err
	}

	return resource, nil

}
<commit_msg>set tags api<commit_after>package zego

import (
	"encoding/json"
	"fmt"
	"net/url"
)

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

type SingleUser struct {
	User *User `json:"user"`
}

type Tags struct {
	Tags []string `json:"tags"`
}

type User struct {
	Id                    uint32         `json:"id,omitempty"`
	Url                   string         `json:"url,omitempty"`
	Name                  string         `json:"name,omitempty"`
	External_id           string         `json:"external_id,omitempty"`
	Alias                 string         `json:"alias,omitempty"`
	Created_at            string         `json:"created_at,omitempty"`
	Updated_at            string         `json:"updated_at,omitempty"`
	Active                bool           `json:"active,omitempty"`
	Verified              bool           `json:"verified,omitempty"`
	Shared                bool           `json:"shared,omitempty"`
	Shared_agent          bool           `json:"shared_agent,omitempty"`
	Locale                string         `json:"locale,omitempty"`
	Locale_id             uint32         `json:"locale_id,omitempty"`
	Time_zone             string         `json:"time_zone,omitempty"`
	Last_login_at         string         `json:"last_login_at,omitempty"`
	Email                 string         `json:"email,omitempty"`
	Phone                 string         `json:"phone,omitempty"`
	Signature             string         `json:"signature,omitempty"`
	Details               string         `json:"details,omitempty"`
	Notes                 string         `json:"notes,omitempty"`
	Organization_id       uint32         `json:"organization_id,omitempty"`
	Role                  string         `json:"role,omitempty"`
	Customer_role_id      uint32         `json:"custom_role_id,omitempty"`
	Moderator             bool           `json:"moderator,omitempty"`
	Ticket_restriction    string         `json:"ticket_restriction,omitempty"`
	Only_private_comments bool           `json:"only_private_comments,omitempty"`
	Tags                  []string       `json:"tags,omitempty"`
	Restricted_agent      bool           `json:"restricted_agent,omitempty"`
	Suspended             bool           `json:"suspended,omitempty"`
	Photo                 []*Users_Photo `json:"photo,omitempty"`
	User_fields           []*User_Field  `json:"user_fields,omitempty"`
}

type Users_Photo struct {
	Id          int    `json:"id"`
	Name        string `json:"name"`
	ContentUrl  string `json:"content_url"`
	ContentType string `json:"content_type"`
	Size        int    `json:"size"`
}

type User_Field struct {
	UserDecimal  float32 `json:"user_decimal"`
	UserDropdown string  `json:"user_dropdown"`
	UserDate     string  `json:"user_date"`
}

func parseUsers(resource *Resource) (*[]User, error) {
	users := &UserArray{}
	json.Unmarshal([]byte(resource.Raw), users)
	return &users.Users, nil
}

func (a Auth) ListUsers() (*[]User, error) {
	path := "/users.json"
	resource, err := api(a, "GET", path, "")
	if err != nil {
		return nil, err
	}

	return parseUsers(resource)
}

func (a Auth) ShowUser(user_id string) (*User, error) {
	UserStruct := &SingleUser{}

	path := "/users/" + user_id + ".json"
	resource, err := api(a, "GET", path, "")
	if err != nil {
		return nil, err
	}

	json.Unmarshal([]byte(resource.Raw), UserStruct)

	return UserStruct.User, nil
}

func (a Auth) CreateUser(user *User) (*User, error) {
	path := "/users.json"
	bytes, err := json.Marshal(SingleUser{user})
	if err != nil {
		return nil, err
	}
	resource, err := api(a, "POST", path, string(bytes))
	if err != nil {
		return nil, err
	}
	singleUser := &SingleUser{}
	json.Unmarshal([]byte(resource.Raw), singleUser)

	return singleUser.User, nil
}

func (a Auth) UpdateUser(user *User) (*User, error) {
	path := fmt.Sprintf("/users/%d.json", user.Id)
	bytes, err := json.Marshal(SingleUser{user})
	if err != nil {
		return nil, err
	}
	resource, err := api(a, "PUT", path, string(bytes))
	if err != nil {
		return nil, err
	}

	singleUser := &SingleUser{}
	json.Unmarshal([]byte(resource.Raw), singleUser)

	return singleUser.User, nil
}

func (a Auth) SetUserTags(user_id uint32, tags []string) (*[]string, error) {
	path := fmt.Sprintf("/users/%d/tags.json", user_id)
	bytes, err := json.Marshal(Tags{tags})
	if err != nil {
		return nil, err
	}
	resource, err := api(a, "POST", path, string(bytes))
	if err != nil {
		return nil, err
	}

	tagsResponse := &Tags{}
	json.Unmarshal([]byte(resource.Raw), tagsResponse)

	return &tagsResponse.Tags, nil
}

func (a Auth) DeleteUser(user_id uint32) error {
	path := fmt.Sprintf("/users/%d.json", user_id)
	_, err := api(a, "DELETE", path, "")
	if err != nil {
		return err
	}
	return nil
}

func (a Auth) SearchUserByExternalId(external_id string) (*[]User, error) {
	data := url.Values{}
	data.Set("external_id", external_id)
	path := fmt.Sprintf("/users/search.json?%s", data.Encode())
	resource, err := api(a, "GET", path, "")
	if err != nil {
		return nil, err
	}

	return parseUsers(resource)
}

func (a Auth) ShowUserRelated(user_id string) (*Resource, error) {

	path := "/users/" + user_id + "/related.json"
	resource, err := api(a, "GET", path, "")
	if err != nil {
		return nil, err
	}

	return resource, nil

}

func (a Auth) ListCollaborators(ticket_id string) (*Resource, error) {

	path := "/tickets/" + ticket_id + "/collaborators.json"
	resource, err := api(a, "GET", path, "")
	if err != nil {
		return nil, err
	}

	return resource, nil

}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"net/url"
	"reflect"
	"regexp"
	"strconv"
	"strings"

	"fmt"
	"io/ioutil"
	"net/textproto"

	"github.com/TykTechnologies/tyk/apidef"
	"github.com/TykTechnologies/tyk/user"
)

const (
	metaLabel    = "$tyk_meta."
	contextLabel = "$tyk_context."
)

var dollarMatch = regexp.MustCompile(`\$\d+`)
var contextMatch = regexp.MustCompile(`\$tyk_context.([A-Za-z0-9_\-\.]+)`)
var metaMatch = regexp.MustCompile(`\$tyk_meta.([A-Za-z0-9_\-\.]+)`)

func urlRewrite(meta *apidef.URLRewriteMeta, r *http.Request) (string, error) {
	path := r.URL.String()
	log.Debug("Inbound path: ", path)
	newpath := path

	if meta.MatchRegexp == nil {
		var err error
		meta.MatchRegexp, err = regexp.Compile(meta.MatchPattern)
		if err != nil {
			return path, fmt.Errorf("URLRewrite regexp error %s", meta.MatchPattern)
		}
	}

	// Check triggers
	rewriteToPath := meta.RewriteTo
	if len(meta.Triggers) > 0 {

		// This feature uses context, we must force it if it doesn't exist
		contextData := ctxGetData(r)
		if contextData == nil {
			contextDataObject := make(map[string]interface{})
			ctxSetData(r, contextDataObject)
		}

		for tn, triggerOpts := range meta.Triggers {
			checkAny := false
			setCount := 0
			if triggerOpts.On == apidef.Any {
				checkAny = true
			}

			// Check headers
			if len(triggerOpts.Options.HeaderMatches) > 0 {
				if checkHeaderTrigger(r, triggerOpts.Options.HeaderMatches, checkAny, tn) {
					setCount += 1
					if checkAny {
						rewriteToPath = triggerOpts.RewriteTo
						break
					}
				}
			}

			// Check query string
			if len(triggerOpts.Options.QueryValMatches) > 0 {
				if checkQueryString(r, triggerOpts.Options.QueryValMatches, checkAny, tn) {
					setCount += 1
					if checkAny {
						rewriteToPath = triggerOpts.RewriteTo
						break
					}
				}
			}

			// Check path parts
			if len(triggerOpts.Options.PathPartMatches) > 0 {
				if checkPathParts(r, triggerOpts.Options.PathPartMatches, checkAny, tn) {
					setCount += 1
					if checkAny {
						rewriteToPath = triggerOpts.RewriteTo
						break
					}
				}
			}

			// Check session meta

			if session := ctxGetSession(r); session != nil {
				if len(triggerOpts.Options.SessionMetaMatches) > 0 {
					if checkSessionTrigger(r, session, triggerOpts.Options.SessionMetaMatches, checkAny, tn) {
						setCount += 1
						if checkAny {
							rewriteToPath = triggerOpts.RewriteTo
							break
						}
					}
				}
			}

			// Check payload
			if triggerOpts.Options.PayloadMatches.MatchPattern != "" {
				if checkPayload(r, triggerOpts.Options.PayloadMatches, tn) {
					setCount += 1
					if checkAny {
						rewriteToPath = triggerOpts.RewriteTo
						break
					}
				}
			}

			if !checkAny {
				// Set total count:
				total := 0
				if len(triggerOpts.Options.HeaderMatches) > 0 {
					total += 1
				}
				if len(triggerOpts.Options.QueryValMatches) > 0 {
					total += 1
				}
				if len(triggerOpts.Options.PathPartMatches) > 0 {
					total += 1
				}
				if len(triggerOpts.Options.SessionMetaMatches) > 0 {
					total += 1
				}
				if triggerOpts.Options.PayloadMatches.MatchPattern != "" {
					total += 1
				}
				if total == setCount {
					rewriteToPath = triggerOpts.RewriteTo
				}
			}
		}
	}

	matchGroups := meta.MatchRegexp.FindAllStringSubmatch(path, -1)

	// Make sure it matches the string
	log.Debug("Rewriter checking matches, len is: ", len(matchGroups))
	if len(matchGroups) > 0 {
		newpath = rewriteToPath
		// get the indices for the replacements:
		dollarMatch := regexp.MustCompile(`\$\d+`) // Prepare our regex
		replaceGroups := dollarMatch.FindAllStringSubmatch(rewriteToPath, -1)

		log.Debug(matchGroups)
		log.Debug(replaceGroups)

		groupReplace := make(map[string]string)
		for mI, replacementVal := range matchGroups[0] {
			indexVal := "$" + strconv.Itoa(mI)
			groupReplace[indexVal] = replacementVal
		}

		for _, v := range replaceGroups {
			newpath = strings.Replace(newpath, v[0], groupReplace[v[0]], -1)
		}

		log.Debug("URL Re-written from: ", path)
		log.Debug("URL Re-written to: ", newpath)

		// put url_rewrite path to context to be used in ResponseTransformMiddleware
		ctxSetUrlRewritePath(r, meta.Path)
	}

	newpath = replaceTykVariables(r, newpath, true)

	return newpath, nil
}

func replaceTykVariables(r *http.Request, in string, escape bool) string {
	if strings.Contains(in, contextLabel) {
		contextData := ctxGetData(r)

		replaceGroups := contextMatch.FindAllStringSubmatch(in, -1)
		for _, v := range replaceGroups {
			contextKey := strings.Replace(v[0], "$tyk_context.", "", 1)

			if val, ok := contextData[contextKey]; ok {
				valStr := valToStr(val)
				// If contains url with domain
				if escape && !strings.HasPrefix(valStr, "http") {
					valStr = url.QueryEscape(valStr)
				}
				in = strings.Replace(in, v[0], valStr, -1)
			}
		}
	}

	if strings.Contains(in, metaLabel) {
		// Meta data from the token
		session := ctxGetSession(r)
		if session == nil {
			return in
		}

		replaceGroups := metaMatch.FindAllStringSubmatch(in, -1)
		for _, v := range replaceGroups {
			contextKey := strings.Replace(v[0], "$tyk_meta.", "", 1)

			val, ok := session.MetaData[contextKey]
			if ok {
				valStr := valToStr(val)
				// If contains url with domain
				if escape && !strings.HasPrefix(valStr, "http") {
					valStr = url.QueryEscape(valStr)
				}
				in = strings.Replace(in, v[0], valStr, -1)
			}
		}
	}

	return in
}

func valToStr(v interface{}) string {
	s := ""
	switch x := v.(type) {
	case string:
		s = x
	case float64:
		s = strconv.FormatFloat(x, 'f', -1, 32)
	case int64:
		s = strconv.FormatInt(x, 10)
	case []string:
		s = strings.Join(x, ",")
		// Remove empty start
		s = strings.TrimPrefix(s, ",")
	case url.Values:
		i := 0
		for key, v := range x {
			s += key + ":" + strings.Join(v, ",")
			if i < len(x)-1 {
				s += ";"
			}
			i++
		}
	default:
		log.Error("Context variable type is not supported: ", reflect.TypeOf(v))
	}
	return s
}

// URLRewriteMiddleware Will rewrite an inbund URL to a matching outbound one, it can also handle dynamic variable substitution
type URLRewriteMiddleware struct {
	BaseMiddleware
}

func (m *URLRewriteMiddleware) Name() string {
	return "URLRewriteMiddleware"
}

func (m *URLRewriteMiddleware) InitTriggerRx() {
	// Generate regexp for each special match parameter
	for verKey := range m.Spec.VersionData.Versions {
		for pathKey := range m.Spec.VersionData.Versions[verKey].ExtendedPaths.URLRewrite {
			rewrite := m.Spec.VersionData.Versions[verKey].ExtendedPaths.URLRewrite[pathKey]

			for trKey := range rewrite.Triggers {
				tr := rewrite.Triggers[trKey]

				for key, h := range tr.Options.HeaderMatches {
					h.Init()
					tr.Options.HeaderMatches[key] = h
				}
				for key, q := range tr.Options.QueryValMatches {
					q.Init()
					tr.Options.QueryValMatches[key] = q
				}
				for key, h := range tr.Options.SessionMetaMatches {
					h.Init()
					tr.Options.SessionMetaMatches[key] = h
				}
				for key, h := range tr.Options.PathPartMatches {
					h.Init()
					tr.Options.PathPartMatches[key] = h
				}
				if tr.Options.PayloadMatches.MatchPattern != "" {
					tr.Options.PayloadMatches.Init()
				}

				rewrite.Triggers[trKey] = tr
			}

			m.Spec.VersionData.Versions[verKey].ExtendedPaths.URLRewrite[pathKey] = rewrite
		}
	}
}

func (m *URLRewriteMiddleware) EnabledForSpec() bool {
	for _, version := range m.Spec.VersionData.Versions {
		if len(version.ExtendedPaths.URLRewrite) > 0 {
			m.Spec.URLRewriteEnabled = true
			m.InitTriggerRx()
			return true
		}
	}
	return false
}

func (m *URLRewriteMiddleware) CheckHostRewrite(oldPath, newTarget string, r *http.Request) {
	oldAsURL, _ := url.Parse(oldPath)
	newAsURL, _ := url.Parse(newTarget)
	if oldAsURL.Host != newAsURL.Host {
		log.Debug("Detected a host rewrite in pattern!")
		setCtxValue(r, RetainHost, true)
	}
}

// ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail
func (m *URLRewriteMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	_, versionPaths, _, _ := m.Spec.Version(r)
	found, meta := m.Spec.CheckSpecMatchesStatus(r, versionPaths, URLRewrite)
	if !found {
		return nil, 200
	}

	log.Debug("Rewriter active")
	umeta := meta.(*apidef.URLRewriteMeta)
	log.Debug(r.URL)
	oldPath := r.URL.String()
	p, err := urlRewrite(umeta, r)
	if err != nil {
		log.Error(err)
		return err, 500
	}

	m.CheckHostRewrite(oldPath, p, r)

	newURL, err := url.Parse(p)
	if err != nil {
		log.Error("URL Rewrite failed, could not parse: ", p)
	} else {
		r.URL = newURL
	}
	return nil, 200
}

func checkHeaderTrigger(r *http.Request, options map[string]apidef.StringRegexMap, any bool, triggernum int) bool {
	contextData := ctxGetData(r)
	fCount := 0
	for mh, mr := range options {
		mhCN := textproto.CanonicalMIMEHeaderKey(mh)
		vals, ok := r.Header[mhCN]
		if ok {
			for i, v := range vals {
				b := mr.Check(v)
				if len(b) > 0 {
					kn := "trigger-" + strconv.Itoa(triggernum) + "-" + mhCN + "-" + strconv.Itoa(i)
					contextData[kn] = b
					fCount++
				}
			}
		}
	}

	if fCount > 0 {
		ctxSetData(r, contextData)
		if any {
			return true
		}

		return len(options) <= fCount
	}

	return false
}

func checkQueryString(r *http.Request, options map[string]apidef.StringRegexMap, any bool, triggernum int) bool {
	contextData := ctxGetData(r)
	fCount := 0
	for mv, mr := range options {
		qvals := r.URL.Query()
		vals, ok := qvals[mv]
		if ok {
			for i, v := range vals {
				b := mr.Check(v)
				if len(b) > 0 {
					kn := "trigger-" + strconv.Itoa(triggernum) + "-" + mv + "-" + strconv.Itoa(i)

					contextData[kn] = b
					fCount++
				}
			}
		}
	}

	if fCount > 0 {
		ctxSetData(r, contextData)
		if any {
			return true
		}

		return len(options) <= fCount
	}

	return false
}

func checkPathParts(r *http.Request, options map[string]apidef.StringRegexMap, any bool, triggernum int) bool {
	contextData := ctxGetData(r)
	fCount := 0
	for mv, mr := range options {
		pathParts := strings.Split(r.URL.Path, "/")

		for _, part := range pathParts {
			b := mr.Check(part)
			if len(b) > 0 {
				kn := "trigger-" + strconv.Itoa(triggernum) + "-" + mv + "-" + strconv.Itoa(fCount)

				contextData[kn] = b
				fCount++
			}
		}
	}

	if fCount > 0 {
		ctxSetData(r, contextData)
		if any {
			return true
		}

		return len(options) <= fCount
	}

	return false
}

func checkSessionTrigger(r *http.Request, sess *user.SessionState, options map[string]apidef.StringRegexMap, any bool, triggernum int) bool {
	contextData := ctxGetData(r)
	fCount := 0
	for mh, mr := range options {
		rawVal, ok := sess.MetaData[mh]
		if ok {
			val, valOk := rawVal.(string)
			if valOk {
				b := mr.Check(val)
				if len(b) > 0 {
					kn := "trigger-" + strconv.Itoa(triggernum) + "-" + mh

					contextData[kn] = b
					fCount++
				}
			}
		}
	}

	if fCount > 0 {
		ctxSetData(r, contextData)
		if any {
			return true
		}

		return len(options) <= fCount
	}

	return false
}

func checkPayload(r *http.Request, options apidef.StringRegexMap, triggernum int) bool {
	contextData := ctxGetData(r)
	cp := copyRequest(r)
	bodyBytes, _ := ioutil.ReadAll(cp.Body)

	b := options.Check(string(bodyBytes))
	if len(b) > 0 {
		kn := "trigger-" + strconv.Itoa(triggernum) + "-payload"

		contextData[kn] = string(b)
		return true
	}

	return false
}
<commit_msg>Remove already compiled expression from the URL rewriter code<commit_after>package main

import (
	"net/http"
	"net/url"
	"reflect"
	"regexp"
	"strconv"
	"strings"

	"fmt"
	"io/ioutil"
	"net/textproto"

	"github.com/TykTechnologies/tyk/apidef"
	"github.com/TykTechnologies/tyk/user"
)

const (
	metaLabel    = "$tyk_meta."
	contextLabel = "$tyk_context."
)

var dollarMatch = regexp.MustCompile(`\$\d+`)
var contextMatch = regexp.MustCompile(`\$tyk_context.([A-Za-z0-9_\-\.]+)`)
var metaMatch = regexp.MustCompile(`\$tyk_meta.([A-Za-z0-9_\-\.]+)`)

func urlRewrite(meta *apidef.URLRewriteMeta, r *http.Request) (string, error) {
	path := r.URL.String()
	log.Debug("Inbound path: ", path)
	newpath := path

	if meta.MatchRegexp == nil {
		var err error
		meta.MatchRegexp, err = regexp.Compile(meta.MatchPattern)
		if err != nil {
			return path, fmt.Errorf("URLRewrite regexp error %s", meta.MatchPattern)
		}
	}

	// Check triggers
	rewriteToPath := meta.RewriteTo
	if len(meta.Triggers) > 0 {

		// This feature uses context, we must force it if it doesn't exist
		contextData := ctxGetData(r)
		if contextData == nil {
			contextDataObject := make(map[string]interface{})
			ctxSetData(r, contextDataObject)
		}

		for tn, triggerOpts := range meta.Triggers {
			checkAny := false
			setCount := 0
			if triggerOpts.On == apidef.Any {
				checkAny = true
			}

			// Check headers
			if len(triggerOpts.Options.HeaderMatches) > 0 {
				if checkHeaderTrigger(r, triggerOpts.Options.HeaderMatches, checkAny, tn) {
					setCount += 1
					if checkAny {
						rewriteToPath = triggerOpts.RewriteTo
						break
					}
				}
			}

			// Check query string
			if len(triggerOpts.Options.QueryValMatches) > 0 {
				if checkQueryString(r, triggerOpts.Options.QueryValMatches, checkAny, tn) {
					setCount += 1
					if checkAny {
						rewriteToPath = triggerOpts.RewriteTo
						break
					}
				}
			}

			// Check path parts
			if len(triggerOpts.Options.PathPartMatches) > 0 {
				if checkPathParts(r, triggerOpts.Options.PathPartMatches, checkAny, tn) {
					setCount += 1
					if checkAny {
						rewriteToPath = triggerOpts.RewriteTo
						break
					}
				}
			}

			// Check session meta

			if session := ctxGetSession(r); session != nil {
				if len(triggerOpts.Options.SessionMetaMatches) > 0 {
					if checkSessionTrigger(r, session, triggerOpts.Options.SessionMetaMatches, checkAny, tn) {
						setCount += 1
						if checkAny {
							rewriteToPath = triggerOpts.RewriteTo
							break
						}
					}
				}
			}

			// Check payload
			if triggerOpts.Options.PayloadMatches.MatchPattern != "" {
				if checkPayload(r, triggerOpts.Options.PayloadMatches, tn) {
					setCount += 1
					if checkAny {
						rewriteToPath = triggerOpts.RewriteTo
						break
					}
				}
			}

			if !checkAny {
				// Set total count:
				total := 0
				if len(triggerOpts.Options.HeaderMatches) > 0 {
					total += 1
				}
				if len(triggerOpts.Options.QueryValMatches) > 0 {
					total += 1
				}
				if len(triggerOpts.Options.PathPartMatches) > 0 {
					total += 1
				}
				if len(triggerOpts.Options.SessionMetaMatches) > 0 {
					total += 1
				}
				if triggerOpts.Options.PayloadMatches.MatchPattern != "" {
					total += 1
				}
				if total == setCount {
					rewriteToPath = triggerOpts.RewriteTo
				}
			}
		}
	}

	matchGroups := meta.MatchRegexp.FindAllStringSubmatch(path, -1)

	// Make sure it matches the string
	log.Debug("Rewriter checking matches, len is: ", len(matchGroups))
	if len(matchGroups) > 0 {
		newpath = rewriteToPath
		// get the indices for the replacements:
		replaceGroups := dollarMatch.FindAllStringSubmatch(rewriteToPath, -1)

		log.Debug(matchGroups)
		log.Debug(replaceGroups)

		groupReplace := make(map[string]string)
		for mI, replacementVal := range matchGroups[0] {
			indexVal := "$" + strconv.Itoa(mI)
			groupReplace[indexVal] = replacementVal
		}

		for _, v := range replaceGroups {
			newpath = strings.Replace(newpath, v[0], groupReplace[v[0]], -1)
		}

		log.Debug("URL Re-written from: ", path)
		log.Debug("URL Re-written to: ", newpath)

		// put url_rewrite path to context to be used in ResponseTransformMiddleware
		ctxSetUrlRewritePath(r, meta.Path)
	}

	newpath = replaceTykVariables(r, newpath, true)

	return newpath, nil
}

func replaceTykVariables(r *http.Request, in string, escape bool) string {
	if strings.Contains(in, contextLabel) {
		contextData := ctxGetData(r)

		replaceGroups := contextMatch.FindAllStringSubmatch(in, -1)
		for _, v := range replaceGroups {
			contextKey := strings.Replace(v[0], "$tyk_context.", "", 1)

			if val, ok := contextData[contextKey]; ok {
				valStr := valToStr(val)
				// If contains url with domain
				if escape && !strings.HasPrefix(valStr, "http") {
					valStr = url.QueryEscape(valStr)
				}
				in = strings.Replace(in, v[0], valStr, -1)
			}
		}
	}

	if strings.Contains(in, metaLabel) {
		// Meta data from the token
		session := ctxGetSession(r)
		if session == nil {
			return in
		}

		replaceGroups := metaMatch.FindAllStringSubmatch(in, -1)
		for _, v := range replaceGroups {
			contextKey := strings.Replace(v[0], "$tyk_meta.", "", 1)

			val, ok := session.MetaData[contextKey]
			if ok {
				valStr := valToStr(val)
				// If contains url with domain
				if escape && !strings.HasPrefix(valStr, "http") {
					valStr = url.QueryEscape(valStr)
				}
				in = strings.Replace(in, v[0], valStr, -1)
			}
		}
	}

	return in
}

func valToStr(v interface{}) string {
	s := ""
	switch x := v.(type) {
	case string:
		s = x
	case float64:
		s = strconv.FormatFloat(x, 'f', -1, 32)
	case int64:
		s = strconv.FormatInt(x, 10)
	case []string:
		s = strings.Join(x, ",")
		// Remove empty start
		s = strings.TrimPrefix(s, ",")
	case url.Values:
		i := 0
		for key, v := range x {
			s += key + ":" + strings.Join(v, ",")
			if i < len(x)-1 {
				s += ";"
			}
			i++
		}
	default:
		log.Error("Context variable type is not supported: ", reflect.TypeOf(v))
	}
	return s
}

// URLRewriteMiddleware Will rewrite an inbund URL to a matching outbound one, it can also handle dynamic variable substitution
type URLRewriteMiddleware struct {
	BaseMiddleware
}

func (m *URLRewriteMiddleware) Name() string {
	return "URLRewriteMiddleware"
}

func (m *URLRewriteMiddleware) InitTriggerRx() {
	// Generate regexp for each special match parameter
	for verKey := range m.Spec.VersionData.Versions {
		for pathKey := range m.Spec.VersionData.Versions[verKey].ExtendedPaths.URLRewrite {
			rewrite := m.Spec.VersionData.Versions[verKey].ExtendedPaths.URLRewrite[pathKey]

			for trKey := range rewrite.Triggers {
				tr := rewrite.Triggers[trKey]

				for key, h := range tr.Options.HeaderMatches {
					h.Init()
					tr.Options.HeaderMatches[key] = h
				}
				for key, q := range tr.Options.QueryValMatches {
					q.Init()
					tr.Options.QueryValMatches[key] = q
				}
				for key, h := range tr.Options.SessionMetaMatches {
					h.Init()
					tr.Options.SessionMetaMatches[key] = h
				}
				for key, h := range tr.Options.PathPartMatches {
					h.Init()
					tr.Options.PathPartMatches[key] = h
				}
				if tr.Options.PayloadMatches.MatchPattern != "" {
					tr.Options.PayloadMatches.Init()
				}

				rewrite.Triggers[trKey] = tr
			}

			m.Spec.VersionData.Versions[verKey].ExtendedPaths.URLRewrite[pathKey] = rewrite
		}
	}
}

func (m *URLRewriteMiddleware) EnabledForSpec() bool {
	for _, version := range m.Spec.VersionData.Versions {
		if len(version.ExtendedPaths.URLRewrite) > 0 {
			m.Spec.URLRewriteEnabled = true
			m.InitTriggerRx()
			return true
		}
	}
	return false
}

func (m *URLRewriteMiddleware) CheckHostRewrite(oldPath, newTarget string, r *http.Request) {
	oldAsURL, _ := url.Parse(oldPath)
	newAsURL, _ := url.Parse(newTarget)
	if oldAsURL.Host != newAsURL.Host {
		log.Debug("Detected a host rewrite in pattern!")
		setCtxValue(r, RetainHost, true)
	}
}

// ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail
func (m *URLRewriteMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	_, versionPaths, _, _ := m.Spec.Version(r)
	found, meta := m.Spec.CheckSpecMatchesStatus(r, versionPaths, URLRewrite)
	if !found {
		return nil, 200
	}

	log.Debug("Rewriter active")
	umeta := meta.(*apidef.URLRewriteMeta)
	log.Debug(r.URL)
	oldPath := r.URL.String()
	p, err := urlRewrite(umeta, r)
	if err != nil {
		log.Error(err)
		return err, 500
	}

	m.CheckHostRewrite(oldPath, p, r)

	newURL, err := url.Parse(p)
	if err != nil {
		log.Error("URL Rewrite failed, could not parse: ", p)
	} else {
		r.URL = newURL
	}
	return nil, 200
}

func checkHeaderTrigger(r *http.Request, options map[string]apidef.StringRegexMap, any bool, triggernum int) bool {
	contextData := ctxGetData(r)
	fCount := 0
	for mh, mr := range options {
		mhCN := textproto.CanonicalMIMEHeaderKey(mh)
		vals, ok := r.Header[mhCN]
		if ok {
			for i, v := range vals {
				b := mr.Check(v)
				if len(b) > 0 {
					kn := "trigger-" + strconv.Itoa(triggernum) + "-" + mhCN + "-" + strconv.Itoa(i)
					contextData[kn] = b
					fCount++
				}
			}
		}
	}

	if fCount > 0 {
		ctxSetData(r, contextData)
		if any {
			return true
		}

		return len(options) <= fCount
	}

	return false
}

func checkQueryString(r *http.Request, options map[string]apidef.StringRegexMap, any bool, triggernum int) bool {
	contextData := ctxGetData(r)
	fCount := 0
	for mv, mr := range options {
		qvals := r.URL.Query()
		vals, ok := qvals[mv]
		if ok {
			for i, v := range vals {
				b := mr.Check(v)
				if len(b) > 0 {
					kn := "trigger-" + strconv.Itoa(triggernum) + "-" + mv + "-" + strconv.Itoa(i)

					contextData[kn] = b
					fCount++
				}
			}
		}
	}

	if fCount > 0 {
		ctxSetData(r, contextData)
		if any {
			return true
		}

		return len(options) <= fCount
	}

	return false
}

func checkPathParts(r *http.Request, options map[string]apidef.StringRegexMap, any bool, triggernum int) bool {
	contextData := ctxGetData(r)
	fCount := 0
	for mv, mr := range options {
		pathParts := strings.Split(r.URL.Path, "/")

		for _, part := range pathParts {
			b := mr.Check(part)
			if len(b) > 0 {
				kn := "trigger-" + strconv.Itoa(triggernum) + "-" + mv + "-" + strconv.Itoa(fCount)

				contextData[kn] = b
				fCount++
			}
		}
	}

	if fCount > 0 {
		ctxSetData(r, contextData)
		if any {
			return true
		}

		return len(options) <= fCount
	}

	return false
}

func checkSessionTrigger(r *http.Request, sess *user.SessionState, options map[string]apidef.StringRegexMap, any bool, triggernum int) bool {
	contextData := ctxGetData(r)
	fCount := 0
	for mh, mr := range options {
		rawVal, ok := sess.MetaData[mh]
		if ok {
			val, valOk := rawVal.(string)
			if valOk {
				b := mr.Check(val)
				if len(b) > 0 {
					kn := "trigger-" + strconv.Itoa(triggernum) + "-" + mh

					contextData[kn] = b
					fCount++
				}
			}
		}
	}

	if fCount > 0 {
		ctxSetData(r, contextData)
		if any {
			return true
		}

		return len(options) <= fCount
	}

	return false
}

func checkPayload(r *http.Request, options apidef.StringRegexMap, triggernum int) bool {
	contextData := ctxGetData(r)
	cp := copyRequest(r)
	bodyBytes, _ := ioutil.ReadAll(cp.Body)

	b := options.Check(string(bodyBytes))
	if len(b) > 0 {
		kn := "trigger-" + strconv.Itoa(triggernum) + "-payload"

		contextData[kn] = string(b)
		return true
	}

	return false
}
<|endoftext|>


<commit_before>package navigator

import (
	"fmt"
	"math/rand"
	"time"

	"github.com/lukevers/arp147/planet"
)

type Cell struct {
	X int64
	Y int64

	Planet     *planet.Planet
	Discovered bool
}

func NewCell(cell *Cell) *Cell {
	if cell == nil {
		cell = &Cell{
			X: randInt(1234567, 7654321),
			Y: randInt(1234567, 7654321),
		}

	}

	cell.initialize()
	return cell
}

func (c *Cell) GetX() string {
	return fmt.Sprintf("0x%X", c.X)
}

func (c *Cell) GetY() string {
	return fmt.Sprintf("0x%X", c.Y)
}

func (c *Cell) HudX() string {
	return fmt.Sprintf("X: %s", c.GetX())
}

func (c *Cell) HudY() string {
	return fmt.Sprintf("Y: %s", c.GetY())
}

func (c *Cell) initialize() {
	seed := time.Now().UTC().UnixNano()
	rand.Seed(seed)

	if randInt(0, 12)%12 == 0 {
		c.Planet = planet.New(planet.SizeViewer, planet.TypePlanet, true)
	}
}

func randInt(min, max int64) int64 {
	return min + rand.Int63n(max-min)
}
<commit_msg>Create a function of chance<commit_after>package navigator

import (
	"fmt"
	"math/rand"
	"time"

	"github.com/lukevers/arp147/planet"
)

type Cell struct {
	X int64
	Y int64

	Planet     *planet.Planet
	Discovered bool
}

func NewCell(cell *Cell) *Cell {
	if cell == nil {
		cell = &Cell{
			X: randInt(1234567, 7654321),
			Y: randInt(1234567, 7654321),
		}

	}

	cell.initialize()
	return cell
}

func (c *Cell) GetX() string {
	return fmt.Sprintf("0x%X", c.X)
}

func (c *Cell) GetY() string {
	return fmt.Sprintf("0x%X", c.Y)
}

func (c *Cell) HudX() string {
	return fmt.Sprintf("X: %s", c.GetX())
}

func (c *Cell) HudY() string {
	return fmt.Sprintf("Y: %s", c.GetY())
}

func (c *Cell) initialize() {
	seed := time.Now().UTC().UnixNano()
	rand.Seed(seed)

	if chance(12) {
		c.Planet = planet.New(planet.SizeViewer, planet.TypePlanet, true)
	}
}

func randInt(min, max int64) int64 {
	return min + rand.Int63n(max-min)
}

func chance(r int64) bool {
	return randInt(0, r)%12 == 0
}
<|endoftext|>


<commit_before>package light

import (
	"time"

	"github.com/kju2/buildbulb/job"
)

type Controller struct {
	light *light
}

func NewController(input <-chan job.Status) (*Controller, error) {
	light, err := newLight()
	if err != nil {
		return nil, err
	}

	c := &Controller{light}
	go c.run(input)

	return c, nil
}

func (c *Controller) run(input <-chan job.Status) {
	timer := time.Tick(1 * time.Minute)

	color := Red
	power := true
	for {
		select {
		case status := <-input:
			color = c.colorFor(status)
		case time := <-timer:
			power = c.turnLightOnIfWorkingHours(time)
		}
		c.light.setColor(color)
		c.light.setPower(power)
	}
}

func (c *Controller) colorFor(status job.Status) Color {
	color := Red
	switch status {
	case job.Failure:
		color = Red
	case job.Unstable:
		color = Yellow
	case job.Success:
		color = Green
	}
	return color
}

func (c *Controller) turnLightOnIfWorkingHours(t time.Time) bool {
	weekday := t.Weekday()
	if time.Sunday < weekday && weekday < time.Saturday {
		hour := t.Hour()
		workStart := 6
		workEnd := 18
		if workStart <= hour && hour <= workEnd {
			return true
		}
	}
	return false
}
<commit_msg>Update logging.<commit_after>package light

import (
	"time"

	"github.com/kju2/buildbulb/job"
	"github.com/kju2/buildbulb/util"
)

type Controller struct {
	light *light
}

func NewController(input <-chan job.Status) (*Controller, error) {
	light, err := newLight()
	if err != nil {
		return nil, err
	}

	c := &Controller{light}
	go c.run(input)

	return c, nil
}

func (c *Controller) run(input <-chan job.Status) {
	timer := time.Tick(1 * time.Minute)

	color := Red
	power := true
	for {
		select {
		case status := <-input:
			color = c.colorFor(status)
			util.Log.WithField("color", color).Debug("setColor")
		case time := <-timer:
			power = c.turnLightOnIfWorkingHours(time)
			util.Log.WithField("power", power).Debug("setPower")
		}
		c.light.setColor(color)
		c.light.setPower(power)
	}
}

func (c *Controller) colorFor(status job.Status) Color {
	color := Red
	switch status {
	case job.Failure:
		color = Red
	case job.Unstable:
		color = Yellow
	case job.Success:
		color = Green
	}
	return color
}

func (c *Controller) turnLightOnIfWorkingHours(t time.Time) bool {
	weekday := t.Weekday()
	if time.Sunday < weekday && weekday < time.Saturday {
		hour := t.Hour()
		workStart := 6
		workEnd := 18
		if workStart <= hour && hour <= workEnd {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>// +build e2e

/*
Copyright 2018 Knative Authors 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
    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 test

import (
	"strings"
	"testing"

	"github.com/knative/build-pipeline/pkg/apis/pipeline/v1alpha1"
	tb "github.com/knative/build-pipeline/test/builder"
	knativetest "github.com/knative/pkg/test"
	"github.com/knative/pkg/test/logging"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	gitSourceResourceName  = "git-source-resource"
	gitTestTaskName        = "git-check-task"
	gitTestPipelineName    = "git-check-pipeline"
	gitTestPipelineRunName = "git-check-pipeline-run"
)

// TestGitPipelineRun is an integration test that will verify the source code is either fetched or pulled
// successfully under different revision inputs (branch, commitid, tag, ref)
func TestGitPipelineRun(t *testing.T) {
	logger := logging.GetContextLogger(t.Name())
	t.Parallel()

	revisions := []string{"c15aced0e5aaee6456fbe6f7a7e95e0b5b3b2b2f", "c15aced", "release-0.1", "v0.1.0", "refs/pull/347/head"}

	for _, revision := range revisions {

		c, namespace := setup(t, logger)
		knativetest.CleanupOnInterrupt(func() { tearDown(t, logger, c, namespace) }, logger)
		defer tearDown(t, logger, c, namespace)

		logger.Infof("Creating Git PipelineResource %s", gitSourceResourceName)
		if _, err := c.PipelineResourceClient.Create(getGitPipelineResource(namespace, revision)); err != nil {
			t.Fatalf("Failed to create Pipeline Resource `%s`: %s", gitSourceResourceName, err)
		}

		logger.Infof("Creating Task %s", gitTestTaskName)
		if _, err := c.TaskClient.Create(getGitCheckTask(namespace, t, logger)); err != nil {
			t.Fatalf("Failed to create Task `%s`: %s", gitTestTaskName, err)
		}

		logger.Infof("Creating Pipeline %s", gitTestPipelineName)
		if _, err := c.PipelineClient.Create(getGitCheckPipeline(namespace)); err != nil {
			t.Fatalf("Failed to create Pipeline `%s`: %s", gitTestPipelineName, err)
		}

		logger.Infof("Creating PipelineRun %s", gitTestPipelineRunName)
		if _, err := c.PipelineRunClient.Create(getGitCheckPipelineRun(namespace)); err != nil {
			t.Fatalf("Failed to create Pipeline `%s`: %s", gitTestPipelineRunName, err)
		}

		if err := WaitForPipelineRunState(c, gitTestPipelineRunName, timeout, PipelineRunSucceed(gitTestPipelineRunName), "PipelineRunCompleted"); err != nil {
			t.Errorf("Error waiting for PipelineRun %s to finish: %s", gitTestPipelineRunName, err)
			taskruns, err := c.TaskRunClient.List(metav1.ListOptions{})
			if err != nil {
				t.Errorf("Error getting TaskRun list for PipelineRun %s %s", gitTestPipelineRunName, err)
			}
			for _, tr := range taskruns.Items {
				if tr.Status.PodName != "" {
					CollectBuildLogs(c, tr.Status.PodName, namespace, logger)
				}
			}
			t.Fatalf("PipelineRun execution failed")
		}
	}
}

// TestGitPipelineRunFail is a test to ensure that the code extraction from github fails as expected when
// an invalid revision is passed on the pipelineresource.
func TestGitPipelineRunFail(t *testing.T) {
	logger := logging.GetContextLogger(t.Name())
	t.Parallel()

	c, namespace := setup(t, logger)
	knativetest.CleanupOnInterrupt(func() { tearDown(t, logger, c, namespace) }, logger)
	defer tearDown(t, logger, c, namespace)

	logger.Infof("Creating Git PipelineResource %s", gitSourceResourceName)
	if _, err := c.PipelineResourceClient.Create(getGitPipelineResource(namespace, "Idontexistrabbitmonkeydonkey")); err != nil {
		t.Fatalf("Failed to create Pipeline Resource `%s`: %s", gitSourceResourceName, err)
	}

	logger.Infof("Creating Task %s", gitTestTaskName)
	if _, err := c.TaskClient.Create(getGitCheckTask(namespace, t, logger)); err != nil {
		t.Fatalf("Failed to create Task `%s`: %s", gitTestTaskName, err)
	}

	logger.Infof("Creating Pipeline %s", gitTestPipelineName)
	if _, err := c.PipelineClient.Create(getGitCheckPipeline(namespace)); err != nil {
		t.Fatalf("Failed to create Pipeline `%s`: %s", gitTestPipelineName, err)
	}

	logger.Infof("Creating PipelineRun %s", gitTestPipelineRunName)
	if _, err := c.PipelineRunClient.Create(getGitCheckPipelineRun(namespace)); err != nil {
		t.Fatalf("Failed to create Pipeline `%s`: %s", gitTestPipelineRunName, err)
	}

	if err := WaitForPipelineRunState(c, gitTestPipelineRunName, timeout, PipelineRunSucceed(gitTestPipelineRunName), "PipelineRunCompleted"); err != nil {
		taskruns, err := c.TaskRunClient.List(metav1.ListOptions{})
		if err != nil {
			t.Errorf("Error getting TaskRun list for PipelineRun %s %s", gitTestPipelineRunName, err)
		}
		for _, tr := range taskruns.Items {
			if tr.Status.PodName != "" {
				p, err := c.KubeClient.Kube.CoreV1().Pods(namespace).Get(tr.Status.PodName, metav1.GetOptions{})
				if err != nil {
					t.Fatalf("Error getting pod `%s` in namespace `%s`", tr.Status.PodName, namespace)
				}

				for _, stat := range p.Status.InitContainerStatuses {
					if strings.HasPrefix(stat.Name, "build-step-git-source-"+gitSourceResourceName) {
						if stat.State.Terminated != nil {
							req := c.KubeClient.Kube.CoreV1().Pods(namespace).GetLogs(p.Name, &corev1.PodLogOptions{Container: stat.Name})
							logContent, err := req.Do().Raw()
							if err != nil {
								t.Fatalf("Error getting pod logs for pod `%s` and container `%s` in namespace `%s`", tr.Status.PodName, stat.Name, namespace)
							}
							// Check for failure messages from fetch and pull in the log file
							if strings.Contains(string(logContent), "Couldn't find remote ref Idontexistrabbitmonkeydonkey") &&
								strings.Contains(string(logContent), "pathspec 'Idontexistrabbitmonkeydonkey' did not match any file(s) known to git") {
								logger.Infof("Found exepected errors when retrieving non-existent git revision")
							} else {
								logger.Infof("Init container `%s` log File: %s", stat.Name, logContent)
								t.Fatalf("The git code extraction did not fail as expected.  Expected errors not found in log file.")
							}
						}
					}
				}
			}
		}

	} else {
		t.Fatalf("PipelineRun succeeded when should have failed")
	}
}

func getGitPipelineResource(namespace, revision string) *v1alpha1.PipelineResource {
	return tb.PipelineResource(gitSourceResourceName, namespace, tb.PipelineResourceSpec(
		v1alpha1.PipelineResourceTypeGit,
		tb.PipelineResourceSpecParam("Url", "https://github.com/knative/build-pipeline"),
		tb.PipelineResourceSpecParam("Revision", revision),
	))
}

func getGitCheckTask(namespace string, t *testing.T, logger *logging.BaseLogger) *v1alpha1.Task {
	return tb.Task(gitTestTaskName, namespace, tb.TaskSpec(
		tb.TaskInputs(tb.InputsResource("gitsource", v1alpha1.PipelineResourceTypeGit)),
		tb.Step("git", "alpine/git", tb.Args("--git-dir=/workspace/gitsource/.git", "show")),
	))
}

func getGitCheckPipeline(namespace string) *v1alpha1.Pipeline {
	return tb.Pipeline(gitTestPipelineName, namespace, tb.PipelineSpec(
		tb.PipelineDeclaredResource("git-repo", "git"),
		tb.PipelineTask("git-check", gitTestTaskName,
			tb.PipelineTaskInputResource("gitsource", "git-repo"),
		),
	))
}

func getGitCheckPipelineRun(namespace string) *v1alpha1.PipelineRun {
	return tb.PipelineRun(gitTestPipelineRunName, namespace, tb.PipelineRunSpec(
		gitTestPipelineName,
		tb.PipelineRunResourceBinding("git-repo", tb.PipelineResourceBindingRef(gitSourceResourceName)),
	))
}
<commit_msg>Test master branch, and remove additional log collection per review<commit_after>// +build e2e

/*
Copyright 2018 Knative Authors 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
    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 test

import (
	"strings"
	"testing"

	"github.com/knative/build-pipeline/pkg/apis/pipeline/v1alpha1"
	tb "github.com/knative/build-pipeline/test/builder"
	knativetest "github.com/knative/pkg/test"
	"github.com/knative/pkg/test/logging"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	gitSourceResourceName  = "git-source-resource"
	gitTestTaskName        = "git-check-task"
	gitTestPipelineName    = "git-check-pipeline"
	gitTestPipelineRunName = "git-check-pipeline-run"
)

// TestGitPipelineRun is an integration test that will verify the source code is either fetched or pulled
// successfully under different revision inputs (branch, commitid, tag, ref)
func TestGitPipelineRun(t *testing.T) {
	logger := logging.GetContextLogger(t.Name())
	t.Parallel()

	revisions := []string{"master", "c15aced0e5aaee6456fbe6f7a7e95e0b5b3b2b2f", "c15aced", "release-0.1", "v0.1.0", "refs/pull/347/head"}

	for _, revision := range revisions {

		c, namespace := setup(t, logger)
		knativetest.CleanupOnInterrupt(func() { tearDown(t, logger, c, namespace) }, logger)
		defer tearDown(t, logger, c, namespace)

		logger.Infof("Creating Git PipelineResource %s", gitSourceResourceName)
		if _, err := c.PipelineResourceClient.Create(getGitPipelineResource(namespace, revision)); err != nil {
			t.Fatalf("Failed to create Pipeline Resource `%s`: %s", gitSourceResourceName, err)
		}

		logger.Infof("Creating Task %s", gitTestTaskName)
		if _, err := c.TaskClient.Create(getGitCheckTask(namespace, t, logger)); err != nil {
			t.Fatalf("Failed to create Task `%s`: %s", gitTestTaskName, err)
		}

		logger.Infof("Creating Pipeline %s", gitTestPipelineName)
		if _, err := c.PipelineClient.Create(getGitCheckPipeline(namespace)); err != nil {
			t.Fatalf("Failed to create Pipeline `%s`: %s", gitTestPipelineName, err)
		}

		logger.Infof("Creating PipelineRun %s", gitTestPipelineRunName)
		if _, err := c.PipelineRunClient.Create(getGitCheckPipelineRun(namespace)); err != nil {
			t.Fatalf("Failed to create Pipeline `%s`: %s", gitTestPipelineRunName, err)
		}

		if err := WaitForPipelineRunState(c, gitTestPipelineRunName, timeout, PipelineRunSucceed(gitTestPipelineRunName), "PipelineRunCompleted"); err != nil {
			t.Errorf("Error waiting for PipelineRun %s to finish: %s", gitTestPipelineRunName, err)
			t.Fatalf("PipelineRun execution failed")
		}
	}
}

// TestGitPipelineRunFail is a test to ensure that the code extraction from github fails as expected when
// an invalid revision is passed on the pipelineresource.
func TestGitPipelineRunFail(t *testing.T) {
	logger := logging.GetContextLogger(t.Name())
	t.Parallel()

	c, namespace := setup(t, logger)
	knativetest.CleanupOnInterrupt(func() { tearDown(t, logger, c, namespace) }, logger)
	defer tearDown(t, logger, c, namespace)

	logger.Infof("Creating Git PipelineResource %s", gitSourceResourceName)
	if _, err := c.PipelineResourceClient.Create(getGitPipelineResource(namespace, "Idontexistrabbitmonkeydonkey")); err != nil {
		t.Fatalf("Failed to create Pipeline Resource `%s`: %s", gitSourceResourceName, err)
	}

	logger.Infof("Creating Task %s", gitTestTaskName)
	if _, err := c.TaskClient.Create(getGitCheckTask(namespace, t, logger)); err != nil {
		t.Fatalf("Failed to create Task `%s`: %s", gitTestTaskName, err)
	}

	logger.Infof("Creating Pipeline %s", gitTestPipelineName)
	if _, err := c.PipelineClient.Create(getGitCheckPipeline(namespace)); err != nil {
		t.Fatalf("Failed to create Pipeline `%s`: %s", gitTestPipelineName, err)
	}

	logger.Infof("Creating PipelineRun %s", gitTestPipelineRunName)
	if _, err := c.PipelineRunClient.Create(getGitCheckPipelineRun(namespace)); err != nil {
		t.Fatalf("Failed to create Pipeline `%s`: %s", gitTestPipelineRunName, err)
	}

	if err := WaitForPipelineRunState(c, gitTestPipelineRunName, timeout, PipelineRunSucceed(gitTestPipelineRunName), "PipelineRunCompleted"); err != nil {
		taskruns, err := c.TaskRunClient.List(metav1.ListOptions{})
		if err != nil {
			t.Errorf("Error getting TaskRun list for PipelineRun %s %s", gitTestPipelineRunName, err)
		}
		for _, tr := range taskruns.Items {
			if tr.Status.PodName != "" {
				p, err := c.KubeClient.Kube.CoreV1().Pods(namespace).Get(tr.Status.PodName, metav1.GetOptions{})
				if err != nil {
					t.Fatalf("Error getting pod `%s` in namespace `%s`", tr.Status.PodName, namespace)
				}

				for _, stat := range p.Status.InitContainerStatuses {
					if strings.HasPrefix(stat.Name, "build-step-git-source-"+gitSourceResourceName) {
						if stat.State.Terminated != nil {
							req := c.KubeClient.Kube.CoreV1().Pods(namespace).GetLogs(p.Name, &corev1.PodLogOptions{Container: stat.Name})
							logContent, err := req.Do().Raw()
							if err != nil {
								t.Fatalf("Error getting pod logs for pod `%s` and container `%s` in namespace `%s`", tr.Status.PodName, stat.Name, namespace)
							}
							// Check for failure messages from fetch and pull in the log file
							if strings.Contains(string(logContent), "Couldn't find remote ref Idontexistrabbitmonkeydonkey") &&
								strings.Contains(string(logContent), "pathspec 'Idontexistrabbitmonkeydonkey' did not match any file(s) known to git") {
								logger.Infof("Found exepected errors when retrieving non-existent git revision")
							} else {
								logger.Infof("Init container `%s` log File: %s", stat.Name, logContent)
								t.Fatalf("The git code extraction did not fail as expected.  Expected errors not found in log file.")
							}
						}
					}
				}
			}
		}

	} else {
		t.Fatalf("PipelineRun succeeded when should have failed")
	}
}

func getGitPipelineResource(namespace, revision string) *v1alpha1.PipelineResource {
	return tb.PipelineResource(gitSourceResourceName, namespace, tb.PipelineResourceSpec(
		v1alpha1.PipelineResourceTypeGit,
		tb.PipelineResourceSpecParam("Url", "https://github.com/knative/build-pipeline"),
		tb.PipelineResourceSpecParam("Revision", revision),
	))
}

func getGitCheckTask(namespace string, t *testing.T, logger *logging.BaseLogger) *v1alpha1.Task {
	return tb.Task(gitTestTaskName, namespace, tb.TaskSpec(
		tb.TaskInputs(tb.InputsResource("gitsource", v1alpha1.PipelineResourceTypeGit)),
		tb.Step("git", "alpine/git", tb.Args("--git-dir=/workspace/gitsource/.git", "show")),
	))
}

func getGitCheckPipeline(namespace string) *v1alpha1.Pipeline {
	return tb.Pipeline(gitTestPipelineName, namespace, tb.PipelineSpec(
		tb.PipelineDeclaredResource("git-repo", "git"),
		tb.PipelineTask("git-check", gitTestTaskName,
			tb.PipelineTaskInputResource("gitsource", "git-repo"),
		),
	))
}

func getGitCheckPipelineRun(namespace string) *v1alpha1.PipelineRun {
	return tb.PipelineRun(gitTestPipelineRunName, namespace, tb.PipelineRunSpec(
		gitTestPipelineName,
		tb.PipelineRunResourceBinding("git-repo", tb.PipelineResourceBindingRef(gitSourceResourceName)),
	))
}
<|endoftext|>