<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"sample/sampleworld"

	"v.io/v23"

	"v.io/x/ref/lib/flags/consts"
	"v.io/x/ref/lib/signals"
	"v.io/x/ref/profiles"
	"v.io/x/ref/test/expect"
	"v.io/x/ref/test/modules"
	"v.io/x/ref/test/modules/core"
)

const (
	SampleWorldCommand = "sampleWorld"           // The modules library command.
	stdoutLog          = "tmp/runner.stdout.log" // Used as stdout drain when shutting down.
	stderrLog          = "tmp/runner.stderr.log" // Used as stderr drain when shutting down.
)

var (
	// Flags used as input to this program.
	runSample     bool
	serveHTTP     bool
	portHTTP      string
	rootHTTP      string
	runTests      bool
	runTestsWatch bool
)

func init() {
	modules.RegisterChild(SampleWorldCommand, "desc", sampleWorld)
	flag.BoolVar(&runSample, "runSample", false, "if true, runs sample services")
	flag.BoolVar(&serveHTTP, "serveHTTP", false, "if true, serves HTTP")
	flag.StringVar(&portHTTP, "portHTTP", "9001", "default 9001, the port to serve HTTP on")
	flag.StringVar(&rootHTTP, "rootHTTP", ".", "default '.', the root HTTP folder path")
	flag.BoolVar(&runTests, "runTests", false, "if true, runs the namespace browser tests")
	flag.BoolVar(&runTestsWatch, "runTestsWatch", false, "if true && runTests, runs the tests in watch mode")
}

// Helper function to simply panic on error.
func panicOnError(err error) {
	if err != nil {
		panic(err)
	}
}

// updateVars captures the vars from the given Handle's stdout and adds them to
// the given vars map, overwriting existing entries.
func updateVars(h modules.Handle, vars map[string]string, varNames ...string) error {
	varsToAdd := map[string]bool{}
	for _, v := range varNames {
		varsToAdd[v] = true
	}
	numLeft := len(varsToAdd)

	s := expect.NewSession(nil, h.Stdout(), 30*time.Second)
	for {
		l := s.ReadLine()
		if err := s.OriginalError(); err != nil {
			return err // EOF or otherwise
		}
		parts := strings.Split(l, "=")
		if len(parts) != 2 {
			return fmt.Errorf("Unexpected line: %s", l)
		}
		if _, ok := varsToAdd[parts[0]]; ok {
			numLeft--
			vars[parts[0]] = parts[1]
			if numLeft == 0 {
				break
			}
		}
	}
	return nil
}

// The module command for running the sample world.
func sampleWorld(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
	ctx, shutdown := v23.Init()
	defer shutdown()

	sampleworld.RunSampleWorld(ctx)

	modules.WaitForEOF(stdin)
	return nil
}

func main() {
	if modules.IsModulesChildProcess() {
		panicOnError(modules.Dispatch())
		return
	}

	// If we ever get a SIGHUP (terminal closes), then end the program.
	signalChannel := make(chan os.Signal)
	signal.Notify(signalChannel, syscall.SIGHUP)
	go func() {
		sig := <-signalChannel
		switch sig {
		case syscall.SIGHUP:
			os.Exit(1)
		}
	}()

	// Try running the program; on failure, exit with error status code.
	if !run() {
		os.Exit(1)
	}
}

// Runs the services and cleans up afterwards.
// Returns true if the run was successful.
func run() bool {
	ctx, shutdown := v23.Init()
	defer shutdown()

	// In order to prevent conflicts, tests and webapp use different mounttable ports.
	port := 5180
	cottagePort := 5181
	housePort := 5182
	if runTests {
		port = 8884
		cottagePort = 8885
		housePort = 8886
	}

	// Start a new shell module.
	vars := map[string]string{}
	sh, err := modules.NewShell(ctx, nil)
	if err != nil {
		panic(fmt.Sprintf("modules.NewShell: %s", err))
	}

	// Collect the output of this shell on termination.
	err = os.MkdirAll("tmp", 0750)
	panicOnError(err)
	outFile, err := os.Create(stdoutLog)
	panicOnError(err)
	defer outFile.Close()
	errFile, err := os.Create(stderrLog)
	panicOnError(err)
	defer errFile.Close()
	defer sh.Cleanup(outFile, errFile)

	// Determine the hostname; this name will be used for mounting.
	hostName, err := exec.Command("hostname", "-s").Output()
	panicOnError(err)

	// Run the host mounttable.
	rootName := fmt.Sprintf("%s-home", strings.TrimSpace(string(hostName))) // Must trim; hostname has \n at the end.
	hRoot, err := sh.Start(core.MTCommand, nil, "--veyron.tcp.protocol=ws", fmt.Sprintf("--veyron.tcp.address=127.0.0.1:%d", port), rootName)
	panicOnError(err)
	panicOnError(updateVars(hRoot, vars, "MT_NAME"))
	defer hRoot.Shutdown(outFile, errFile)

	// Set consts.NamespaceRootPrefix env var, consumed downstream.
	sh.SetVar(consts.NamespaceRootPrefix, vars["MT_NAME"])
	v23.GetNamespace(ctx).SetRoots(vars["MT_NAME"])

	// Run the cottage mounttable at host/cottage.
	hCottage, err := sh.Start(core.MTCommand, nil, "--veyron.tcp.protocol=ws", fmt.Sprintf("--veyron.tcp.address=127.0.0.1:%d", cottagePort), "cottage")
	panicOnError(err)
	expect.NewSession(nil, hCottage.Stdout(), 30*time.Second)
	defer hCottage.Shutdown(outFile, errFile)

	// run the house mounttable at host/house.
	hHouse, err := sh.Start(core.MTCommand, nil, "--veyron.tcp.protocol=ws", fmt.Sprintf("--veyron.tcp.address=127.0.0.1:%d", housePort), "house")
	panicOnError(err)
	expect.NewSession(nil, hHouse.Stdout(), 30*time.Second)
	defer hHouse.Shutdown(outFile, errFile)

	// Possibly run the sample world.
	if runSample {
		fmt.Println("Running Sample World")
		hSample, err := sh.Start(SampleWorldCommand, nil, "--veyron.tcp.protocol=ws", "--veyron.tcp.address=127.0.0.1:0")
		panicOnError(err)
		expect.NewSession(nil, hSample.Stdout(), 30*time.Second)
		defer hSample.Shutdown(outFile, errFile)
	}

	// Possibly serve the public bundle at the portHTTP.
	if serveHTTP {
		fmt.Printf("Also serving HTTP at %s for %s\n", portHTTP, rootHTTP)
		http.ListenAndServe(":"+portHTTP, http.FileServer(http.Dir(rootHTTP)))
	}

	// Just print out the collected variables. This is for debugging purposes.
	bytes, err := json.Marshal(vars)
	panicOnError(err)
	fmt.Println(string(bytes))

	// Possibly run the tests in Prova.
	if runTests {
		// Also set HOUSE_MOUNTTABLE (used in the tests)
		os.Setenv("HOUSE_MOUNTTABLE", fmt.Sprintf("/127.0.0.1:%d", housePort))

		proxyShutdown, proxyEndpoint, err := profiles.NewProxy(ctx, "ws", "127.0.0.1:0", "", "test/proxy")
		panicOnError(err)
		defer proxyShutdown()
		vars["PROXY_NAME"] = proxyEndpoint.Name()

		hIdentityd, err := sh.Start(core.TestIdentitydCommand, nil, "--veyron.tcp.protocol=ws", "--veyron.tcp.address=127.0.0.1:0", "--veyron.proxy=test/proxy", "--host=localhost", "--httpaddr=localhost:0")
		panicOnError(err)
		panicOnError(updateVars(hIdentityd, vars, "TEST_IDENTITYD_NAME", "TEST_IDENTITYD_HTTP_ADDR"))
		defer hIdentityd.Shutdown(outFile, errFile)

		// Setup a lot of environment variables; these are used for the tests and building the test extension.
		os.Setenv("NAMESPACE_ROOT", vars["MT_NAME"])
		os.Setenv("PROXY_ADDR", vars["PROXY_NAME"])
		os.Setenv("IDENTITYD", fmt.Sprintf("%s/google", vars["TEST_IDENTITYD_NAME"]))
		os.Setenv("IDENTITYD_BLESSING_URL", fmt.Sprintf("%s/blessing-root", vars["TEST_IDENTITYD_HTTP_ADDR"]))
		os.Setenv("DEBUG", "false")

		testsOk := runProva()

		fmt.Println("Cleaning up launched services...")
		return testsOk
	}

	// Not in a test, so run until the program is killed.
	<-signals.ShutdownOnSignals(ctx)
	return true
}

// Run the prova tests and convert its tap output to xunit.
func runProva() bool {
	// This is also useful information for routing the test output.
	VANADIUM_ROOT := os.Getenv("VANADIUM_ROOT")
	VANADIUM_JS := fmt.Sprintf("%s/release/javascript/core", VANADIUM_ROOT)
	VANADIUM_BROWSER := fmt.Sprintf("%s/release/projects/namespace_browser", VANADIUM_ROOT)

	TAP_XUNIT := fmt.Sprintf("%s/node_modules/.bin/tap-xunit", VANADIUM_BROWSER)
	XUNIT_OUTPUT_FILE := os.Getenv("XUNIT_OUTPUT_FILE")
	if XUNIT_OUTPUT_FILE == "" {
		XUNIT_OUTPUT_FILE = fmt.Sprintf("%s/test_output.xml", os.Getenv("TMPDIR"))
	}
	TAP_XUNIT_OPTIONS := " --package=namespace-browser"

	// Make sure we're in the right folder when we run make test-extension.
	vbroot, err := os.Open(VANADIUM_BROWSER)
	panicOnError(err)
	err = vbroot.Chdir()
	panicOnError(err)

	// Make the test-extension, this should also remove the old one.
	fmt.Println("Rebuilding test extension...")
	cmdExtensionClean := exec.Command("rm", "-fr", fmt.Sprintf("%s/extension/build-test", VANADIUM_JS))
	err = cmdExtensionClean.Run()
	panicOnError(err)
	cmdExtensionBuild := exec.Command("make", "-C", fmt.Sprintf("%s/extension", VANADIUM_JS), "build-test")
	err = cmdExtensionBuild.Run()
	panicOnError(err)

	// These are the basic prova options.
	options := []string{
		"test/**/*.js",
		"--browser",
		"--includeFilenameAsPackage",
		"--launch",
		"chrome",
		"--plugin",
		"proxyquireify/plugin",
		"--transform",
		"envify,./main-transform",
		"--log",
		"tmp/chrome.log",
		fmt.Sprintf("--options=--load-extension=%s/extension/build-test/,--ignore-certificate-errors,--enable-logging=stderr", VANADIUM_JS),
	}

	// Normal tests have a few more options and a different port from the watch tests.
	var PROVA_PORT int
	if !runTestsWatch {
		PROVA_PORT = 8893
		options = append(options, "--headless", "--quit", "--progress", "--tap")
		fmt.Printf("\033[34m-Executing tests. See %s for test xunit output.\033[0m\n", XUNIT_OUTPUT_FILE)
	} else {
		PROVA_PORT = 8894
		fmt.Println("\033[34m-Running tests in watch mode.\033[0m")
	}
	options = append(options, "--port", fmt.Sprintf("%d", PROVA_PORT))

	// This is the prova command.
	cmdProva := exec.Command(
		fmt.Sprintf("%s/node_modules/.bin/prova", VANADIUM_BROWSER),
		options...,
	)
	fmt.Printf("\033[34m-Go to \033[32mhttp://0.0.0.0:%d\033[34m to see tests running.\033[0m\n", PROVA_PORT)
	fmt.Println(cmdProva)

	// Collect the prova stdout. This information needs to be sent to xunit.
	provaOut, err := cmdProva.StdoutPipe()
	panicOnError(err)

	// Setup the tap to xunit command. It uses Prova's stdout as input.
	// The output will got the xunit output file.
	cmdTap := exec.Command(TAP_XUNIT, TAP_XUNIT_OPTIONS)
	cmdTap.Stdin = io.TeeReader(provaOut, os.Stdout) // Tee the prova output to see it on the console too.
	outfile, err := os.Create(XUNIT_OUTPUT_FILE)
	panicOnError(err)
	defer outfile.Close()
	bufferedWriter := bufio.NewWriter(outfile)
	cmdTap.Stdout = bufferedWriter
	defer bufferedWriter.Flush() // Ensure that the full xunit output is written.

	// We start the tap command...
	err = cmdTap.Start()
	panicOnError(err)

	// Meanwhile, run Prova to completion. If there was an error, print ERROR, otherwise PASS.
	err = cmdProva.Run()
	testsOk := true
	if err != nil {
		fmt.Println(err)
		fmt.Println("\033[31m\033[1mERROR\033[0m")
		testsOk = false
	} else {
		fmt.Println("\033[32m\033[1mPASS\033[0m")
	}

	// Wait for tap to xunit to finish itself off. This file will be ready for reading by Jenkins.
	fmt.Println("Converting Tap output to XUnit")
	err = cmdTap.Wait()
	panicOnError(err)

	return testsOk
}
<commit_msg>namespace-browser: Use ipv4 addresses for sample world<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"sample/sampleworld"

	"v.io/v23"

	"v.io/x/ref/lib/flags/consts"
	"v.io/x/ref/lib/signals"
	"v.io/x/ref/profiles"
	"v.io/x/ref/test/expect"
	"v.io/x/ref/test/modules"
	"v.io/x/ref/test/modules/core"
)

const (
	SampleWorldCommand = "sampleWorld"           // The modules library command.
	stdoutLog          = "tmp/runner.stdout.log" // Used as stdout drain when shutting down.
	stderrLog          = "tmp/runner.stderr.log" // Used as stderr drain when shutting down.
)

var (
	// Flags used as input to this program.
	runSample     bool
	serveHTTP     bool
	portHTTP      string
	rootHTTP      string
	runTests      bool
	runTestsWatch bool
)

func init() {
	modules.RegisterChild(SampleWorldCommand, "desc", sampleWorld)
	flag.BoolVar(&runSample, "runSample", false, "if true, runs sample services")
	flag.BoolVar(&serveHTTP, "serveHTTP", false, "if true, serves HTTP")
	flag.StringVar(&portHTTP, "portHTTP", "9001", "default 9001, the port to serve HTTP on")
	flag.StringVar(&rootHTTP, "rootHTTP", ".", "default '.', the root HTTP folder path")
	flag.BoolVar(&runTests, "runTests", false, "if true, runs the namespace browser tests")
	flag.BoolVar(&runTestsWatch, "runTestsWatch", false, "if true && runTests, runs the tests in watch mode")
}

// Helper function to simply print an error and then exit.
func exitOnError(err error, desc string) {
	if err != nil {
		fmt.Fprintln(os.Stderr, desc, err)
		os.Exit(1)
	}
}

// updateVars captures the vars from the given Handle's stdout and adds them to
// the given vars map, overwriting existing entries.
func updateVars(h modules.Handle, vars map[string]string, varNames ...string) error {
	varsToAdd := map[string]bool{}
	for _, v := range varNames {
		varsToAdd[v] = true
	}
	numLeft := len(varsToAdd)

	s := expect.NewSession(nil, h.Stdout(), 30*time.Second)
	for {
		l := s.ReadLine()
		if err := s.OriginalError(); err != nil {
			return err // EOF or otherwise
		}
		parts := strings.Split(l, "=")
		if len(parts) != 2 {
			return fmt.Errorf("Unexpected line: %s", l)
		}
		if _, ok := varsToAdd[parts[0]]; ok {
			numLeft--
			vars[parts[0]] = parts[1]
			if numLeft == 0 {
				break
			}
		}
	}
	return nil
}

// The module command for running the sample world.
func sampleWorld(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
	ctx, shutdown := v23.Init()
	defer shutdown()

	sampleworld.RunSampleWorld(ctx)

	modules.WaitForEOF(stdin)
	return nil
}

func main() {
	if modules.IsModulesChildProcess() {
		exitOnError(modules.Dispatch(), "Failed to dispatch module")
		return
	}

	// If we ever get a SIGHUP (terminal closes), then end the program.
	signalChannel := make(chan os.Signal)
	signal.Notify(signalChannel, syscall.SIGHUP)
	go func() {
		sig := <-signalChannel
		switch sig {
		case syscall.SIGHUP:
			os.Exit(1)
		}
	}()

	// Try running the program; on failure, exit with error status code.
	if !run() {
		os.Exit(1)
	}
}

// Returns the first ipv4 address found or an error
func getFirstIPv4Address() (string, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return "", fmt.Errorf("No net interfaces found")
	}
	for _, i := range ifaces {
		addrs, err := i.Addrs()
		if err != nil {
			continue
		}

		for _, addr := range addrs {
			var ip net.IP
			if v, ok := addr.(*net.IPNet); ok {
				ip = v.IP
			}
			if ip == nil || ip.IsLoopback() {
				continue
			}
			ip = ip.To4()
			if ip == nil {
				continue // not an ipv4 address
			}
			return ip.String(), nil
		}
	}
	return "", fmt.Errorf("no ipv4 addresses were found")
}

// Runs the services and cleans up afterwards.
// Returns true if the run was successful.
func run() bool {
	ctx, shutdown := v23.Init()
	defer shutdown()

	// In order to prevent conflicts, tests and webapp use different mounttable ports.
	port := 8884
	cottagePort := 8885
	housePort := 8886
	host := "localhost"
	if !runTests {
		port = 5180
		cottagePort = 5181
		housePort = 5182

		// Get the IP address to serve at, since this is external-facing.
		sampleHost, err := getFirstIPv4Address()
		exitOnError(err, "Could not get host IP address")
		fmt.Printf("Using host %s\n", sampleHost)
		host = sampleHost
	}

	// Start a new shell module.
	vars := map[string]string{}
	sh, err := modules.NewShell(ctx, nil)
	if err != nil {
		panic(fmt.Sprintf("modules.NewShell: %s", err))
	}

	// Collect the output of this shell on termination.
	err = os.MkdirAll("tmp", 0750)
	exitOnError(err, "Could not make temp directory")
	outFile, err := os.Create(stdoutLog)
	exitOnError(err, "Could not open stdout log file")
	defer outFile.Close()
	errFile, err := os.Create(stderrLog)
	exitOnError(err, "Could not open stderr log file")
	defer errFile.Close()
	defer sh.Cleanup(outFile, errFile)

	// Determine the hostname; this name will be used for mounting.
	hostName, err := exec.Command("hostname", "-s").Output()
	exitOnError(err, "Failed to obtain hostname")

	// Run the host mounttable.
	rootName := fmt.Sprintf("%s-home", strings.TrimSpace(string(hostName))) // Must trim; hostname has \n at the end.
	hRoot, err := sh.Start(core.MTCommand, nil, "--veyron.tcp.protocol=wsh", fmt.Sprintf("--veyron.tcp.address=%s:%d", host, port), rootName)
	exitOnError(err, "Failed to start root mount table")
	exitOnError(updateVars(hRoot, vars, "MT_NAME"), "Failed to get MT_NAME")
	defer hRoot.Shutdown(outFile, errFile)

	// Set consts.NamespaceRootPrefix env var, consumed downstream.
	sh.SetVar(consts.NamespaceRootPrefix, vars["MT_NAME"])
	v23.GetNamespace(ctx).SetRoots(vars["MT_NAME"])

	// Run the cottage mounttable at host/cottage.
	hCottage, err := sh.Start(core.MTCommand, nil, "--veyron.tcp.protocol=wsh", fmt.Sprintf("--veyron.tcp.address=%s:%d", host, cottagePort), "cottage")
	exitOnError(err, "Failed to start cottage mount table")
	expect.NewSession(nil, hCottage.Stdout(), 30*time.Second)
	defer hCottage.Shutdown(outFile, errFile)

	// run the house mounttable at host/house.
	hHouse, err := sh.Start(core.MTCommand, nil, "--veyron.tcp.protocol=wsh", fmt.Sprintf("--veyron.tcp.address=%s:%d", host, housePort), "house")
	exitOnError(err, "Failed to start house mount table")
	expect.NewSession(nil, hHouse.Stdout(), 30*time.Second)
	defer hHouse.Shutdown(outFile, errFile)

	// Possibly run the sample world.
	if runSample {
		fmt.Println("Running Sample World")
		hSample, err := sh.Start(SampleWorldCommand, nil, "--veyron.tcp.protocol=wsh", fmt.Sprintf("--veyron.tcp.address=%s:0", host))
		exitOnError(err, "Failed to start sample world")
		expect.NewSession(nil, hSample.Stdout(), 30*time.Second)
		defer hSample.Shutdown(outFile, errFile)
	}

	// Possibly serve the public bundle at the portHTTP.
	if serveHTTP {
		fmt.Printf("Also serving HTTP at %s for %s\n", portHTTP, rootHTTP)
		http.ListenAndServe(":"+portHTTP, http.FileServer(http.Dir(rootHTTP)))
	}

	// Just print out the collected variables. This is for debugging purposes.
	bytes, err := json.Marshal(vars)
	exitOnError(err, "Failed to marshal the collected variables")
	fmt.Println(string(bytes))

	// Possibly run the tests in Prova.
	if runTests {
		// Also set HOUSE_MOUNTTABLE (used in the tests)
		os.Setenv("HOUSE_MOUNTTABLE", fmt.Sprintf("/%s:%d", host, housePort))

		proxyShutdown, proxyEndpoint, err := profiles.NewProxy(ctx, "wsh", ":0", "", "test/proxy")
		exitOnError(err, "Failed to start proxy")
		defer proxyShutdown()
		vars["PROXY_NAME"] = proxyEndpoint.Name()

		hIdentityd, err := sh.Start(core.TestIdentitydCommand, nil, "--veyron.tcp.protocol=wsh", "--veyron.tcp.address=:0", "--veyron.proxy=test/proxy", "--host=localhost", "--httpaddr=localhost:0")
		exitOnError(err, "Failed to start identityd")
		exitOnError(updateVars(hIdentityd, vars, "TEST_IDENTITYD_NAME", "TEST_IDENTITYD_HTTP_ADDR"), "Failed to obtain identityd address")
		defer hIdentityd.Shutdown(outFile, errFile)

		// Setup a lot of environment variables; these are used for the tests and building the test extension.
		os.Setenv("NAMESPACE_ROOT", vars["MT_NAME"])
		os.Setenv("PROXY_ADDR", vars["PROXY_NAME"])
		os.Setenv("IDENTITYD", fmt.Sprintf("%s/google", vars["TEST_IDENTITYD_NAME"]))
		os.Setenv("IDENTITYD_BLESSING_URL", fmt.Sprintf("%s/blessing-root", vars["TEST_IDENTITYD_HTTP_ADDR"]))
		os.Setenv("DEBUG", "false")

		testsOk := runProva()

		fmt.Println("Cleaning up launched services...")
		return testsOk
	}

	// Not in a test, so run until the program is killed.
	<-signals.ShutdownOnSignals(ctx)
	return true
}

// Run the prova tests and convert its tap output to xunit.
func runProva() bool {
	// This is also useful information for routing the test output.
	VANADIUM_ROOT := os.Getenv("VANADIUM_ROOT")
	VANADIUM_JS := fmt.Sprintf("%s/release/javascript/core", VANADIUM_ROOT)
	VANADIUM_BROWSER := fmt.Sprintf("%s/release/projects/namespace_browser", VANADIUM_ROOT)

	TAP_XUNIT := fmt.Sprintf("%s/node_modules/.bin/tap-xunit", VANADIUM_BROWSER)
	XUNIT_OUTPUT_FILE := os.Getenv("XUNIT_OUTPUT_FILE")
	if XUNIT_OUTPUT_FILE == "" {
		XUNIT_OUTPUT_FILE = fmt.Sprintf("%s/test_output.xml", os.Getenv("TMPDIR"))
	}
	TAP_XUNIT_OPTIONS := " --package=namespace-browser"

	// Make sure we're in the right folder when we run make test-extension.
	vbroot, err := os.Open(VANADIUM_BROWSER)
	exitOnError(err, "Failed to open vanadium browser dir")
	err = vbroot.Chdir()
	exitOnError(err, "Failed to change to vanadium browser dir")

	// Make the test-extension, this should also remove the old one.
	fmt.Println("Rebuilding test extension...")
	cmdExtensionClean := exec.Command("rm", "-fr", fmt.Sprintf("%s/extension/build-test", VANADIUM_JS))
	err = cmdExtensionClean.Run()
	exitOnError(err, "Failed to clean test extension")
	cmdExtensionBuild := exec.Command("make", "-C", fmt.Sprintf("%s/extension", VANADIUM_JS), "build-test")
	err = cmdExtensionBuild.Run()
	exitOnError(err, "Failed to build test extension")

	// These are the basic prova options.
	options := []string{
		"test/**/*.js",
		"--browser",
		"--includeFilenameAsPackage",
		"--launch",
		"chrome",
		"--plugin",
		"proxyquireify/plugin",
		"--transform",
		"envify,./main-transform",
		"--log",
		"tmp/chrome.log",
		fmt.Sprintf("--options=--load-extension=%s/extension/build-test/,--ignore-certificate-errors,--enable-logging=stderr", VANADIUM_JS),
	}

	// Normal tests have a few more options and a different port from the watch tests.
	var PROVA_PORT int
	if !runTestsWatch {
		PROVA_PORT = 8893
		options = append(options, "--headless", "--quit", "--progress", "--tap")
		fmt.Printf("\033[34m-Executing tests. See %s for test xunit output.\033[0m\n", XUNIT_OUTPUT_FILE)
	} else {
		PROVA_PORT = 8894
		fmt.Println("\033[34m-Running tests in watch mode.\033[0m")
	}
	options = append(options, "--port", fmt.Sprintf("%d", PROVA_PORT))

	// This is the prova command.
	cmdProva := exec.Command(
		fmt.Sprintf("%s/node_modules/.bin/prova", VANADIUM_BROWSER),
		options...,
	)
	fmt.Printf("\033[34m-Go to \033[32mhttp://0.0.0.0:%d\033[34m to see tests running.\033[0m\n", PROVA_PORT)
	fmt.Println(cmdProva)

	// Collect the prova stdout. This information needs to be sent to xunit.
	provaOut, err := cmdProva.StdoutPipe()
	exitOnError(err, "Failed to get prova stdout pipe")

	// Setup the tap to xunit command. It uses Prova's stdout as input.
	// The output will got the xunit output file.
	cmdTap := exec.Command(TAP_XUNIT, TAP_XUNIT_OPTIONS)
	cmdTap.Stdin = io.TeeReader(provaOut, os.Stdout) // Tee the prova output to see it on the console too.
	outfile, err := os.Create(XUNIT_OUTPUT_FILE)
	exitOnError(err, "Failed to create xunit output file")
	defer outfile.Close()
	bufferedWriter := bufio.NewWriter(outfile)
	cmdTap.Stdout = bufferedWriter
	defer bufferedWriter.Flush() // Ensure that the full xunit output is written.

	// We start the tap command...
	err = cmdTap.Start()
	exitOnError(err, "Failed to start tap to xunit command")

	// Meanwhile, run Prova to completion. If there was an error, print ERROR, otherwise PASS.
	err = cmdProva.Run()
	testsOk := true
	if err != nil {
		fmt.Println(err)
		fmt.Println("\033[31m\033[1mERROR\033[0m")
		testsOk = false
	} else {
		fmt.Println("\033[32m\033[1mPASS\033[0m")
	}

	// Wait for tap to xunit to finish itself off. This file will be ready for reading by Jenkins.
	fmt.Println("Converting Tap output to XUnit")
	err = cmdTap.Wait()
	exitOnError(err, "Failed tap to xunit conversion")

	return testsOk
}
<|endoftext|>


<commit_before>package common

// used for numberic arrays
func NumbericLength(n []int) int {
	i := 0
	for i = 0; i < len(n); i++ {
		if n[i] > 0 {
			break
		}
	}
	return len(n) - i
}

func Plus(a []int, b []int, r []int) {

	for i := 0; i < len(r); i++ {
		r[i] = 0
	}

	al, bl := NumbericLength(a), NumbericLength(b)

	j := len(r) - 1
	c := 0

	pos, pa, pb := 0, 0, 0
	for {
		pos = len(r) - 1 - j

		if c >= al && c >= bl {
			break
		}

		pos = len(r) - 1 - j
		pa = len(a) - 1 - pos
		pb = len(b) - 1 - pos

		if pa >= 0 && pb >= 0 {
			tmp := a[pa] + b[pb]
			r[j] += tmp % 10
			r[j-1] += r[j]/10 + tmp/10
			r[j] %= 10
		} else if pa < 0 {
			r[j] += b[pb]
			r[j-1] += r[j] / 10
			r[j] %= 10
		} else if pb < 0 {
			r[j] += a[pa]
			r[j-1] += r[j] / 10
			r[j] %= 10
		}

		c++
		j--
	}
}

func PlusV2(a []int, b []int, r []int) {
	pos := len(a)
	carry := 0

	for {
		pos--
		if pos < 0 {
			break
		}

		total := a[pos] + b[pos] + carry
		if total > 9 {
			r[pos] = total - 10
			carry = 1
		} else {
			r[pos+1] = total
			carry = 0
		}
	}
	r[0] = carry
}

func Multiple(a []int, b []int, r []int) {

	pos := len(r) - 1

	for i := 0; i < len(r); i++ {
		r[i] = 0
	}

	for i := len(a) - 1; i >= 0; i-- {
		off := len(a) - 1 - i

		for j := len(b) - 1; j >= 0; j-- {
			tmp := b[j] * a[i]
			r[pos-off] += tmp % 10
			r[pos-off-1] += r[pos-off]/10 + tmp/10
			r[pos-off] %= 10
			off++
		}
	}
}

func MultipleWithResult(f []int, g []int) []int {

	if len(f) < len(g) {
		t := f
		f = g
		g = t
	}

	result := make([]int, len(f)+len(g)+1)

	for j := len(g) - 1; j >= 0; j-- {
		//initially pos (index of result ) has the same relative postion as j in array
		pos := len(result) - (len(g) - j)
		for i := len(f) - 1; i >= 0; i-- {
			temp := g[j] * f[i]
			result[pos] += temp % 10
			result[pos-1] += temp / 10
			pos--
		}
		//	fmt.Println(result)
	}

	for i := len(result) - 1; i > 0; i-- {
		temp := result[i]
		result[i] = temp % 10
		result[i-1] += temp / 10
	}

	return result
}

func Divisor(n int) []int {

	nums := make([]int, 500)

	for i := 0; i < len(nums); i++ {
		nums[i] = 0
	}

	i, c := 1, 0

	for {
		if i*i > n {
			break
		}

		tmp := n % i
		if tmp == 0 {
			nums[c] = i
			// only collect 1, ingore the number itself
			if i != 1 && i != n/i {
				c++
				nums[c] = n / i
			}
		}
		i++
		c++
		//fmt.Println("c:  ", c)
	}

	return nums
}

func DivideV1(a int, b int) (int, int) {
	q, r := 0, a
	for {
		if r < b {
			break
		}

		r = r - b
		q = q + 1
	}

	return q, r
}

func QuickDivision(a int, b int) (int, int) {

	counter, power, mid, appr := 0, 1, 0, 0

	for {
		if power*b > a {
			break
		}

		counter++
		power = power * 2
	}
	p, q := power, power/2

	for k := 1; k < counter; k++ {
		comp := (p + q) / 2
		mid = comp * b

		if mid <= a {
			appr = mid
			q = comp
		} else {
			p = comp
		}
	}

	r := a - appr
	return q, r
}

func PostiveSub(a []int, b []int, r []int) {
	// assuem a > b

	for i := 0; i < len(r); i++ {
		r[i] = 0
	}

	al, bl := NumbericLength(a), NumbericLength(b)

	c := 0
	j := len(r) - 1
	pos, pa, pb := 0, 0, 0

	for {
		pos = len(r) - 1 - j

		pa = al - 1 - pos
		pb = bl - 1 - pos

		if c >= al && c >= bl {
			break
		}

		if pa >= 0 && pb >= 0 {
			if a[pa] > b[pb] {
				r[j] = a[pa] - b[pb]
			} else {
				r[j] = a[pa] + 10 - b[pb]
				for k := pa - 1; k >= 0; k-- {
					if a[k] == 0 {
						a[k] = 9
					} else {
						a[k] = a[k] - 1
						break
					}
				}
			}
		} else if pb < 0 {
			r[j] = a[pa]
		}

		c++
		j--
	}
}
<commit_msg>update golang<commit_after>package common

// used for numberic arrays
func NumbericLength(n []int) int {
	i := 0
	for i = 0; i < len(n); i++ {
		if n[i] > 0 {
			break
		}
	}
	return len(n) - i
}

func Plus(a []int, b []int, r []int) {

	for i := 0; i < len(r); i++ {
		r[i] = 0
	}

	al, bl := NumbericLength(a), NumbericLength(b)

	j := len(r) - 1
	c := 0

	pos, pa, pb := 0, 0, 0
	for {
		pos = len(r) - 1 - j

		if c >= al && c >= bl {
			break
		}

		pos = len(r) - 1 - j
		pa = len(a) - 1 - pos
		pb = len(b) - 1 - pos

		if pa >= 0 && pb >= 0 {
			tmp := a[pa] + b[pb]
			r[j] += tmp % 10
			r[j-1] += r[j]/10 + tmp/10
			r[j] %= 10
		} else if pa < 0 {
			r[j] += b[pb]
			r[j-1] += r[j] / 10
			r[j] %= 10
		} else if pb < 0 {
			r[j] += a[pa]
			r[j-1] += r[j] / 10
			r[j] %= 10
		}

		c++
		j--
	}
}

func PlusV2(a []int, b []int, r []int) {
	pos := len(a)
	carry := 0

	for {
		pos--
		if pos < 0 {
			break
		}

		total := a[pos] + b[pos] + carry
		if total > 9 {
			r[pos] = total - 10
			carry = 1
		} else {
			r[pos+1] = total
			carry = 0
		}
	}
	r[0] = carry
}

func Multiple(a []int, b []int, r []int) {

	pos := len(r) - 1

	for i := 0; i < len(r); i++ {
		r[i] = 0
	}

	for i := len(a) - 1; i >= 0; i-- {
		off := len(a) - 1 - i

		for j := len(b) - 1; j >= 0; j-- {
			tmp := b[j] * a[i]
			r[pos-off] += tmp % 10
			r[pos-off-1] += r[pos-off]/10 + tmp/10
			r[pos-off] %= 10
			off++
		}
	}
}

func MultipleWithResult(f []int, g []int) []int {

	if len(f) < len(g) {
		t := f
		f = g
		g = t
	}

	result := make([]int, len(f)+len(g)+1)

	for j := len(g) - 1; j >= 0; j-- {
		//initially pos (index of result ) has the same relative postion as j in array
		pos := len(result) - (len(g) - j)
		for i := len(f) - 1; i >= 0; i-- {
			temp := g[j] * f[i]
			result[pos] += temp % 10
			result[pos-1] += temp / 10
			pos--
		}
		//	fmt.Println(result)
	}

	for i := len(result) - 1; i > 0; i-- {
		temp := result[i]
		result[i] = temp % 10
		result[i-1] += temp / 10
	}

	return result
}

func Divisor(n int) []int {

	nums := make([]int, 500)

	for i := 0; i < len(nums); i++ {
		nums[i] = 0
	}

	i, c := 1, 0

	for {
		if i*i > n {
			break
		}

		tmp := n % i
		if tmp == 0 {
			nums[c] = i
			// only collect 1, ingore the number itself
			if i != 1 && i != n/i {
				c++
				nums[c] = n / i
			}
		}
		i++
		c++
		//fmt.Println("c:  ", c)
	}

	return nums
}

func DivideV1(a int, b int) (int, int) {
	q, r := 0, a
	for {
		if r < b {
			break
		}

		r = r - b
		q = q + 1
	}

	return q, r
}

func QuickDivision(a int, b int) (int, int) {

	counter, power, mid, appr := 0, 1, 0, 0

	for {
		if power*b > a {
			break
		}

		counter++
		power = power * 2
	}
	p, q := power, power/2

	for k := 1; k < counter; k++ {
		comp := (p + q) / 2
		mid = comp * b

		if mid <= a {
			appr = mid
			q = comp
		} else {
			p = comp
		}
	}

	r := a - appr
	return q, r
}

// https://blog.csdn.net/gd007he/article/details/69055031
// https://blog.csdn.net/gd007he/article/details/68961974
func PostiveSub(a []int, b []int, r []int) {
	// assuem a > b

	for i := 0; i < len(r); i++ {
		r[i] = 0
	}

	al, bl := NumbericLength(a), NumbericLength(b)

	c := 0
	j := len(r) - 1
	pos, pa, pb := 0, 0, 0

	for {
		pos = len(r) - 1 - j

		pa = al - 1 - pos
		pb = bl - 1 - pos

		if c >= al && c >= bl {
			break
		}

		if pa >= 0 && pb >= 0 {
			if a[pa] > b[pb] {
				r[j] = a[pa] - b[pb]
			} else {
				r[j] = a[pa] + 10 - b[pb]
				for k := pa - 1; k >= 0; k-- {
					if a[k] == 0 {
						a[k] = 9
					} else {
						a[k] = a[k] - 1
						break
					}
				}
			}
		} else if pb < 0 {
			r[j] = a[pa]
		}

		c++
		j--
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Michael Wendland
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 *	Authors:
 * 		Michael Wendland <michael@michiwend.com>
 */

package gomusicbrainz

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"net/url"
	"reflect"
	"testing"
	"time"
)

var (
	mux    *http.ServeMux
	server *httptest.Server
	client GoMusicBrainz
)

// Init multiplexer and httptest server
func setup() {
	mux = http.NewServeMux()
	server = httptest.NewServer(mux)

	host, _ := url.Parse(server.URL)
	client = GoMusicBrainz{WS2RootURL: host}
}

// handleFunc passes response to the http client.
func handleFunc(url string, response *string, t *testing.T) {
	mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, *response)
	})
}

// serveTestFile responses to the http client with content of a file located
// in ./testdata
func serveTestFile(url string, file string, t *testing.T) {
	mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, "./testdata/"+file)
	})
}

func TestSearchArtist(t *testing.T) {

	want := []Artist{
		{
			Id:          "some-artist-id",
			Type:        "Group",
			Name:        "Gopher And Friends",
			SortName:    "0Gopher And Friends",
			CountryCode: "DE",
			Lifespan: Lifespan{
				Ended: false,
				Begin: BrainzTime{time.Date(2007, 9, 21, 0, 0, 0, 0, time.UTC)},
				End:   BrainzTime{time.Time{}},
			},
			Aliases: []Alias{
				{
					Name:     "Mr. Gopher and Friends",
					SortName: "0Mr. Gopher and Friends",
				},
				{
					Name:     "Mr Gopher and Friends",
					SortName: "0Mr Gopher and Friends",
				},
			},
		},
	}

	setup()
	defer server.Close()
	serveTestFile("/artist", "SearchArtist.xml", t)

	returned, err := client.SearchArtist("", -1, -1)
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(returned, want) {
		t.Errorf("Artists returned: %+v, want: %+v", returned, want)
	}
}

func TestSearchRelease(t *testing.T) {

	want := []Release{
		{
			Id:     "9ab1b03e-6722-4ab8-bc7f-a8722f0d34c1",
			Title:  "Fred Schneider & The Shake Society",
			Status: "official",
			TextRepresentation: TextRepresentation{
				Language: "eng",
				Script:   "latn",
			},
			ArtistCredit: ArtistCredit{
				NameCredit{
					Artist{
						Id:       "43bcca8b-9edc-4997-8343-122350e790bf",
						Name:     "Fred Schneider",
						SortName: "Schneider, Fred",
					},
				},
			},
			ReleaseGroup: ReleaseGroup{
				Type: "Album",
			},
			Date:        BrainzTime{time.Date(1991, 4, 30, 0, 0, 0, 0, time.UTC)},
			CountryCode: "us",
			Barcode:     "075992659222",
			Asin:        "075992659222",
			LabelInfos: []LabelInfo{
				{
					CatalogNumber: "9 26592-2",
					Label: Label{
						Name: "Reprise Records",
					},
				},
			},
			Mediums: []Medium{
				{
					Format: "cd",
				},
			},
		},
	}

	setup()
	defer server.Close()
	serveTestFile("/release", "SearchRelease.xml", t)

	returned, err := client.SearchRelease("", -1, -1)
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(returned, want) {
		t.Errorf("Releases returned: %+v, want: %+v", returned, want)
	}
}
<commit_msg>tests: fixes, be more verbose<commit_after>/*
 * Copyright (c) 2014 Michael Wendland
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 *	Authors:
 * 		Michael Wendland <michael@michiwend.com>
 */

package gomusicbrainz

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"net/url"
	"reflect"
	"testing"
	"time"
)

var (
	mux    *http.ServeMux
	server *httptest.Server
	client GoMusicBrainz
)

// Init multiplexer and httptest server
func setupHttpTesting() {
	mux = http.NewServeMux()
	server = httptest.NewServer(mux)

	host, _ := url.Parse(server.URL)
	client = GoMusicBrainz{WS2RootURL: host}
}

// handleFunc passes response to the http client.
func handleFunc(url string, response *string, t *testing.T) {
	mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, *response)
	})
}

// serveTestFile responses to the http client with content of a test file
// located in ./testdata
func serveTestFile(url string, testfile string, t *testing.T) {

	//TODO check request URL if it matches one of the following patterns
	//lookup:   /<ENTITY>/<MBID>?inc=<INC>
	//browse:   /<ENTITY>?<ENTITY>=<MBID>&limit=<LIMIT>&offset=<OFFSET>&inc=<INC>
	//search:   /<ENTITY>?query=<QUERY>&limit=<LIMIT>&offset=<OFFSET>

	mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
		if testing.Verbose() {
			fmt.Println("GET request:", r.URL.String())
		}

		http.ServeFile(w, r, "./testdata/"+testfile)
	})
}

func TestSearchArtist(t *testing.T) {

	want := []Artist{
		{
			Id:          "some-artist-id",
			Type:        "Group",
			Name:        "Gopher And Friends",
			SortName:    "0Gopher And Friends",
			CountryCode: "DE",
			Lifespan: Lifespan{
				Ended: false,
				Begin: BrainzTime{time.Date(2007, 9, 21, 0, 0, 0, 0, time.UTC)},
				End:   BrainzTime{time.Time{}},
			},
			Aliases: []Alias{
				{
					Name:     "Mr. Gopher and Friends",
					SortName: "0Mr. Gopher and Friends",
				},
				{
					Name:     "Mr Gopher and Friends",
					SortName: "0Mr Gopher and Friends",
				},
			},
		},
	}

	setupHttpTesting()
	defer server.Close()
	serveTestFile("/artist", "SearchArtist.xml", t)

	returned, err := client.SearchArtist("Gopher", -1, -1)
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(returned, want) {
		t.Errorf("Artists returned: %+v, want: %+v", returned, want)
	}
}

func TestSearchRelease(t *testing.T) {

	want := []Release{
		{
			Id:     "9ab1b03e-6722-4ab8-bc7f-a8722f0d34c1",
			Title:  "Fred Schneider & The Shake Society",
			Status: "official",
			TextRepresentation: TextRepresentation{
				Language: "eng",
				Script:   "latn",
			},
			ArtistCredit: ArtistCredit{
				NameCredit{
					Artist{
						Id:       "43bcca8b-9edc-4997-8343-122350e790bf",
						Name:     "Fred Schneider",
						SortName: "Schneider, Fred",
					},
				},
			},
			ReleaseGroup: ReleaseGroup{
				Type: "Album",
			},
			Date:        BrainzTime{time.Date(1991, 4, 30, 0, 0, 0, 0, time.UTC)},
			CountryCode: "us",
			Barcode:     "075992659222",
			Asin:        "075992659222",
			LabelInfos: []LabelInfo{
				{
					CatalogNumber: "9 26592-2",
					Label: Label{
						Name: "Reprise Records",
					},
				},
			},
			Mediums: []Medium{
				{
					Format: "cd",
				},
			},
		},
	}

	setupHttpTesting()
	defer server.Close()
	serveTestFile("/release", "SearchRelease.xml", t)

	returned, err := client.SearchRelease("Fred", -1, -1)
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(returned, want) {
		t.Errorf("Releases returned: %+v, want: %+v", returned, want)
	}
}
<|endoftext|>


<commit_before>package consultant

import (
	"fmt"
	"github.com/hashicorp/consul/watch"
)

const (
	updateChanLength = 100 // must exceed the maximum number of watch plans
	chanLength       = 10  // a size for all other channels
)

// A config object that implements this interface can be initialized from consul's
// KV store or from it's service list and then automatically updated as these things change in consul.
type Configurator interface {
	Update(uint64, interface{})
}

type serviceDetails struct {
	plan        *watch.Plan
	tag         string
	passingOnly bool
}

type update struct {
	index uint64
	data  interface{}
}

type ConfigChan chan Configurator

// ConfigManager keeps a private copy of the Configurator object in order to manage thread-safe access.
type ConfigManager struct {
	client        *Client                    // a consultant client
	config        Configurator               // private copy
	prefixPlans   map[string]*watch.Plan     // the prefixes we are managing
	servicePlans  map[string]*serviceDetails // services we are managing
	subscriptions map[ConfigChan]bool        // user can subscribe to updates
	seedChan      ConfigChan
	readChan      chan ConfigChan
	updateChan    chan update
	syncChan      chan chan chan bool
	stopChan      chan bool
}

// NewConfigManager creates a new instance and kicks off a manager for it
func (c *Client) NewConfigManager(config Configurator) *ConfigManager {

	cm := &ConfigManager{
		client:        c,
		config:        config,
		prefixPlans:   make(map[string]*watch.Plan),
		servicePlans:  make(map[string]*serviceDetails),
		subscriptions: make(map[ConfigChan]bool),
		seedChan:      make(ConfigChan, chanLength),
		readChan:      make(chan ConfigChan, chanLength),
		updateChan:    make(chan update, updateChanLength),
		syncChan:      make(chan chan chan bool),
		stopChan:      make(chan bool, 1),
	}

	// send in the config first so this is the first thing the handler sees
	cm.Seed(config)

	cm.configHandler()

	return cm
}

// Seed replaces the config handled by cm and updates the consul-dependent information
func (cm *ConfigManager) Seed(config Configurator) {
	cm.seedChan <- config
}

// Read retrieves the current configuration
func (cm *ConfigManager) Read() Configurator {
	req := make(ConfigChan)
	cm.readChan <- req
	return <-req
}

// Refresh all updates (in preparation for a read)
func (cm *ConfigManager) Refresh() *ConfigManager {
	sync := cm.pause()
	cm.updateAll()
	unpause(sync)
	return cm
}

func (cm *ConfigManager) configHandler() {
	go func() { //  make sure the handler is running before we return
	loop:
		for {
			select {

			// initialize the config object with non-consul items
			case seed := <-cm.seedChan:
				//log.Println("seedChan")
				cm.config = seed
				cm.updateAll()

			// request to get a copy of the config
			case req := <-cm.readChan:
				// Handle all updates before we serve the config back (push request back on channel)
				if len(cm.updateChan) > 0 {
					cm.readChan <- req
				} else {
					req <- cm.config
				}

			// updates are processed here
			case u := <-cm.updateChan:
				//log.Println("updateChan")
				cm.config.Update(u.index, u.data) // user-defined handling

				// Serve subscribers once all updates have been processed
				if len(cm.updateChan) == 0 {
					cm.handleSubscriptions()
				}

			// provide a means to pause the handler
			case ch := <-cm.syncChan:
				//log.Println("syncChan")
				c1 := make(chan bool)
				ch <- c1 // say: do your work now
				<-c1     // wait until ready to move on again

			case <-cm.stopChan:
				//log.Println("stopChan")
				cm.cleanup()
				break loop
			}
		}
		log.Println("Exiting the handler")
	}()
}

// Trigger all updates
func (cm *ConfigManager) updateAll() {
	for prefix := range cm.prefixPlans {
		cm.updateKVPrefix(prefix)
	}
	for service, details := range cm.servicePlans {
		cm.updateService(service, details.tag, details.passingOnly)
	}
}

// transform a callback to a channel push
func (cm *ConfigManager) updateHandler(index uint64, data interface{}) {
	cm.updateChan <- update{
		index: index,
		data:  data,
	}
}

// Subscribe returns a channel that will send updates about the config
func (cm *ConfigManager) Subscribe() ConfigChan {
	ch := make(ConfigChan, 1)
	cm.subscriptions[ch] = true
	return ch
}

// Unsubscribe from channel updates by passing the channel here.
func (cm *ConfigManager) Unsubscribe(ch ConfigChan) {
	_, ok := cm.subscriptions[ch]
	if ok {
		delete(cm.subscriptions, ch)
	}
}

func (cm *ConfigManager) handleSubscriptions() {
	for ch := range cm.subscriptions {
		// Replace current item in the queue if there is something there
		if len(ch) == 1 {
			<-ch
		}
		ch <- cm.config
	}
}

// Stop shuts down the plans, channels, and the handler
func (cm *ConfigManager) Stop() {
	cm.stopChan <- true
}

// pause pauses the handler while we do some otherwise thread-unsafe stuff
func (cm *ConfigManager) pause() chan bool {
	c2 := make(chan chan bool)
	cm.syncChan <- c2
	return <-c2
}

// unpause tells the handler that it is okay to resume normal operations
func unpause(sync chan bool) {
	sync <- true
}

// AddKvPrefix starts watching the given prefix and updates the config with current values
func (cm *ConfigManager) AddKVPrefix(prefix string) error {

	var err error

	sync := cm.pause()
	defer unpause(sync)

	wp, ok := cm.prefixPlans[prefix]
	if ok {
		wp.Stop()
	}

	wp, err = cm.client.WatchKeyPrefix(prefix, true, cm.updateHandler)
	if err != nil {
		return fmt.Errorf("Trouble building the watch plan: %s", err)
	}

	go func() {
		err := wp.Run(cm.client.config.Address)
		if err != nil {
			log.Printf("Watch plan failed for prefix: %s", prefix)
		}
	}()

	cm.prefixPlans[prefix] = wp

	return nil
}

// AddService starts watching the specified service and updates the config
func (cm *ConfigManager) AddService(service, tag string, passingOnly bool) error {

	var err error

	sync := cm.pause()
	defer unpause(sync)

	details, ok := cm.servicePlans[service]
	if ok {
		details.plan.Stop()
	}

	details = &serviceDetails{
		tag:         tag,
		passingOnly: passingOnly,
	}

	details.plan, err = cm.client.WatchService(service, tag, passingOnly, true, cm.updateHandler)
	if err != nil {
		return fmt.Errorf("Trouble building the watch plan: %s", err)
	}

	go func() {
		err := details.plan.Run(cm.client.config.Address)
		if err != nil {
			fmt.Fprintf(details.plan.LogOutput, "Watch plan failed for service: %s", service)
		}
	}()

	cm.servicePlans[service] = details

	return nil
}

// updateKVPrefix - list kv:s in the prefix and update our config with the result
func (cm *ConfigManager) updateKVPrefix(prefix string) error {
	kvps, _, err := cm.client.KV().List(prefix, nil)
	if err != nil {
		return fmt.Errorf("Trouble getting the KVs under: %s", prefix)
	}
	cm.updateHandler(0, kvps)

	return nil
}

// updateService lists current services and forces an update
func (cm *ConfigManager) updateService(service, tag string, passingOnly bool) error {
	seList, _, err := cm.client.Health().Service(service, tag, passingOnly, nil)
	if err != nil {
		return fmt.Errorf("Trouble finding a passing service for %s (tag=%s)", service, tag)
	}
	cm.updateHandler(0, seList)

	return nil
}

// cleanup frees up resources in the ConfigManager
func (cm *ConfigManager) cleanup() {

	// Shut down the watch plans
	for _, details := range cm.servicePlans {
		details.plan.Stop()
	}

	// Close subscriber channels
	for ch := range cm.subscriptions {
		close(ch)
	}
}
<commit_msg>added stop for prefix watcher<commit_after>package consultant

import (
	"fmt"
	"github.com/hashicorp/consul/watch"
)

const (
	updateChanLength = 100 // must exceed the maximum number of watch plans
	chanLength       = 10  // a size for all other channels
)

// A config object that implements this interface can be initialized from consul's
// KV store or from it's service list and then automatically updated as these things change in consul.
type Configurator interface {
	Update(uint64, interface{})
}

type serviceDetails struct {
	plan        *watch.Plan
	tag         string
	passingOnly bool
}

type update struct {
	index uint64
	data  interface{}
}

type ConfigChan chan Configurator

// ConfigManager keeps a private copy of the Configurator object in order to manage thread-safe access.
type ConfigManager struct {
	client        *Client                    // a consultant client
	config        Configurator               // private copy
	prefixPlans   map[string]*watch.Plan     // the prefixes we are managing
	servicePlans  map[string]*serviceDetails // services we are managing
	subscriptions map[ConfigChan]bool        // user can subscribe to updates
	seedChan      ConfigChan
	readChan      chan ConfigChan
	updateChan    chan update
	syncChan      chan chan chan bool
	stopChan      chan bool
}

// NewConfigManager creates a new instance and kicks off a manager for it
func (c *Client) NewConfigManager(config Configurator) *ConfigManager {

	cm := &ConfigManager{
		client:        c,
		config:        config,
		prefixPlans:   make(map[string]*watch.Plan),
		servicePlans:  make(map[string]*serviceDetails),
		subscriptions: make(map[ConfigChan]bool),
		seedChan:      make(ConfigChan, chanLength),
		readChan:      make(chan ConfigChan, chanLength),
		updateChan:    make(chan update, updateChanLength),
		syncChan:      make(chan chan chan bool),
		stopChan:      make(chan bool, 1),
	}

	// send in the config first so this is the first thing the handler sees
	cm.Seed(config)

	cm.configHandler()

	return cm
}

// Seed replaces the config handled by cm and updates the consul-dependent information
func (cm *ConfigManager) Seed(config Configurator) {
	cm.seedChan <- config
}

// Read retrieves the current configuration
func (cm *ConfigManager) Read() Configurator {
	req := make(ConfigChan)
	cm.readChan <- req
	return <-req
}

// Refresh all updates (in preparation for a read)
func (cm *ConfigManager) Refresh() *ConfigManager {
	sync := cm.pause()
	cm.updateAll()
	unpause(sync)
	return cm
}

func (cm *ConfigManager) configHandler() {
	go func() { //  make sure the handler is running before we return
	loop:
		for {
			select {

			// initialize the config object with non-consul items
			case seed := <-cm.seedChan:
				//log.Println("seedChan")
				cm.config = seed
				cm.updateAll()

			// request to get a copy of the config
			case req := <-cm.readChan:
				// Handle all updates before we serve the config back (push request back on channel)
				if len(cm.updateChan) > 0 {
					cm.readChan <- req
				} else {
					req <- cm.config
				}

			// updates are processed here
			case u := <-cm.updateChan:
				//log.Println("updateChan")
				cm.config.Update(u.index, u.data) // user-defined handling

				// Serve subscribers once all updates have been processed
				if len(cm.updateChan) == 0 {
					cm.handleSubscriptions()
				}

			// provide a means to pause the handler
			case ch := <-cm.syncChan:
				//log.Println("syncChan")
				c1 := make(chan bool)
				ch <- c1 // say: do your work now
				<-c1     // wait until ready to move on again

			case <-cm.stopChan:
				//log.Println("stopChan")
				cm.cleanup()
				break loop
			}
		}
		log.Println("Exiting the handler")
	}()
}

// Trigger all updates
func (cm *ConfigManager) updateAll() {
	for prefix := range cm.prefixPlans {
		cm.updateKVPrefix(prefix)
	}
	for service, details := range cm.servicePlans {
		cm.updateService(service, details.tag, details.passingOnly)
	}
}

// transform a callback to a channel push
func (cm *ConfigManager) updateHandler(index uint64, data interface{}) {
	cm.updateChan <- update{
		index: index,
		data:  data,
	}
}

// Subscribe returns a channel that will send updates about the config
func (cm *ConfigManager) Subscribe() ConfigChan {
	ch := make(ConfigChan, 1)
	cm.subscriptions[ch] = true
	return ch
}

// Unsubscribe from channel updates by passing the channel here.
func (cm *ConfigManager) Unsubscribe(ch ConfigChan) {
	_, ok := cm.subscriptions[ch]
	if ok {
		delete(cm.subscriptions, ch)
	}
}

func (cm *ConfigManager) handleSubscriptions() {
	for ch := range cm.subscriptions {
		// Replace current item in the queue if there is something there
		if len(ch) == 1 {
			<-ch
		}
		ch <- cm.config
	}
}

// Stop shuts down the plans, channels, and the handler
func (cm *ConfigManager) Stop() {
	cm.stopChan <- true
}

// pause pauses the handler while we do some otherwise thread-unsafe stuff
func (cm *ConfigManager) pause() chan bool {
	c2 := make(chan chan bool)
	cm.syncChan <- c2
	return <-c2
}

// unpause tells the handler that it is okay to resume normal operations
func unpause(sync chan bool) {
	sync <- true
}

// AddKvPrefix starts watching the given prefix and updates the config with current values
func (cm *ConfigManager) AddKVPrefix(prefix string) error {

	var err error

	sync := cm.pause()
	defer unpause(sync)

	wp, ok := cm.prefixPlans[prefix]
	if ok {
		wp.Stop()
	}

	wp, err = cm.client.WatchKeyPrefix(prefix, true, cm.updateHandler)
	if err != nil {
		return fmt.Errorf("Trouble building the watch plan: %s", err)
	}

	go func() {
		err := wp.Run(cm.client.config.Address)
		if err != nil {
			log.Printf("Watch plan failed for prefix: %s", prefix)
		}
	}()

	cm.prefixPlans[prefix] = wp

	return nil
}

// AddService starts watching the specified service and updates the config
func (cm *ConfigManager) AddService(service, tag string, passingOnly bool) error {

	var err error

	sync := cm.pause()
	defer unpause(sync)

	details, ok := cm.servicePlans[service]
	if ok {
		details.plan.Stop()
	}

	details = &serviceDetails{
		tag:         tag,
		passingOnly: passingOnly,
	}

	details.plan, err = cm.client.WatchService(service, tag, passingOnly, true, cm.updateHandler)
	if err != nil {
		return fmt.Errorf("Trouble building the watch plan: %s", err)
	}

	go func() {
		err := details.plan.Run(cm.client.config.Address)
		if err != nil {
			fmt.Fprintf(details.plan.LogOutput, "Watch plan failed for service: %s", service)
		}
	}()

	cm.servicePlans[service] = details

	return nil
}

// updateKVPrefix - list kv:s in the prefix and update our config with the result
func (cm *ConfigManager) updateKVPrefix(prefix string) error {
	kvps, _, err := cm.client.KV().List(prefix, nil)
	if err != nil {
		return fmt.Errorf("Trouble getting the KVs under: %s", prefix)
	}
	cm.updateHandler(0, kvps)

	return nil
}

// updateService lists current services and forces an update
func (cm *ConfigManager) updateService(service, tag string, passingOnly bool) error {
	seList, _, err := cm.client.Health().Service(service, tag, passingOnly, nil)
	if err != nil {
		return fmt.Errorf("Trouble finding a passing service for %s (tag=%s)", service, tag)
	}
	cm.updateHandler(0, seList)

	return nil
}

// cleanup frees up resources in the ConfigManager
func (cm *ConfigManager) cleanup() {

	// Shut down the watch plans
	for _, details := range cm.servicePlans {
		details.plan.Stop()
	}

	for _, details := range cm.prefixPlans {
		details.Stop()
	}

	// Close subscriber channels
	for ch := range cm.subscriptions {
		close(ch)
	}
}
<|endoftext|>


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

// +build go1.8

package xorm

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestPingContext(t *testing.T) {
	assert.NoError(t, prepareEngine())

	// TODO: Since EngineInterface should be compitable with old Go version, PingContext is not supported.
	/*
		ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
		err := testEngine.PingContext(ctx)
		assert.NoError(t, err)
	*/
}
<commit_msg>PingContext test<commit_after>// Copyright 2017 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build go1.8

package xorm

import (
	"context"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestPingContext(t *testing.T) {
	assert.NoError(t, prepareEngine())

	ctx, canceled := context.WithTimeout(context.Background(), 10*time.Second)
	defer canceled()

	err := testEngine.(*Engine).PingContext(ctx)
	assert.NoError(t, err)

	// TODO: Since EngineInterface should be compitable with old Go version, PingContext is not supported.
	/*
		ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
		err := testEngine.PingContext(ctx)
		assert.NoError(t, err)
	*/
}
<|endoftext|>


<commit_before>package gqltesting

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"reflect"
	"sort"
	"strconv"
	"testing"

	graphql "github.com/graph-gophers/graphql-go"
	"github.com/graph-gophers/graphql-go/errors"
)

// Test is a GraphQL test case to be used with RunTest(s).
type Test struct {
	Context        context.Context
	Schema         *graphql.Schema
	Query          string
	OperationName  string
	Variables      map[string]interface{}
	ExpectedResult string
	ExpectedErrors []*errors.QueryError
	RawResponse    bool
}

// RunTests runs the given GraphQL test cases as subtests.
func RunTests(t *testing.T, tests []*Test) {
	if len(tests) == 1 {
		RunTest(t, tests[0])
		return
	}

	for i, test := range tests {
		t.Run(strconv.Itoa(i+1), func(t *testing.T) {
			RunTest(t, test)
		})
	}
}

// RunTest runs a single GraphQL test case.
func RunTest(t *testing.T, test *Test) {
	if test.Context == nil {
		test.Context = context.Background()
	}
	result := test.Schema.Exec(test.Context, test.Query, test.OperationName, test.Variables)

	checkErrors(t, test.ExpectedErrors, result.Errors)

	if test.ExpectedResult == "" {
		if result.Data != nil {
			t.Fatalf("got: %s", result.Data)
			t.Fatalf("want: null")
		}
		return
	}

	// Verify JSON to avoid red herring errors.
	var got []byte

	if test.RawResponse {
		value, err := result.Data.MarshalJSON()
		if err != nil {
			t.Fatalf("got: unable to marshal JSON response: %s", err)
		}
		got = value
	} else {
		value, err := formatJSON(result.Data)
		if err != nil {
			t.Fatalf("got: invalid JSON: %s", err)
		}
		got = value
	}

	want, err := formatJSON([]byte(test.ExpectedResult))
	if err != nil {
		t.Fatalf("want: invalid JSON: %s", err)
	}

	if !bytes.Equal(got, want) {
		t.Logf("got:  %s", got)
		t.Logf("want: %s", want)
		t.Fail()
	}
}

func formatJSON(data []byte) ([]byte, error) {
	var v interface{}
	if err := json.Unmarshal(data, &v); err != nil {
		return nil, err
	}
	formatted, err := json.Marshal(v)
	if err != nil {
		return nil, err
	}
	return formatted, nil
}

func checkErrors(t *testing.T, want, got []*errors.QueryError) {
	sortErrors(want)
	sortErrors(got)

	if !reflect.DeepEqual(got, want) {
		t.Fatalf("unexpected error: got %+v, want %+v", got, want)
	}
}

func sortErrors(errors []*errors.QueryError) {
	if len(errors) <= 1 {
		return
	}
	sort.Slice(errors, func(i, j int) bool {
		return fmt.Sprintf("%s", errors[i].Path) < fmt.Sprintf("%s", errors[j].Path)
	})
}
<commit_msg>checkErrors ignores the raw error for purposes of determining if the test passed or failed<commit_after>package gqltesting

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"reflect"
	"sort"
	"strconv"
	"testing"

	graphql "github.com/graph-gophers/graphql-go"
	"github.com/graph-gophers/graphql-go/errors"
)

// Test is a GraphQL test case to be used with RunTest(s).
type Test struct {
	Context        context.Context
	Schema         *graphql.Schema
	Query          string
	OperationName  string
	Variables      map[string]interface{}
	ExpectedResult string
	ExpectedErrors []*errors.QueryError
	RawResponse    bool
}

// RunTests runs the given GraphQL test cases as subtests.
func RunTests(t *testing.T, tests []*Test) {
	if len(tests) == 1 {
		RunTest(t, tests[0])
		return
	}

	for i, test := range tests {
		t.Run(strconv.Itoa(i+1), func(t *testing.T) {
			RunTest(t, test)
		})
	}
}

// RunTest runs a single GraphQL test case.
func RunTest(t *testing.T, test *Test) {
	if test.Context == nil {
		test.Context = context.Background()
	}
	result := test.Schema.Exec(test.Context, test.Query, test.OperationName, test.Variables)

	checkErrors(t, test.ExpectedErrors, result.Errors)

	if test.ExpectedResult == "" {
		if result.Data != nil {
			t.Fatalf("got: %s", result.Data)
			t.Fatalf("want: null")
		}
		return
	}

	// Verify JSON to avoid red herring errors.
	var got []byte

	if test.RawResponse {
		value, err := result.Data.MarshalJSON()
		if err != nil {
			t.Fatalf("got: unable to marshal JSON response: %s", err)
		}
		got = value
	} else {
		value, err := formatJSON(result.Data)
		if err != nil {
			t.Fatalf("got: invalid JSON: %s", err)
		}
		got = value
	}

	want, err := formatJSON([]byte(test.ExpectedResult))
	if err != nil {
		t.Fatalf("want: invalid JSON: %s", err)
	}

	if !bytes.Equal(got, want) {
		t.Logf("got:  %s", got)
		t.Logf("want: %s", want)
		t.Fail()
	}
}

func formatJSON(data []byte) ([]byte, error) {
	var v interface{}
	if err := json.Unmarshal(data, &v); err != nil {
		return nil, err
	}
	formatted, err := json.Marshal(v)
	if err != nil {
		return nil, err
	}
	return formatted, nil
}

func checkErrors(t *testing.T, want, got []*errors.QueryError) {
	sortErrors(want)
	sortErrors(got)

	// Clear the underlying error before the DeepEqual check.  It's too
	// much to ask the tester to include the raw failing error.
	for _, err := range got {
		err.Err = nil
	}

	if !reflect.DeepEqual(got, want) {
		t.Fatalf("unexpected error: got %+v, want %+v", got, want)
	}
}

func sortErrors(errors []*errors.QueryError) {
	if len(errors) <= 1 {
		return
	}
	sort.Slice(errors, func(i, j int) bool {
		return fmt.Sprintf("%s", errors[i].Path) < fmt.Sprintf("%s", errors[j].Path)
	})
}
<|endoftext|>


<commit_before>package gqltesting

import (
	"bytes"
	"context"
	"encoding/json"
	"strconv"
	"testing"

	graphql "github.com/neelance/graphql-go"
)

// Test is a GraphQL test case to be used with RunTest(s).
type Test struct {
	Schema         *graphql.Schema
	Query          string
	OperationName  string
	Variables      map[string]interface{}
	ExpectedResult string
}

// RunTests runs the given GraphQL test cases as subtests.
func RunTests(t *testing.T, tests []*Test) {
	if len(tests) == 1 {
		RunTest(t, tests[0])
		return
	}

	for i, test := range tests {
		t.Run(strconv.Itoa(i+1), func(t *testing.T) {
			RunTest(t, test)
		})
	}
}

// RunTest runs a single GraphQL test case.
func RunTest(t *testing.T, test *Test) {
	result := test.Schema.Exec(context.Background(), test.Query, test.OperationName, test.Variables)
	if len(result.Errors) != 0 {
		t.Fatal(result.Errors[0])
	}
	got := formatJSON(t, result.Data)

	want := formatJSON(t, []byte(test.ExpectedResult))

	if !bytes.Equal(got, want) {
		t.Logf("got:  %s", got)
		t.Logf("want: %s", want)
		t.Fail()
	}
}

func formatJSON(t *testing.T, data []byte) []byte {
	var v interface{}
	if err := json.Unmarshal(data, &v); err != nil {
		t.Fatalf("invalid JSON: %s", err)
	}
	formatted, err := json.Marshal(v)
	if err != nil {
		t.Fatal(err)
	}
	return formatted
}
<commit_msg>Support context injection in testing<commit_after>package gqltesting

import (
	"bytes"
	"context"
	"encoding/json"
	"strconv"
	"testing"

	graphql "github.com/neelance/graphql-go"
)

// Test is a GraphQL test case to be used with RunTest(s).
type Test struct {
	Context        context.Context
	Schema         *graphql.Schema
	Query          string
	OperationName  string
	Variables      map[string]interface{}
	ExpectedResult string
}

// RunTests runs the given GraphQL test cases as subtests.
func RunTests(t *testing.T, tests []*Test) {
	if len(tests) == 1 {
		RunTest(t, tests[0])
		return
	}

	for i, test := range tests {
		t.Run(strconv.Itoa(i+1), func(t *testing.T) {
			RunTest(t, test)
		})
	}
}

// RunTest runs a single GraphQL test case.
func RunTest(t *testing.T, test *Test) {
	if test.Context == nil {
		test.Context = context.Background()
	}
	result := test.Schema.Exec(test.Context, test.Query, test.OperationName, test.Variables)
	if len(result.Errors) != 0 {
		t.Fatal(result.Errors[0])
	}
	got := formatJSON(t, result.Data)

	want := formatJSON(t, []byte(test.ExpectedResult))

	if !bytes.Equal(got, want) {
		t.Logf("got:  %s", got)
		t.Logf("want: %s", want)
		t.Fail()
	}
}

func formatJSON(t *testing.T, data []byte) []byte {
	var v interface{}
	if err := json.Unmarshal(data, &v); err != nil {
		t.Fatalf("invalid JSON: %s", err)
	}
	formatted, err := json.Marshal(v)
	if err != nil {
		t.Fatal(err)
	}
	return formatted
}
<|endoftext|>


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

// author           tolsen
// author-github    https://github.com/tolsen
//
// repository-name  gojsonschema
// repository-desc  An implementation of JSON Schema, based on IETF's draft v4 - Go language.
//
// description      Implements a persistent (immutable w/ shared structure) singly-linked list of strings for the purpose of storing a json context
//
// created          04-09-2013

package gojsonschema

import "bytes"

// jsonContext implements a persistent linked-list of strings
type jsonContext struct {
	head string
	tail *jsonContext
}

func newJsonContext(head string, tail *jsonContext) *jsonContext {
	return &jsonContext{head, tail}
}

// String displays the context in reverse.
// This plays well with the data structure's persistent nature with
// Cons and a json document's tree structure.
func (c *jsonContext) String() string {
	byteArr := make([]byte, 0, c.stringLen())
	buf := bytes.NewBuffer(byteArr)
	c.writeStringToBuffer(buf)

	return buf.String()
}

func (c *jsonContext) stringLen() int {
	length := 0
	if c.tail != nil {
		length = c.tail.stringLen() + 1 // add 1 for "."
	}

	length += len(c.head)
	return length
}

func (c *jsonContext) writeStringToBuffer(buf *bytes.Buffer) {
	if c.tail != nil {
		c.tail.writeStringToBuffer(buf)
		buf.WriteString(".")
	}

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

// author           tolsen
// author-github    https://github.com/tolsen
//
// repository-name  gojsonschema
// repository-desc  An implementation of JSON Schema, based on IETF's draft v4 - Go language.
//
// description      Implements a persistent (immutable w/ shared structure) singly-linked list of strings for the purpose of storing a json context
//
// created          04-09-2013

package gojsonschema

import "bytes"

// jsonContext implements a persistent linked-list of strings
type jsonContext struct {
	head string
	tail *jsonContext
}

func newJsonContext(head string, tail *jsonContext) *jsonContext {
	return &jsonContext{head, tail}
}

// String displays the context in reverse.
// This plays well with the data structure's persistent nature with
// Cons and a json document's tree structure.
func (c *jsonContext) String(del ...string) string {
	byteArr := make([]byte, 0, c.stringLen())
	buf := bytes.NewBuffer(byteArr)
	c.writeStringToBuffer(buf, del)

	return buf.String()
}

func (c *jsonContext) stringLen() int {
	length := 0
	if c.tail != nil {
		length = c.tail.stringLen() + 1 // add 1 for "."
	}

	length += len(c.head)
	return length
}

func (c *jsonContext) writeStringToBuffer(buf *bytes.Buffer, del []string) {
	if c.tail != nil {
		c.tail.writeStringToBuffer(buf, del)

		if len(del) > 0 {
			buf.WriteString(del[0])
		} else {
			buf.WriteString(".")
		}
	}

	buf.WriteString(c.head)
}
<|endoftext|>


<commit_before>// Copyright 2012 tsuru 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 juju

import (
	"bytes"
	"regexp"
)

// FilterOutput filters output from juju.
//
// It removes all lines that does not represent useful output, like juju's
// logging and Python's deprecation warnings.
func FilterOutput(output []byte) []byte {
	var result [][]byte
	var ignore bool
	deprecation := []byte("DeprecationWarning")
	regexLog := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}`)
	regexSshWarning := regexp.MustCompile(`^Warning: Permanently added`)
	regexPythonWarning := regexp.MustCompile(`^.*warnings.warn`)
	regexUserWarning := regexp.MustCompile(`^.*UserWarning`)
	lines := bytes.Split(output, []byte{'\n'})
	for _, line := range lines {
		if ignore {
			ignore = false
			continue
		}
		if bytes.Contains(line, deprecation) {
			ignore = true
			continue
		}
		if !regexSshWarning.Match(line) && !regexLog.Match(line) && !regexPythonWarning.Match(line) && !regexUserWarning.Match(line) {
			result = append(result, line)
		}
	}
	return bytes.Join(result, []byte{'\n'})
}
<commit_msg>added a doc for juju package<commit_after>// Copyright 2012 tsuru 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 juju provide utilities functions for handle with juju .
package juju

import (
	"bytes"
	"regexp"
)

// FilterOutput filters output from juju.
//
// It removes all lines that does not represent useful output, like juju's
// logging and Python's deprecation warnings.
func FilterOutput(output []byte) []byte {
	var result [][]byte
	var ignore bool
	deprecation := []byte("DeprecationWarning")
	regexLog := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}`)
	regexSshWarning := regexp.MustCompile(`^Warning: Permanently added`)
	regexPythonWarning := regexp.MustCompile(`^.*warnings.warn`)
	regexUserWarning := regexp.MustCompile(`^.*UserWarning`)
	lines := bytes.Split(output, []byte{'\n'})
	for _, line := range lines {
		if ignore {
			ignore = false
			continue
		}
		if bytes.Contains(line, deprecation) {
			ignore = true
			continue
		}
		if !regexSshWarning.Match(line) && !regexLog.Match(line) && !regexPythonWarning.Match(line) && !regexUserWarning.Match(line) {
			result = append(result, line)
		}
	}
	return bytes.Join(result, []byte{'\n'})
}
<|endoftext|>


<commit_before>package core

import "github.com/spf13/cobra"

var ConnectCommand = &cobra.Command{
	Use:   "connect",
	Short: "Connect to GitHub",
	Long:  `Filler`,

	Run: func(cmd *cobra.Command, args []string) {

	},
}

var PushCommand = &cobra.Command{
	Use:   "push",
	Short: "Upload repository",
	Long:  `Filler`,

	Run: func(cmd *cobra.Command, args []string) {

	},
}

var GetCommand = &cobra.Command{
	Use:   "get",
	Short: "Fetch repository",
	Long:  `Filler`,

	Run: func(cmd *cobra.Command, args []string) {

	},
}

// Add to plugins?
var UnpackCommand = &cobra.Command{
	Use:   "unpack",
	Short: "Open compressed storage",
	Long:  `Filler`,

	Run: func(cmd *cobra.Command, args []string) {

	},
}

var PackCommand = &cobra.Command{
	Use:   "pack",
	Short: "Pack storage to compressed file",
	Long:  `Filler`,

	Run: func(cmd *cobra.Command, args []string) {

	},
}
<commit_msg>Add Backup/Restore commands.<commit_after>package core

import "github.com/spf13/cobra"

var ConnectCommand = &cobra.Command{
	Use:   "connect",
	Short: "Connect to GitHub",
	Long:  `Filler`,

	Run: func(cmd *cobra.Command, args []string) {

	},
}

var PushCommand = &cobra.Command{
	Use:   "push",
	Short: "Upload repository",
	Long:  `Filler`,

	Run: func(cmd *cobra.Command, args []string) {

	},
}

var GetCommand = &cobra.Command{
	Use:   "get",
	Short: "Fetch repository",
	Long:  `Filler`,

	Run: func(cmd *cobra.Command, args []string) {

	},
}

var BackupCommand = &cobra.Command{
	Use:   "backup",
	Short: "Backup configuration to storage",
	Long:  `Filler`,

	Run: func(cmd *cobra.Command, args []string) {

	},
}

var RestoreCommand = &cobra.Command{
	Use:   "restore",
	Short: "Restore configuration from storage",
	Long:  `Filler`,

	Run: func(cmd *cobra.Command, args []string) {

	},
}

// Add to plugins?
var UnpackCommand = &cobra.Command{
	Use:   "unpack",
	Short: "Open compressed storage",
	Long:  `Filler`,

	Run: func(cmd *cobra.Command, args []string) {

	},
}

var PackCommand = &cobra.Command{
	Use:   "pack",
	Short: "Pack storage to compressed file",
	Long:  `Filler`,

	Run: func(cmd *cobra.Command, args []string) {

	},
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The cert-manager 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 trigger

import (
	"context"
	"time"

	"github.com/go-logr/logr"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/informers"
	corelisters "k8s.io/client-go/listers/core/v1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"
	"k8s.io/client-go/util/workqueue"
	"k8s.io/utils/clock"

	apiutil "github.com/jetstack/cert-manager/pkg/api/util"
	cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
	cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
	cmclient "github.com/jetstack/cert-manager/pkg/client/clientset/versioned"
	cminformers "github.com/jetstack/cert-manager/pkg/client/informers/externalversions"
	cmlisters "github.com/jetstack/cert-manager/pkg/client/listers/certmanager/v1"
	controllerpkg "github.com/jetstack/cert-manager/pkg/controller"
	"github.com/jetstack/cert-manager/pkg/controller/certificates"
	"github.com/jetstack/cert-manager/pkg/controller/certificates/trigger/policies"
	logf "github.com/jetstack/cert-manager/pkg/logs"
	"github.com/jetstack/cert-manager/pkg/scheduler"
	"github.com/jetstack/cert-manager/pkg/util/predicate"
)

const (
	ControllerName = "CertificateTrigger"

	// the amount of time after the LastFailureTime of a Certificate
	// before the request should be retried.
	// In future this should be replaced with a more dynamic exponential
	// back-off algorithm.
	retryAfterLastFailure = time.Hour
)

// This controller observes the state of the certificate's currently
// issued `spec.secretName` and the rest of the `certificate.spec` fields to
// determine whether a re-issuance is required.
// It triggers re-issuance by adding the `Issuing` status condition when a new
// certificate is required.
type controller struct {
	certificateLister        cmlisters.CertificateLister
	certificateRequestLister cmlisters.CertificateRequestLister
	secretLister             corelisters.SecretLister
	client                   cmclient.Interface
	recorder                 record.EventRecorder
	scheduledWorkQueue       scheduler.ScheduledWorkQueue

	// The following is used for testing purposes.
	clock              clock.Clock
	shouldReissue      policies.Func
	dataForCertificate func(context.Context, *cmapi.Certificate) (policies.Input, error)
}

func NewController(
	log logr.Logger,
	client cmclient.Interface,
	factory informers.SharedInformerFactory,
	cmFactory cminformers.SharedInformerFactory,
	recorder record.EventRecorder,
	clock clock.Clock,
	shouldReissue policies.Func,
) (*controller, workqueue.RateLimitingInterface, []cache.InformerSynced) {
	// create a queue used to queue up items to be processed
	queue := workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(time.Second*1, time.Second*30), ControllerName)

	// obtain references to all the informers used by this controller
	certificateInformer := cmFactory.Certmanager().V1().Certificates()
	certificateRequestInformer := cmFactory.Certmanager().V1().CertificateRequests()
	secretsInformer := factory.Core().V1().Secrets()

	certificateInformer.Informer().AddEventHandler(&controllerpkg.QueuingEventHandler{Queue: queue})

	// When a CertificateRequest resource changes, enqueue the Certificate resource that owns it.
	certificateRequestInformer.Informer().AddEventHandler(&controllerpkg.BlockingEventHandler{
		WorkFunc: certificates.EnqueueCertificatesForResourceUsingPredicates(log, queue, certificateInformer.Lister(), labels.Everything(), predicate.ResourceOwnerOf),
	})
	// When a Secret resource changes, enqueue any Certificate resources that name it as spec.secretName.
	secretsInformer.Informer().AddEventHandler(&controllerpkg.BlockingEventHandler{
		// Trigger reconciles on changes to the Secret named `spec.secretName`
		WorkFunc: certificates.EnqueueCertificatesForResourceUsingPredicates(log, queue, certificateInformer.Lister(), labels.Everything(),
			predicate.ExtractResourceName(predicate.CertificateSecretName)),
	})

	// build a list of InformerSynced functions that will be returned by the Register method.
	// the controller will only begin processing items once all of these informers have synced.
	mustSync := []cache.InformerSynced{
		certificateRequestInformer.Informer().HasSynced,
		secretsInformer.Informer().HasSynced,
		certificateInformer.Informer().HasSynced,
	}

	return &controller{
		certificateLister:        certificateInformer.Lister(),
		certificateRequestLister: certificateRequestInformer.Lister(),
		secretLister:             secretsInformer.Lister(),
		client:                   client,
		recorder:                 recorder,
		scheduledWorkQueue:       scheduler.NewScheduledWorkQueue(clock, queue.Add),

		// The following is used for testing purposes.
		clock:         clock,
		shouldReissue: shouldReissue,
		dataForCertificate: (&policies.Gatherer{
			CertificateRequestLister: certificateRequestInformer.Lister(),
			SecretLister:             secretsInformer.Lister(),
		}).DataForCertificate,
	}, queue, mustSync
}

func (c *controller) ProcessItem(ctx context.Context, key string) error {
	log := logf.FromContext(ctx).WithValues("key", key)
	ctx = logf.NewContext(ctx, log)
	namespace, name, err := cache.SplitMetaNamespaceKey(key)
	if err != nil {
		log.Error(err, "invalid resource key passed to ProcessItem")
		return nil
	}

	crt, err := c.certificateLister.Certificates(namespace).Get(name)
	if apierrors.IsNotFound(err) {
		log.Error(err, "certificate not found for key")
		return nil
	}
	if err != nil {
		return err
	}
	if apiutil.CertificateHasCondition(crt, cmapi.CertificateCondition{
		Type:   cmapi.CertificateConditionIssuing,
		Status: cmmeta.ConditionTrue,
	}) {
		// Do nothing if an issuance is already in progress.
		return nil
	}

	input, err := c.dataForCertificate(ctx, crt)
	if err != nil {
		return err
	}

	// Back off from re-issuing immediately when the certificate has been
	// in failing mode for less than 1 hour.
	backoff, delay := shouldBackoffReissuingOnFailure(log, c.clock, input.Certificate)
	if backoff {
		log.V(logf.InfoLevel).Info("Not re-issuing certificate as an attempt has been made in the last hour", "retry_delay", delay)
		c.scheduleRecheckOfCertificateIfRequired(log, key, delay)
		return nil
	}

	if crt.Status.RenewalTime != nil {
		// ensure a resync is scheduled in the future so that we re-check
		// Certificate resources and trigger them near expiry time
		c.scheduleRecheckOfCertificateIfRequired(log, key, crt.Status.RenewalTime.Time.Sub(c.clock.Now()))
	}

	reason, message, reissue := c.shouldReissue(input)
	if !reissue {
		// no re-issuance required, return early
		return nil
	}

	// Although the below recorder.Event already logs the event, the log
	// line is quite unreadable (very long). Since this information is very
	// important for the user and the operator, we log the following
	// message.
	log.V(logf.InfoLevel).Info("Certificate must be re-issued", "reason", reason, "message", message)

	crt = crt.DeepCopy()
	apiutil.SetCertificateCondition(crt, crt.Generation, cmapi.CertificateConditionIssuing, cmmeta.ConditionTrue, reason, message)
	_, err = c.client.CertmanagerV1().Certificates(crt.Namespace).UpdateStatus(ctx, crt, metav1.UpdateOptions{})
	if err != nil {
		return err
	}
	c.recorder.Event(crt, corev1.EventTypeNormal, "Issuing", message)

	return nil
}

// shouldBackoffReissuingOnFailure tells us if we should back off from
// reissuing the certificate and for how much time.
func shouldBackoffReissuingOnFailure(log logr.Logger, c clock.Clock, crt *cmapi.Certificate) (backoff bool, delay time.Duration) {
	if crt.Status.LastFailureTime == nil {
		return false, 0
	}

	now := c.Now()
	durationSinceFailure := now.Sub(crt.Status.LastFailureTime.Time)
	if durationSinceFailure >= retryAfterLastFailure {
		log.V(logf.ExtendedInfoLevel).WithValues("since_failure", durationSinceFailure).Info("Certificate has been in failure mode long enough, no need to back off")
		return false, 0
	}

	return true, retryAfterLastFailure - durationSinceFailure
}

// scheduleRecheckOfCertificateIfRequired will schedule the resource with the
// given key to be re-queued for processing after the given amount of time
// has elapsed.
// If the 'durationUntilRenewalTime' is less than zero, it will not be
// queued again.
func (c *controller) scheduleRecheckOfCertificateIfRequired(log logr.Logger, key string, durationUntilRenewalTime time.Duration) {
	// don't schedule a re-queue if the time is in the past.
	// if it is in the past, the resource will be triggered during the
	// current call to the ProcessItem method. If we added the item to the
	// queue with a duration of <=0, we would otherwise continually re-queue
	// in a tight loop whilst we wait for the caching listers to observe
	// the 'Triggered' status condition changing to 'True'.
	if durationUntilRenewalTime < 0 {
		return
	}

	log.V(logf.DebugLevel).Info("scheduling renewal", "duration_until_renewal", durationUntilRenewalTime.String())

	c.scheduledWorkQueue.Add(key, durationUntilRenewalTime)
}

// controllerWrapper wraps the `controller` structure to make it implement
// the controllerpkg.queueingController interface
type controllerWrapper struct {
	*controller
}

func (c *controllerWrapper) Register(ctx *controllerpkg.Context) (workqueue.RateLimitingInterface, []cache.InformerSynced, error) {
	// construct a new named logger to be reused throughout the controller
	log := logf.FromContext(ctx.RootContext, ControllerName)

	ctrl, queue, mustSync := NewController(log,
		ctx.CMClient,
		ctx.KubeSharedInformerFactory,
		ctx.SharedInformerFactory,
		ctx.Recorder,
		ctx.Clock,
		policies.NewTriggerPolicyChain(ctx.Clock, cmapi.DefaultRenewBefore).Evaluate,
	)
	c.controller = ctrl

	return queue, mustSync, nil
}

func init() {
	controllerpkg.Register(ControllerName, func(ctx *controllerpkg.Context) (controllerpkg.Interface, error) {
		return controllerpkg.NewBuilder(ctx, ControllerName).
			For(&controllerWrapper{}).
			Complete()
	})
}
<commit_msg>PR comment: typo: "the following are" instead of "is"<commit_after>/*
Copyright 2020 The cert-manager 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 trigger

import (
	"context"
	"time"

	"github.com/go-logr/logr"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/informers"
	corelisters "k8s.io/client-go/listers/core/v1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"
	"k8s.io/client-go/util/workqueue"
	"k8s.io/utils/clock"

	apiutil "github.com/jetstack/cert-manager/pkg/api/util"
	cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
	cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
	cmclient "github.com/jetstack/cert-manager/pkg/client/clientset/versioned"
	cminformers "github.com/jetstack/cert-manager/pkg/client/informers/externalversions"
	cmlisters "github.com/jetstack/cert-manager/pkg/client/listers/certmanager/v1"
	controllerpkg "github.com/jetstack/cert-manager/pkg/controller"
	"github.com/jetstack/cert-manager/pkg/controller/certificates"
	"github.com/jetstack/cert-manager/pkg/controller/certificates/trigger/policies"
	logf "github.com/jetstack/cert-manager/pkg/logs"
	"github.com/jetstack/cert-manager/pkg/scheduler"
	"github.com/jetstack/cert-manager/pkg/util/predicate"
)

const (
	ControllerName = "CertificateTrigger"

	// the amount of time after the LastFailureTime of a Certificate
	// before the request should be retried.
	// In future this should be replaced with a more dynamic exponential
	// back-off algorithm.
	retryAfterLastFailure = time.Hour
)

// This controller observes the state of the certificate's currently
// issued `spec.secretName` and the rest of the `certificate.spec` fields to
// determine whether a re-issuance is required.
// It triggers re-issuance by adding the `Issuing` status condition when a new
// certificate is required.
type controller struct {
	certificateLister        cmlisters.CertificateLister
	certificateRequestLister cmlisters.CertificateRequestLister
	secretLister             corelisters.SecretLister
	client                   cmclient.Interface
	recorder                 record.EventRecorder
	scheduledWorkQueue       scheduler.ScheduledWorkQueue

	// The following are used for testing purposes.
	clock              clock.Clock
	shouldReissue      policies.Func
	dataForCertificate func(context.Context, *cmapi.Certificate) (policies.Input, error)
}

func NewController(
	log logr.Logger,
	client cmclient.Interface,
	factory informers.SharedInformerFactory,
	cmFactory cminformers.SharedInformerFactory,
	recorder record.EventRecorder,
	clock clock.Clock,
	shouldReissue policies.Func,
) (*controller, workqueue.RateLimitingInterface, []cache.InformerSynced) {
	// create a queue used to queue up items to be processed
	queue := workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(time.Second*1, time.Second*30), ControllerName)

	// obtain references to all the informers used by this controller
	certificateInformer := cmFactory.Certmanager().V1().Certificates()
	certificateRequestInformer := cmFactory.Certmanager().V1().CertificateRequests()
	secretsInformer := factory.Core().V1().Secrets()

	certificateInformer.Informer().AddEventHandler(&controllerpkg.QueuingEventHandler{Queue: queue})

	// When a CertificateRequest resource changes, enqueue the Certificate resource that owns it.
	certificateRequestInformer.Informer().AddEventHandler(&controllerpkg.BlockingEventHandler{
		WorkFunc: certificates.EnqueueCertificatesForResourceUsingPredicates(log, queue, certificateInformer.Lister(), labels.Everything(), predicate.ResourceOwnerOf),
	})
	// When a Secret resource changes, enqueue any Certificate resources that name it as spec.secretName.
	secretsInformer.Informer().AddEventHandler(&controllerpkg.BlockingEventHandler{
		// Trigger reconciles on changes to the Secret named `spec.secretName`
		WorkFunc: certificates.EnqueueCertificatesForResourceUsingPredicates(log, queue, certificateInformer.Lister(), labels.Everything(),
			predicate.ExtractResourceName(predicate.CertificateSecretName)),
	})

	// build a list of InformerSynced functions that will be returned by the Register method.
	// the controller will only begin processing items once all of these informers have synced.
	mustSync := []cache.InformerSynced{
		certificateRequestInformer.Informer().HasSynced,
		secretsInformer.Informer().HasSynced,
		certificateInformer.Informer().HasSynced,
	}

	return &controller{
		certificateLister:        certificateInformer.Lister(),
		certificateRequestLister: certificateRequestInformer.Lister(),
		secretLister:             secretsInformer.Lister(),
		client:                   client,
		recorder:                 recorder,
		scheduledWorkQueue:       scheduler.NewScheduledWorkQueue(clock, queue.Add),

		// The following are used for testing purposes.
		clock:         clock,
		shouldReissue: shouldReissue,
		dataForCertificate: (&policies.Gatherer{
			CertificateRequestLister: certificateRequestInformer.Lister(),
			SecretLister:             secretsInformer.Lister(),
		}).DataForCertificate,
	}, queue, mustSync
}

func (c *controller) ProcessItem(ctx context.Context, key string) error {
	log := logf.FromContext(ctx).WithValues("key", key)
	ctx = logf.NewContext(ctx, log)
	namespace, name, err := cache.SplitMetaNamespaceKey(key)
	if err != nil {
		log.Error(err, "invalid resource key passed to ProcessItem")
		return nil
	}

	crt, err := c.certificateLister.Certificates(namespace).Get(name)
	if apierrors.IsNotFound(err) {
		log.Error(err, "certificate not found for key")
		return nil
	}
	if err != nil {
		return err
	}
	if apiutil.CertificateHasCondition(crt, cmapi.CertificateCondition{
		Type:   cmapi.CertificateConditionIssuing,
		Status: cmmeta.ConditionTrue,
	}) {
		// Do nothing if an issuance is already in progress.
		return nil
	}

	input, err := c.dataForCertificate(ctx, crt)
	if err != nil {
		return err
	}

	// Back off from re-issuing immediately when the certificate has been
	// in failing mode for less than 1 hour.
	backoff, delay := shouldBackoffReissuingOnFailure(log, c.clock, input.Certificate)
	if backoff {
		log.V(logf.InfoLevel).Info("Not re-issuing certificate as an attempt has been made in the last hour", "retry_delay", delay)
		c.scheduleRecheckOfCertificateIfRequired(log, key, delay)
		return nil
	}

	if crt.Status.RenewalTime != nil {
		// ensure a resync is scheduled in the future so that we re-check
		// Certificate resources and trigger them near expiry time
		c.scheduleRecheckOfCertificateIfRequired(log, key, crt.Status.RenewalTime.Time.Sub(c.clock.Now()))
	}

	reason, message, reissue := c.shouldReissue(input)
	if !reissue {
		// no re-issuance required, return early
		return nil
	}

	// Although the below recorder.Event already logs the event, the log
	// line is quite unreadable (very long). Since this information is very
	// important for the user and the operator, we log the following
	// message.
	log.V(logf.InfoLevel).Info("Certificate must be re-issued", "reason", reason, "message", message)

	crt = crt.DeepCopy()
	apiutil.SetCertificateCondition(crt, crt.Generation, cmapi.CertificateConditionIssuing, cmmeta.ConditionTrue, reason, message)
	_, err = c.client.CertmanagerV1().Certificates(crt.Namespace).UpdateStatus(ctx, crt, metav1.UpdateOptions{})
	if err != nil {
		return err
	}
	c.recorder.Event(crt, corev1.EventTypeNormal, "Issuing", message)

	return nil
}

// shouldBackoffReissuingOnFailure tells us if we should back off from
// reissuing the certificate and for how much time.
func shouldBackoffReissuingOnFailure(log logr.Logger, c clock.Clock, crt *cmapi.Certificate) (backoff bool, delay time.Duration) {
	if crt.Status.LastFailureTime == nil {
		return false, 0
	}

	now := c.Now()
	durationSinceFailure := now.Sub(crt.Status.LastFailureTime.Time)
	if durationSinceFailure >= retryAfterLastFailure {
		log.V(logf.ExtendedInfoLevel).WithValues("since_failure", durationSinceFailure).Info("Certificate has been in failure mode long enough, no need to back off")
		return false, 0
	}

	return true, retryAfterLastFailure - durationSinceFailure
}

// scheduleRecheckOfCertificateIfRequired will schedule the resource with the
// given key to be re-queued for processing after the given amount of time
// has elapsed.
// If the 'durationUntilRenewalTime' is less than zero, it will not be
// queued again.
func (c *controller) scheduleRecheckOfCertificateIfRequired(log logr.Logger, key string, durationUntilRenewalTime time.Duration) {
	// don't schedule a re-queue if the time is in the past.
	// if it is in the past, the resource will be triggered during the
	// current call to the ProcessItem method. If we added the item to the
	// queue with a duration of <=0, we would otherwise continually re-queue
	// in a tight loop whilst we wait for the caching listers to observe
	// the 'Triggered' status condition changing to 'True'.
	if durationUntilRenewalTime < 0 {
		return
	}

	log.V(logf.DebugLevel).Info("scheduling renewal", "duration_until_renewal", durationUntilRenewalTime.String())

	c.scheduledWorkQueue.Add(key, durationUntilRenewalTime)
}

// controllerWrapper wraps the `controller` structure to make it implement
// the controllerpkg.queueingController interface
type controllerWrapper struct {
	*controller
}

func (c *controllerWrapper) Register(ctx *controllerpkg.Context) (workqueue.RateLimitingInterface, []cache.InformerSynced, error) {
	// construct a new named logger to be reused throughout the controller
	log := logf.FromContext(ctx.RootContext, ControllerName)

	ctrl, queue, mustSync := NewController(log,
		ctx.CMClient,
		ctx.KubeSharedInformerFactory,
		ctx.SharedInformerFactory,
		ctx.Recorder,
		ctx.Clock,
		policies.NewTriggerPolicyChain(ctx.Clock, cmapi.DefaultRenewBefore).Evaluate,
	)
	c.controller = ctrl

	return queue, mustSync, nil
}

func init() {
	controllerpkg.Register(ControllerName, func(ctx *controllerpkg.Context) (controllerpkg.Interface, error) {
		return controllerpkg.NewBuilder(ctx, ControllerName).
			For(&controllerWrapper{}).
			Complete()
	})
}
<|endoftext|>


<commit_before>// @author       sigu-399
// @description  An implementation of JSON Schema, draft v4 - Go language
// @created      27-02-2013

package gojsonschema

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
)

func GetHttpJson(url string) (interface{}, error) {

	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != http.StatusOK {
		return nil, errors.New("Could not access schema " + resp.Status)
	}

	bodyBuff, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var document interface{}
	err = json.Unmarshal(bodyBuff, &document)
	if err != nil {
		return nil, err
	}

	return document, nil
}
<commit_msg>removed jsonutil<commit_after><|endoftext|>