<commit_before>package godirwalk

import (
	"os"
	"path/filepath"
	"testing"
)

const testScratchBufferSize = 16 * 1024

func helperFilepathWalk(tb testing.TB, osDirname string) []string {
	tb.Helper()
	var entries []string
	err := filepath.Walk(osDirname, func(osPathname string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.Name() == "skip" {
			return filepath.SkipDir
		}
		// filepath.Walk invokes callback function with a slashed version of the
		// pathname, while godirwalk invokes callback function with the
		// os-specific pathname separator.
		entries = append(entries, filepath.FromSlash(osPathname))
		return nil
	})
	if err != nil {
		tb.Fatal(err)
	}
	return entries
}

func helperGodirwalkWalk(tb testing.TB, osDirname string) []string {
	tb.Helper()
	var entries []string
	err := Walk(osDirname, &Options{
		Callback: func(osPathname string, dirent *Dirent) error {
			if dirent.Name() == "skip" {
				return filepath.SkipDir
			}
			// filepath.Walk invokes callback function with a slashed version of
			// the pathname, while godirwalk invokes callback function with the
			// os-specific pathname separator.
			entries = append(entries, filepath.FromSlash(osPathname))
			return nil
		},
		ScratchBuffer: make([]byte, testScratchBufferSize),
	})
	if err != nil {
		tb.Fatal(err)
	}
	return entries
}

func symlinkAbs(oldname, newname string) error {
	absDir, err := filepath.Abs(oldname)
	if err != nil {
		return err
	}
	return os.Symlink(absDir, newname)
}

func TestWalkSkipDir(t *testing.T) {
	// Ensure the results from calling filepath.Walk exactly match the results
	// for calling this library's walk function.

	test := func(t *testing.T, osDirname string) {
		osDirname = filepath.Join(rootDir, osDirname)
		expected := helperFilepathWalk(t, osDirname)
		actual := helperGodirwalkWalk(t, osDirname)

		if got, want := len(actual), len(expected); got != want {
			t.Fatalf("\n(GOT)\n\t%#v\n(WNT)\n\t%#v", actual, expected)
		}

		for i := 0; i < len(actual); i++ {
			if got, want := actual[i], expected[i]; got != want {
				t.Errorf("(GOT) %v; (WNT) %v", got, want)
				// } else {
				// 	t.Log(got)
			}
		}
	}

	// Test cases for encountering the filepath.SkipDir error at different times
	// from the call.

	t.Run("SkipFileAtRoot", func(t *testing.T) {
		test(t, "dir1/dir1a")
	})

	t.Run("SkipFileUnderRoot", func(t *testing.T) {
		test(t, "dir1")
	})

	t.Run("SkipDirAtRoot", func(t *testing.T) {
		test(t, "dir2/skip")
	})

	t.Run("SkipDirUnderRoot", func(t *testing.T) {
		test(t, "dir2")
	})

	t.Run("SkipDirOnSymlink", func(t *testing.T) {
		osDirname := filepath.Join(rootDir, "dir3")
		actual := helperGodirwalkWalk(t, osDirname)

		expected := []string{
			filepath.Join(rootDir, "dir3"),
			filepath.Join(rootDir, "dir3/aaa.txt"),
			filepath.Join(rootDir, "dir3/zzz"),
			filepath.Join(rootDir, "dir3/zzz/aaa.txt"),
		}

		if got, want := len(actual), len(expected); got != want {
			t.Fatalf("\n(GOT)\n\t%#v\n(WNT)\n\t%#v", actual, expected)
		}

		for i := 0; i < len(actual); i++ {
			if got, want := actual[i], expected[i]; got != want {
				t.Errorf("(GOT) %v; (WNT) %v", got, want)
			}
		}
	})
}

func TestWalkNoAccess(t *testing.T) {
	var actual []string

	err := Walk(rootDir, &Options{
		ScratchBuffer: make([]byte, testScratchBufferSize),
		Callback: func(osPathname string, _ *Dirent) error {
			// t.Logf("walk in: %s", osPathname)
			return nil
		},
		ErrorCallback: func(osChildname string, err error) ErrorAction {
			actual = append(actual, osChildname)
			return SkipNode
		},
	})
	if err != nil {
		t.Errorf("(GOT): %v; (WNT): %v", err, nil)
	}

	expected := []string{
		filepath.Join(rootDir, "dir6/noaccess"),
	}

	if got, want := len(actual), len(expected); got != want {
		t.Fatalf("\n(GOT)\n\t%#v\n(WNT)\n\t%#v", actual, expected)
	}

	for i := 0; i < len(actual); i++ {
		if got, want := actual[i], expected[i]; got != want {
			t.Errorf("(GOT) %v; (WNT) %v", got, want)
		}
	}
}

func TestWalkFollowSymbolicLinksFalse(t *testing.T) {
	osDirname := filepath.Join(rootDir, "dir4")
	symlink := filepath.Join(rootDir, "dir4/symlinkToAbsDirectory")

	if err := symlinkAbs(filepath.Join(rootDir, "dir4/zzz"), symlink); err != nil {
		t.Fatal(err)
	}

	defer func() {
		if err := os.Remove(symlink); err != nil {
			t.Error(err)
		}
	}()

	var actual []string
	err := Walk(osDirname, &Options{
		Callback: func(osPathname string, dirent *Dirent) error {
			if dirent.Name() == "skip" {
				return filepath.SkipDir
			}
			// filepath.Walk invokes callback function with a slashed version of
			// the pathname, while godirwalk invokes callback function with the
			// os-specific pathname separator.
			actual = append(actual, filepath.ToSlash(osPathname))
			return nil
		},
	})
	if err != nil {
		t.Fatal(err)
	}

	expected := []string{
		filepath.Join(rootDir, "dir4"),
		filepath.Join(rootDir, "dir4/aaa.txt"),
		filepath.Join(rootDir, "dir4/symlinkToAbsDirectory"),
		filepath.Join(rootDir, "dir4/symlinkToDirectory"),
		filepath.Join(rootDir, "dir4/symlinkToFile"),
		filepath.Join(rootDir, "dir4/zzz"),
		filepath.Join(rootDir, "dir4/zzz/aaa.txt"),
	}

	if got, want := len(actual), len(expected); got != want {
		t.Fatalf("\n(GOT)\n\t%#v\n(WNT)\n\t%#v", actual, expected)
	}

	for i := 0; i < len(actual); i++ {
		if got, want := actual[i], expected[i]; got != want {
			t.Errorf("(GOT) %v; (WNT) %v", got, want)
		}
	}
}

func TestWalkFollowSymbolicLinksTrue(t *testing.T) {
	osDirname := filepath.Join(rootDir, "dir4")
	symlink := filepath.Join(rootDir, "dir4/symlinkToAbsDirectory")

	if err := symlinkAbs(filepath.Join(rootDir, "dir4/zzz"), symlink); err != nil {
		t.Fatal(err)
	}

	defer func() {
		if err := os.Remove(symlink); err != nil {
			t.Error(err)
		}
	}()

	var actual []string
	err := Walk(osDirname, &Options{
		FollowSymbolicLinks: true,
		Callback: func(osPathname string, dirent *Dirent) error {
			if dirent.Name() == "skip" {
				return filepath.SkipDir
			}
			// filepath.Walk invokes callback function with a slashed version of
			// the pathname, while godirwalk invokes callback function with the
			// os-specific pathname separator.
			actual = append(actual, filepath.ToSlash(osPathname))
			return nil
		},
	})
	if err != nil {
		t.Fatal(err)
	}

	expected := []string{
		filepath.Join(rootDir, "dir4"),
		filepath.Join(rootDir, "dir4/aaa.txt"),
		filepath.Join(rootDir, "dir4/symlinkToAbsDirectory"),
		filepath.Join(rootDir, "dir4/symlinkToAbsDirectory/aaa.txt"),
		filepath.Join(rootDir, "dir4/symlinkToDirectory"),
		filepath.Join(rootDir, "dir4/symlinkToDirectory/aaa.txt"),
		filepath.Join(rootDir, "dir4/symlinkToFile"),
		filepath.Join(rootDir, "dir4/zzz"),
		filepath.Join(rootDir, "dir4/zzz/aaa.txt"),
	}

	if got, want := len(actual), len(expected); got != want {
		t.Fatalf("\n(GOT)\n\t%#v\n(WNT)\n\t%#v", actual, expected)
	}

	for i := 0; i < len(actual); i++ {
		if got, want := actual[i], expected[i]; got != want {
			t.Errorf("(GOT) %v; (WNT) %v", got, want)
		}
	}
}

func TestWalkSymbolicRelativeLinkChain(t *testing.T) {
	var actual []string
	err := Walk(filepath.Join(rootDir, "dir7"), &Options{
		FollowSymbolicLinks: true,
		Callback: func(osPathname string, dirent *Dirent) error {
			actual = append(actual, filepath.ToSlash(osPathname))
			return nil
		},
	})
	if err != nil {
		t.Fatal(err)
	}

	expected := []string{
		filepath.Join(rootDir, "dir7"),
		filepath.Join(rootDir, "dir7", "a"),
		filepath.Join(rootDir, "dir7", "a", "x"),
		filepath.Join(rootDir, "dir7", "a", "x", "y"),
		filepath.Join(rootDir, "dir7", "b"),
		filepath.Join(rootDir, "dir7", "b", "y"),
		filepath.Join(rootDir, "dir7", "z"),
	}

	if got, want := len(actual), len(expected); got != want {
		t.Fatalf("\n(GOT)\n\t%#v\n(WNT)\n\t%#v", actual, expected)
	}

	for i := 0; i < len(actual); i++ {
		if got, want := actual[i], expected[i]; got != want {
			t.Errorf("(GOT) %v; (WNT) %v", got, want)
		}
	}
}

func TestPostChildrenCallback(t *testing.T) {
	osDirname := filepath.Join(rootDir, "dir5")

	var actual []string

	err := Walk(osDirname, &Options{
		ScratchBuffer: make([]byte, testScratchBufferSize),
		Callback: func(osPathname string, _ *Dirent) error {
			// t.Logf("walk in: %s", osPathname)
			return nil
		},
		PostChildrenCallback: func(osPathname string, de *Dirent) error {
			// t.Logf("walk out: %s", osPathname)
			actual = append(actual, osPathname)
			return nil
		},
	})
	if err != nil {
		t.Errorf("(GOT): %v; (WNT): %v", err, nil)
	}

	expected := []string{
		filepath.Join(rootDir, "dir5/a2/a2a"),
		filepath.Join(rootDir, "dir5/a2"),
		filepath.Join(rootDir, "dir5"),
	}

	if got, want := len(actual), len(expected); got != want {
		t.Errorf("(GOT) %v; (WNT) %v", got, want)
	}

	for i := 0; i < len(actual); i++ {
		if i >= len(expected) {
			t.Fatalf("(GOT) %v; (WNT): %v", actual[i], nil)
		}
		if got, want := actual[i], expected[i]; got != want {
			t.Errorf("(GOT) %v; (WNT) %v", got, want)
		}
	}
}

var goPrefix = filepath.Join(os.Getenv("GOPATH"), "src")

func BenchmarkFilepathWalk(b *testing.B) {
	if testing.Short() {
		b.Skip("Skipping benchmark using user's Go source directory")
	}

	for i := 0; i < b.N; i++ {
		_ = helperFilepathWalk(b, goPrefix)
	}
}

func BenchmarkGoDirWalk(b *testing.B) {
	if testing.Short() {
		b.Skip("Skipping benchmark using user's Go source directory")
	}

	for i := 0; i < b.N; i++ {
		_ = helperGodirwalkWalk(b, goPrefix)
	}
}

const flameIterations = 10

func BenchmarkFlameGraphFilepathWalk(b *testing.B) {
	for i := 0; i < flameIterations; i++ {
		_ = helperFilepathWalk(b, goPrefix)
	}
}

func BenchmarkFlameGraphGoDirWalk(b *testing.B) {
	for i := 0; i < flameIterations; i++ {
		_ = helperGodirwalkWalk(b, goPrefix)
	}
}
<commit_msg>filepath.FromSlash for the remainder of the walk_test.go tests<commit_after>package godirwalk

import (
	"os"
	"path/filepath"
	"testing"
)

const testScratchBufferSize = 16 * 1024

func helperFilepathWalk(tb testing.TB, osDirname string) []string {
	tb.Helper()
	var entries []string
	err := filepath.Walk(osDirname, func(osPathname string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.Name() == "skip" {
			return filepath.SkipDir
		}
		// filepath.Walk invokes callback function with a slashed version of the
		// pathname, while godirwalk invokes callback function with the
		// os-specific pathname separator.
		entries = append(entries, filepath.FromSlash(osPathname))
		return nil
	})
	if err != nil {
		tb.Fatal(err)
	}
	return entries
}

func helperGodirwalkWalk(tb testing.TB, osDirname string) []string {
	tb.Helper()
	var entries []string
	err := Walk(osDirname, &Options{
		Callback: func(osPathname string, dirent *Dirent) error {
			if dirent.Name() == "skip" {
				return filepath.SkipDir
			}
			// filepath.Walk invokes callback function with a slashed version of
			// the pathname, while godirwalk invokes callback function with the
			// os-specific pathname separator.
			entries = append(entries, filepath.FromSlash(osPathname))
			return nil
		},
		ScratchBuffer: make([]byte, testScratchBufferSize),
	})
	if err != nil {
		tb.Fatal(err)
	}
	return entries
}

func symlinkAbs(oldname, newname string) error {
	absDir, err := filepath.Abs(oldname)
	if err != nil {
		return err
	}
	return os.Symlink(absDir, newname)
}

func TestWalkSkipDir(t *testing.T) {
	// Ensure the results from calling filepath.Walk exactly match the results
	// for calling this library's walk function.

	test := func(t *testing.T, osDirname string) {
		osDirname = filepath.Join(rootDir, osDirname)
		expected := helperFilepathWalk(t, osDirname)
		actual := helperGodirwalkWalk(t, osDirname)

		if got, want := len(actual), len(expected); got != want {
			t.Fatalf("\n(GOT)\n\t%#v\n(WNT)\n\t%#v", actual, expected)
		}

		for i := 0; i < len(actual); i++ {
			if got, want := actual[i], expected[i]; got != want {
				t.Errorf("(GOT) %v; (WNT) %v", got, want)
			}
		}
	}

	// Test cases for encountering the filepath.SkipDir error at different times
	// from the call.

	t.Run("SkipFileAtRoot", func(t *testing.T) {
		test(t, "dir1/dir1a")
	})

	t.Run("SkipFileUnderRoot", func(t *testing.T) {
		test(t, "dir1")
	})

	t.Run("SkipDirAtRoot", func(t *testing.T) {
		test(t, "dir2/skip")
	})

	t.Run("SkipDirUnderRoot", func(t *testing.T) {
		test(t, "dir2")
	})

	t.Run("SkipDirOnSymlink", func(t *testing.T) {
		osDirname := filepath.Join(rootDir, "dir3")
		actual := helperGodirwalkWalk(t, osDirname)

		expected := []string{
			filepath.Join(rootDir, "dir3"),
			filepath.Join(rootDir, "dir3/aaa.txt"),
			filepath.Join(rootDir, "dir3/zzz"),
			filepath.Join(rootDir, "dir3/zzz/aaa.txt"),
		}

		if got, want := len(actual), len(expected); got != want {
			t.Fatalf("\n(GOT)\n\t%#v\n(WNT)\n\t%#v", actual, expected)
		}

		for i := 0; i < len(actual); i++ {
			if got, want := actual[i], expected[i]; got != want {
				t.Errorf("(GOT) %v; (WNT) %v", got, want)
			}
		}
	})
}

func TestWalkNoAccess(t *testing.T) {
	var actual []string

	err := Walk(rootDir, &Options{
		ScratchBuffer: make([]byte, testScratchBufferSize),
		Callback: func(osPathname string, _ *Dirent) error {
			// t.Logf("walk in: %s", osPathname)
			return nil
		},
		ErrorCallback: func(osChildname string, err error) ErrorAction {
			actual = append(actual, osChildname)
			return SkipNode
		},
	})
	if err != nil {
		t.Errorf("(GOT): %v; (WNT): %v", err, nil)
	}

	expected := []string{
		filepath.Join(rootDir, "dir6/noaccess"),
	}

	if got, want := len(actual), len(expected); got != want {
		t.Fatalf("\n(GOT)\n\t%#v\n(WNT)\n\t%#v", actual, expected)
	}

	for i := 0; i < len(actual); i++ {
		if got, want := actual[i], expected[i]; got != want {
			t.Errorf("(GOT) %v; (WNT) %v", got, want)
		}
	}
}

func TestWalkFollowSymbolicLinksFalse(t *testing.T) {
	osDirname := filepath.Join(rootDir, "dir4")
	symlink := filepath.Join(rootDir, "dir4/symlinkToAbsDirectory")

	if err := symlinkAbs(filepath.Join(rootDir, "dir4/zzz"), symlink); err != nil {
		t.Fatal(err)
	}

	defer func() {
		if err := os.Remove(symlink); err != nil {
			t.Error(err)
		}
	}()

	var actual []string
	err := Walk(osDirname, &Options{
		Callback: func(osPathname string, dirent *Dirent) error {
			if dirent.Name() == "skip" {
				return filepath.SkipDir
			}
			// filepath.Walk invokes callback function with a slashed version of
			// the pathname, while godirwalk invokes callback function with the
			// os-specific pathname separator.
			actual = append(actual, filepath.FromSlash(osPathname))
			return nil
		},
	})
	if err != nil {
		t.Fatal(err)
	}

	expected := []string{
		filepath.Join(rootDir, "dir4"),
		filepath.Join(rootDir, "dir4/aaa.txt"),
		filepath.Join(rootDir, "dir4/symlinkToAbsDirectory"),
		filepath.Join(rootDir, "dir4/symlinkToDirectory"),
		filepath.Join(rootDir, "dir4/symlinkToFile"),
		filepath.Join(rootDir, "dir4/zzz"),
		filepath.Join(rootDir, "dir4/zzz/aaa.txt"),
	}

	if got, want := len(actual), len(expected); got != want {
		t.Fatalf("\n(GOT)\n\t%#v\n(WNT)\n\t%#v", actual, expected)
	}

	for i := 0; i < len(actual); i++ {
		if got, want := actual[i], expected[i]; got != want {
			t.Errorf("(GOT) %v; (WNT) %v", got, want)
		}
	}
}

func TestWalkFollowSymbolicLinksTrue(t *testing.T) {
	osDirname := filepath.Join(rootDir, "dir4")
	symlink := filepath.Join(rootDir, "dir4/symlinkToAbsDirectory")

	if err := symlinkAbs(filepath.Join(rootDir, "dir4/zzz"), symlink); err != nil {
		t.Fatal(err)
	}

	defer func() {
		if err := os.Remove(symlink); err != nil {
			t.Error(err)
		}
	}()

	var actual []string
	err := Walk(osDirname, &Options{
		FollowSymbolicLinks: true,
		Callback: func(osPathname string, dirent *Dirent) error {
			if dirent.Name() == "skip" {
				return filepath.SkipDir
			}
			// filepath.Walk invokes callback function with a slashed version of
			// the pathname, while godirwalk invokes callback function with the
			// os-specific pathname separator.
			actual = append(actual, filepath.FromSlash(osPathname))
			return nil
		},
	})
	if err != nil {
		t.Fatal(err)
	}

	expected := []string{
		filepath.Join(rootDir, "dir4"),
		filepath.Join(rootDir, "dir4/aaa.txt"),
		filepath.Join(rootDir, "dir4/symlinkToAbsDirectory"),
		filepath.Join(rootDir, "dir4/symlinkToAbsDirectory/aaa.txt"),
		filepath.Join(rootDir, "dir4/symlinkToDirectory"),
		filepath.Join(rootDir, "dir4/symlinkToDirectory/aaa.txt"),
		filepath.Join(rootDir, "dir4/symlinkToFile"),
		filepath.Join(rootDir, "dir4/zzz"),
		filepath.Join(rootDir, "dir4/zzz/aaa.txt"),
	}

	if got, want := len(actual), len(expected); got != want {
		t.Fatalf("\n(GOT)\n\t%#v\n(WNT)\n\t%#v", actual, expected)
	}

	for i := 0; i < len(actual); i++ {
		if got, want := actual[i], expected[i]; got != want {
			t.Errorf("(GOT) %v; (WNT) %v", got, want)
		}
	}
}

func TestWalkSymbolicRelativeLinkChain(t *testing.T) {
	var actual []string
	err := Walk(filepath.Join(rootDir, "dir7"), &Options{
		FollowSymbolicLinks: true,
		Callback: func(osPathname string, dirent *Dirent) error {
			actual = append(actual, filepath.FromSlash(osPathname))
			return nil
		},
	})
	if err != nil {
		t.Fatal(err)
	}

	expected := []string{
		filepath.Join(rootDir, "dir7"),
		filepath.Join(rootDir, "dir7", "a"),
		filepath.Join(rootDir, "dir7", "a", "x"),
		filepath.Join(rootDir, "dir7", "a", "x", "y"),
		filepath.Join(rootDir, "dir7", "b"),
		filepath.Join(rootDir, "dir7", "b", "y"),
		filepath.Join(rootDir, "dir7", "z"),
	}

	if got, want := len(actual), len(expected); got != want {
		t.Fatalf("\n(GOT)\n\t%#v\n(WNT)\n\t%#v", actual, expected)
	}

	for i := 0; i < len(actual); i++ {
		if got, want := actual[i], expected[i]; got != want {
			t.Errorf("(GOT) %v; (WNT) %v", got, want)
		}
	}
}

func TestPostChildrenCallback(t *testing.T) {
	osDirname := filepath.Join(rootDir, "dir5")

	var actual []string

	err := Walk(osDirname, &Options{
		ScratchBuffer: make([]byte, testScratchBufferSize),
		Callback: func(osPathname string, _ *Dirent) error {
			// t.Logf("walk in: %s", osPathname)
			return nil
		},
		PostChildrenCallback: func(osPathname string, de *Dirent) error {
			// t.Logf("walk out: %s", osPathname)
			actual = append(actual, osPathname)
			return nil
		},
	})
	if err != nil {
		t.Errorf("(GOT): %v; (WNT): %v", err, nil)
	}

	expected := []string{
		filepath.Join(rootDir, "dir5/a2/a2a"),
		filepath.Join(rootDir, "dir5/a2"),
		filepath.Join(rootDir, "dir5"),
	}

	if got, want := len(actual), len(expected); got != want {
		t.Errorf("(GOT) %v; (WNT) %v", got, want)
	}

	for i := 0; i < len(actual); i++ {
		if i >= len(expected) {
			t.Fatalf("(GOT) %v; (WNT): %v", actual[i], nil)
		}
		if got, want := actual[i], expected[i]; got != want {
			t.Errorf("(GOT) %v; (WNT) %v", got, want)
		}
	}
}

var goPrefix = filepath.Join(os.Getenv("GOPATH"), "src")

func BenchmarkFilepathWalk(b *testing.B) {
	if testing.Short() {
		b.Skip("Skipping benchmark using user's Go source directory")
	}

	for i := 0; i < b.N; i++ {
		_ = helperFilepathWalk(b, goPrefix)
	}
}

func BenchmarkGoDirWalk(b *testing.B) {
	if testing.Short() {
		b.Skip("Skipping benchmark using user's Go source directory")
	}

	for i := 0; i < b.N; i++ {
		_ = helperGodirwalkWalk(b, goPrefix)
	}
}

const flameIterations = 10

func BenchmarkFlameGraphFilepathWalk(b *testing.B) {
	for i := 0; i < flameIterations; i++ {
		_ = helperFilepathWalk(b, goPrefix)
	}
}

func BenchmarkFlameGraphGoDirWalk(b *testing.B) {
	for i := 0; i < flameIterations; i++ {
		_ = helperGodirwalkWalk(b, goPrefix)
	}
}
<|endoftext|>


<commit_before>package builder

import (
	"testing"
)

func TestRunEnvironment(t *testing.T) {
	RunEnvironment()
}
<commit_msg>Added Benchmark Teset<commit_after>package builder

import (
	"testing"
)

func TestRunEnvironment(t *testing.T) {
	RunEnvironment()
}

func BenchmarkRunEvenironment(b *testing.B) {
        for n := 0; n < b.N; n++ {
         	RunEnvironment()
        }
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"os"
	"net/http"
	"bytes"
)

type Source struct {
	Uri        string
	Branch     string
	PrivateKey string
}

type Version struct {
	Ref string
}

type Payload struct {
	Source  Source
	Version Version
}

func parseInputJson(inbytes []byte) *Payload {
	defaultVersion := &Version{Ref: "1"}
	payload := &Payload{Version: *defaultVersion}

	if err := json.Unmarshal(inbytes, payload); err != nil {
		fmt.Fprintf(os.Stderr, "error parsing input as JSON: %s", err)
		os.Exit(1)
	}
	return payload
}

func findById(subdomain string, userName string, password string, id string) string {
	url := fmt.Sprintf("https://%s.zendesk.com/api/v2/search.json?query=%s", subdomain, id)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error creating request: %s", err)
		os.Exit(1)
	}
	req.SetBasicAuth(userName, password)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error making request: %s", err)
		os.Exit(1)
	}
	defer resp.Body.Close()

	buf := new(bytes.Buffer)
	buf.ReadFrom(resp.Body)

	return buf.String()
}

type ZendeskResponse struct {
	Results []struct {
		Created_At string
	}
	Count int
}

func parseZendDeskFindByIdJson(jsonString string) *ZendeskResponse{
	response:= &ZendeskResponse{}

	if err := json.Unmarshal([]byte(jsonString), response); err != nil {
		fmt.Fprintf(os.Stderr, "error parsing response as JSON: %s", err)
		os.Exit(1)
	}

	return response
}
<commit_msg>refactor unused types<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"os"
	"net/http"
	"bytes"
)

type Payload struct {
	Source  struct {
		Uri        string
		Branch     string
		PrivateKey string
	}
	Version struct {
		Ref string
	}
}

func parseInputJson(inbytes []byte) *Payload {
	payload := &Payload{Version: struct {Ref string}{Ref: "1"}}

	if err := json.Unmarshal(inbytes, payload); err != nil {
		fmt.Fprintf(os.Stderr, "error parsing input as JSON: %s", err)
		os.Exit(1)
	}
	return payload
}

func findById(subdomain string, userName string, password string, id string) string {
	url := fmt.Sprintf("https://%s.zendesk.com/api/v2/search.json?query=%s", subdomain, id)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error creating request: %s", err)
		os.Exit(1)
	}
	req.SetBasicAuth(userName, password)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error making request: %s", err)
		os.Exit(1)
	}
	defer resp.Body.Close()

	buf := new(bytes.Buffer)
	buf.ReadFrom(resp.Body)

	return buf.String()
}

type ZendeskResponse struct {
	Results []struct {
		Created_At string
	}
	Count int
}

func parseZendDeskFindByIdJson(jsonString string) *ZendeskResponse{
	response:= &ZendeskResponse{}

	if err := json.Unmarshal([]byte(jsonString), response); err != nil {
		fmt.Fprintf(os.Stderr, "error parsing response as JSON: %s", err)
		os.Exit(1)
	}

	return response
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	goetcd "github.com/coreos/go-etcd/etcd"
	"log"
	"strings"
	"time"
)

type Watch struct {
	client    *goetcd.Client
	prefix    string
	sentIndex uint64
	C         chan *goetcd.Node
}

func NewWatch(client *goetcd.Client, prefix string, limit int) *Watch {
	watch := &Watch{
		client: client,
		prefix: prefix,
		C:      make(chan *goetcd.Node, limit),
	}

	go watch.worker()

	return watch
}

func (watch *Watch) worker() {
	defer close(watch.C)

	if _, err := watch.client.SetDir(watch.prefix, 0); err != nil {
		// Ignore error code 102 (directory exists).
		if e, ok := err.(*goetcd.EtcdError); !ok || e.ErrorCode != 102 {
			log.Println("Watch etcd.SetDir error", watch.prefix, err)
			return
		}
	}

	for {
		// Fetch all current keys under this prefix, recursively.
		resp, err := watch.client.Get(watch.prefix, true, true)
		if err != nil {
			log.Println("Watch etcd.Get error", watch.prefix, err)
			return
		}

		// Find all non-directory nodes and send each to the channel.
		watch.sendNodes(resp.Node)

		// Start watching for updates after the current index given in the Get.
		index := resp.EtcdIndex

		// Fetch the next changed node for this prefix after index.
		resp, err = watch.client.Watch(watch.prefix, index+1, true, nil, nil)
		if err != nil {
			// TODO: Etcd closes the connection after 5 minutes,
			// resulting in a json.SyntaxError.  Retry watch.
			if _, ok := err.(*json.SyntaxError); ok {
				time.Sleep(*etcdRetryDelay)
				continue
			}

			// 401 means our index is too old, and we need to Get a new one.
			if e, ok := err.(*goetcd.EtcdError); ok && e.ErrorCode == 401 {
				time.Sleep(*etcdRetryDelay)
				break
			}

			log.Println("Watch etcd.Watch error", watch.prefix, err)
			return
		}

		// Send the changed node(s) to the update channel, track largest index we've sent.
		if i := watch.sendNodes(resp.Node); i > index {
			index = i
		}
	}
}

func (watch *Watch) sendNodes(node *goetcd.Node) uint64 {
	if !node.Dir {
		// Send this to channel if it is not a repeat.
		if node.ModifiedIndex > watch.sentIndex {
			node.Key = strings.TrimPrefix(node.Key, watch.prefix+"/")
			watch.C <- node
		}
		return node.ModifiedIndex
	}

	var index uint64
	for _, node := range node.Nodes {
		// Iterate into directory, track largest index we've seen.
		if i := watch.sendNodes(node); i > index {
			index = i
		}
	}
	return index
}
<commit_msg>Update sentIndex so we dont resend nodes.<commit_after>package main

import (
	"encoding/json"
	goetcd "github.com/coreos/go-etcd/etcd"
	"log"
	"strings"
	"time"
)

type Watch struct {
	client    *goetcd.Client
	prefix    string
	sentIndex uint64
	C         chan *goetcd.Node
}

func NewWatch(client *goetcd.Client, prefix string, limit int) *Watch {
	watch := &Watch{
		client: client,
		prefix: prefix,
		C:      make(chan *goetcd.Node, limit),
	}

	go watch.worker()

	return watch
}

func (watch *Watch) worker() {
	defer close(watch.C)

	if _, err := watch.client.SetDir(watch.prefix, 0); err != nil {
		// Ignore error code 102 (directory exists).
		if e, ok := err.(*goetcd.EtcdError); !ok || e.ErrorCode != 102 {
			log.Println("Watch etcd.SetDir error", watch.prefix, err)
			return
		}
	}

	for {
		// Fetch all current keys under this prefix, recursively.
		resp, err := watch.client.Get(watch.prefix, true, true)
		if err != nil {
			log.Println("Watch etcd.Get error", watch.prefix, err)
			return
		}

		// Find all non-directory nodes and send each to the channel.
		watch.sendNodes(resp.Node)

		// Start watching for updates after the current index given in the Get.
		index := resp.EtcdIndex

		// Fetch the next changed node for this prefix after index.
		resp, err = watch.client.Watch(watch.prefix, index+1, true, nil, nil)
		if err != nil {
			// TODO: Etcd closes the connection after 5 minutes,
			// resulting in a json.SyntaxError.  Retry watch.
			if _, ok := err.(*json.SyntaxError); ok {
				time.Sleep(*etcdRetryDelay)
				continue
			}

			// 401 means our index is too old, and we need to Get a new one.
			if e, ok := err.(*goetcd.EtcdError); ok && e.ErrorCode == 401 {
				time.Sleep(*etcdRetryDelay)
				break
			}

			log.Println("Watch etcd.Watch error", watch.prefix, err)
			return
		}

		// Send the changed node(s) to the update channel, track largest index we've sent.
		if i := watch.sendNodes(resp.Node); i > index {
			index = i
			watch.sentIndex = i
		}
	}
}

func (watch *Watch) sendNodes(node *goetcd.Node) uint64 {
	if !node.Dir {
		// Send this to channel if it is not a repeat.
		if node.ModifiedIndex > watch.sentIndex {
			node.Key = strings.TrimPrefix(node.Key, watch.prefix+"/")
			watch.C <- node
		}
		return node.ModifiedIndex
	}

	var index uint64
	for _, node := range node.Nodes {
		// Iterate into directory, track largest index we've seen.
		if i := watch.sendNodes(node); i > index {
			index = i
		}
	}
	return index
}
<|endoftext|>


<commit_before>package web

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/bobinette/papernet"
	"github.com/bobinette/papernet/auth"
	"github.com/bobinette/papernet/errors"
)

type PaperHandler struct {
	Store papernet.PaperStore
	Index papernet.PaperIndex

	TagIndex papernet.TagIndex

	UserStore papernet.UserRepository
}

func (h *PaperHandler) Routes() []papernet.Route {
	return []papernet.Route{
		papernet.Route{
			Route:         "/api/papers",
			Method:        "GET",
			Renderer:      "JSON",
			Authenticated: true,
			HandlerFunc:   WrapRequest(h.List),
		},
		papernet.Route{
			Route:         "/api/papers",
			Method:        "POST",
			Renderer:      "JSON",
			Authenticated: true,
			HandlerFunc:   WrapRequest(h.Insert),
		},
		papernet.Route{
			Route:         "/api/papers/:id",
			Method:        "GET",
			Renderer:      "JSON",
			Authenticated: true,
			HandlerFunc:   WrapRequest(h.Get),
		},
		papernet.Route{
			Route:         "/api/papers/:id",
			Method:        "PUT",
			Renderer:      "JSON",
			Authenticated: true,
			HandlerFunc:   WrapRequest(h.Update),
		},
		papernet.Route{
			Route:         "/api/papers/:id",
			Method:        "DELETE",
			Renderer:      "JSON",
			Authenticated: true,
			HandlerFunc:   WrapRequest(h.Delete),
		},
	}
}

func (h *PaperHandler) List(req *Request) (interface{}, error) {
	q := ""
	_ = req.Query("q", &q)

	bookmarked := false
	err := req.Query("bookmarked", &bookmarked)
	if err != nil {
		return nil, err
	}

	user, err := auth.UserFromContext(req.Context())
	if err != nil {
		return nil, err
	}

	var limit uint64 = 20
	err = req.Query("limit", &limit)
	if err != nil {
		return nil, err
	}
	if limit == 0 {
		limit = 20
	}

	var offset uint64 = 0
	err = req.Query("offset", &offset)
	if err != nil {
		return nil, err
	}

	search := papernet.PaperSearch{
		Q:      q,
		IDs:    user.CanSee,
		Limit:  limit,
		Offset: offset,
	}

	if bookmarked {
		search.IDs = user.Bookmarks
	}

	res, err := h.Index.Search(search)
	if err != nil {
		return nil, err
	}

	papers, err := h.Store.Get(res.IDs...)
	if err != nil {
		return nil, err
	}

	return map[string]interface{}{
		"data":       papers,
		"pagination": res.Pagination,
	}, nil
}

func (h *PaperHandler) Insert(req *Request) (interface{}, error) {
	user, err := auth.UserFromContext(req.Context())
	if err != nil {
		return nil, err
	}

	var paper papernet.Paper
	body := req.Body
	defer body.Close()
	err = json.NewDecoder(body).Decode(&paper)
	if err != nil {
		return nil, errors.New("error decoding json body", errors.WithCause(err))
	}

	if paper.ID > 0 {
		return nil, errors.New(
			fmt.Sprintf("field id should be empty, got %d", paper.ID),
			errors.WithCode(http.StatusBadRequest),
		)
	}

	err = h.Store.Upsert(&paper)
	if err != nil {
		return nil, errors.New("error inserting paper", errors.WithCause(err))
	}

	// Give ownership
	user.CanSee = append(user.CanSee, paper.ID)
	user.CanEdit = append(user.CanEdit, paper.ID)
	err = h.UserStore.Upsert(user)
	if err != nil {
		return nil, errors.New("error setting rights on user", errors.WithCause(err))
	}

	err = h.Index.Index(&paper)
	if err != nil {
		return nil, errors.New("error indexing paper", errors.WithCause(err))
	}

	for _, tag := range paper.Tags {
		err = h.TagIndex.Index(tag)
		if err != nil {
			log.Printf("error indexing tag %s: %v", tag, err)
		}
	}

	return map[string]interface{}{
		"data": paper,
	}, nil
}

func (h *PaperHandler) Get(req *Request) (interface{}, error) {
	id, err := strconv.Atoi(req.Param("id"))
	if err != nil {
		return nil, errors.New("id should be an integer", errors.WithCode(http.StatusBadRequest))
	}

	user, err := auth.UserFromContext(req.Context())
	if err != nil {
		return nil, err
	}

	if !isIn(id, user.CanSee) {
		return nil, errors.New(fmt.Sprintf("Paper %d not found", id), errors.WithCode(http.StatusNotFound))
	}

	papers, err := h.Store.Get(id)
	if err != nil {
		return nil, errors.New(
			fmt.Sprintf("error retrieving paper %d", id),
			errors.WithCause(err),
		)
	} else if len(papers) == 0 {
		return nil, errors.New(fmt.Sprintf("Paper %d not found", id), errors.WithCode(http.StatusNotFound))
	}

	return map[string]interface{}{
		"data": papers[0],
	}, nil
}

func (h *PaperHandler) Update(req *Request) (interface{}, error) {
	user, err := auth.UserFromContext(req.Context())
	if err != nil {
		return nil, err
	}

	id, err := strconv.Atoi(req.Param("id"))
	if err != nil {
		return nil, errors.New("id should be an integer", errors.WithCode(http.StatusBadRequest))
	}

	var paper papernet.Paper
	body := req.Body
	defer body.Close()
	err = json.NewDecoder(body).Decode(&paper)
	if err != nil {
		return nil, errors.New("error decoding json body", errors.WithCause(err))
	}

	papers, err := h.Store.Get(id)
	if err != nil {
		return nil, errors.New(
			fmt.Sprintf("error retrieving paper %d", id),
			errors.WithCause(err),
		)
	} else if len(papers) == 0 {
		return nil, errors.New(fmt.Sprintf("Paper %d not found", id), errors.WithCode(http.StatusNotFound))
	}

	if paper.ID != id {
		return nil, errors.New(
			fmt.Sprintf("ids do not match: %d (url) != %d (body)", id, paper.ID),
			errors.WithCode(http.StatusBadRequest),
		)
	}

	// Now we can check the permissions
	if !isIn(id, user.CanEdit) {
		return nil, errors.New(
			fmt.Sprintf("You are not allowed to edit Paper %d", id),
			errors.WithCode(http.StatusForbidden),
		)
	}

	err = h.Store.Upsert(&paper)
	if err != nil {
		return nil, err
	}

	err = h.Index.Index(&paper)
	if err != nil {
		return nil, err
	}

	for _, tag := range paper.Tags {
		err = h.TagIndex.Index(tag)
		if err != nil {
			return nil, err
		}
	}

	return map[string]interface{}{
		"data": paper,
	}, nil
}

func (h *PaperHandler) Delete(req *Request) (interface{}, error) {
	user, err := auth.UserFromContext(req.Context())
	if err != nil {
		return nil, err
	}

	id, err := strconv.Atoi(req.Param("id"))
	if err != nil {
		return nil, errors.New("id should be an integer", errors.WithCode(http.StatusBadRequest))
	}

	papers, err := h.Store.Get(id)
	if err != nil {
		return nil, errors.New(
			fmt.Sprintf("error retrieving paper %d", id),
			errors.WithCause(err),
		)
	} else if len(papers) == 0 {
		return nil, errors.New(fmt.Sprintf("Paper %d not found", id), errors.WithCode(http.StatusNotFound))
	}

	if !isIn(id, user.CanEdit) {
		return nil, errors.New(
			fmt.Sprintf("You are not allowed to delete Paper %d", id),
			errors.WithCode(http.StatusForbidden),
		)
	}

	err = h.Index.Delete(id)
	if err != nil {
		return nil, errors.New(
			fmt.Sprintf("error deleting paper from the index %d", id),
			errors.WithCause(err),
		)
	}

	err = h.Store.Delete(id)
	if err != nil {
		return nil, errors.New(
			fmt.Sprintf("error deleting paper in the database %d", id),
			errors.WithCause(err),
		)
	}

	return map[string]interface{}{
		"data": "ok",
	}, nil
}

// ------------------------------------------------------------------------------------------
// Helpers

func isIn(i int, a []int) bool {
	for _, e := range a {
		if e == i {
			return true
		}
	}
	return false
}
<commit_msg>better handling of query params in paper list<commit_after>package web

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/bobinette/papernet"
	"github.com/bobinette/papernet/auth"
	"github.com/bobinette/papernet/errors"
)

type PaperHandler struct {
	Store papernet.PaperStore
	Index papernet.PaperIndex

	TagIndex papernet.TagIndex

	UserStore papernet.UserRepository
}

func (h *PaperHandler) Routes() []papernet.Route {
	return []papernet.Route{
		papernet.Route{
			Route:         "/api/papers",
			Method:        "GET",
			Renderer:      "JSON",
			Authenticated: true,
			HandlerFunc:   WrapRequest(h.List),
		},
		papernet.Route{
			Route:         "/api/papers",
			Method:        "POST",
			Renderer:      "JSON",
			Authenticated: true,
			HandlerFunc:   WrapRequest(h.Insert),
		},
		papernet.Route{
			Route:         "/api/papers/:id",
			Method:        "GET",
			Renderer:      "JSON",
			Authenticated: true,
			HandlerFunc:   WrapRequest(h.Get),
		},
		papernet.Route{
			Route:         "/api/papers/:id",
			Method:        "PUT",
			Renderer:      "JSON",
			Authenticated: true,
			HandlerFunc:   WrapRequest(h.Update),
		},
		papernet.Route{
			Route:         "/api/papers/:id",
			Method:        "DELETE",
			Renderer:      "JSON",
			Authenticated: true,
			HandlerFunc:   WrapRequest(h.Delete),
		},
	}
}

func (h *PaperHandler) List(req *Request) (interface{}, error) {
	user, err := auth.UserFromContext(req.Context())
	if err != nil {
		return nil, err
	}

	search := papernet.PaperSearch{
		IDs: user.CanSee,
	}

	err = req.Query("q", &search.Q)
	if err != nil {
		return nil, err
	}

	err = req.Query("limit", &search.Limit)
	if err != nil {
		return nil, err
	}
	if search.Limit == 0 {
		search.Limit = 20
	}

	err = req.Query("offset", &search.Offset)
	if err != nil {
		return nil, err
	}

	bookmarked := false
	err = req.Query("bookmarked", &bookmarked)
	if err != nil {
		return nil, err
	}
	if bookmarked {
		search.IDs = user.Bookmarks
	}

	res, err := h.Index.Search(search)
	if err != nil {
		return nil, err
	}

	papers, err := h.Store.Get(res.IDs...)
	if err != nil {
		return nil, err
	}

	return map[string]interface{}{
		"data":       papers,
		"pagination": res.Pagination,
	}, nil
}

func (h *PaperHandler) Insert(req *Request) (interface{}, error) {
	user, err := auth.UserFromContext(req.Context())
	if err != nil {
		return nil, err
	}

	var paper papernet.Paper
	body := req.Body
	defer body.Close()
	err = json.NewDecoder(body).Decode(&paper)
	if err != nil {
		return nil, errors.New("error decoding json body", errors.WithCause(err))
	}

	if paper.ID > 0 {
		return nil, errors.New(
			fmt.Sprintf("field id should be empty, got %d", paper.ID),
			errors.WithCode(http.StatusBadRequest),
		)
	}

	err = h.Store.Upsert(&paper)
	if err != nil {
		return nil, errors.New("error inserting paper", errors.WithCause(err))
	}

	// Give ownership
	user.CanSee = append(user.CanSee, paper.ID)
	user.CanEdit = append(user.CanEdit, paper.ID)
	err = h.UserStore.Upsert(user)
	if err != nil {
		return nil, errors.New("error setting rights on user", errors.WithCause(err))
	}

	err = h.Index.Index(&paper)
	if err != nil {
		return nil, errors.New("error indexing paper", errors.WithCause(err))
	}

	for _, tag := range paper.Tags {
		err = h.TagIndex.Index(tag)
		if err != nil {
			log.Printf("error indexing tag %s: %v", tag, err)
		}
	}

	return map[string]interface{}{
		"data": paper,
	}, nil
}

func (h *PaperHandler) Get(req *Request) (interface{}, error) {
	id, err := strconv.Atoi(req.Param("id"))
	if err != nil {
		return nil, errors.New("id should be an integer", errors.WithCode(http.StatusBadRequest))
	}

	user, err := auth.UserFromContext(req.Context())
	if err != nil {
		return nil, err
	}

	if !isIn(id, user.CanSee) {
		return nil, errors.New(fmt.Sprintf("Paper %d not found", id), errors.WithCode(http.StatusNotFound))
	}

	papers, err := h.Store.Get(id)
	if err != nil {
		return nil, errors.New(
			fmt.Sprintf("error retrieving paper %d", id),
			errors.WithCause(err),
		)
	} else if len(papers) == 0 {
		return nil, errors.New(fmt.Sprintf("Paper %d not found", id), errors.WithCode(http.StatusNotFound))
	}

	return map[string]interface{}{
		"data": papers[0],
	}, nil
}

func (h *PaperHandler) Update(req *Request) (interface{}, error) {
	user, err := auth.UserFromContext(req.Context())
	if err != nil {
		return nil, err
	}

	id, err := strconv.Atoi(req.Param("id"))
	if err != nil {
		return nil, errors.New("id should be an integer", errors.WithCode(http.StatusBadRequest))
	}

	var paper papernet.Paper
	body := req.Body
	defer body.Close()
	err = json.NewDecoder(body).Decode(&paper)
	if err != nil {
		return nil, errors.New("error decoding json body", errors.WithCause(err))
	}

	papers, err := h.Store.Get(id)
	if err != nil {
		return nil, errors.New(
			fmt.Sprintf("error retrieving paper %d", id),
			errors.WithCause(err),
		)
	} else if len(papers) == 0 {
		return nil, errors.New(fmt.Sprintf("Paper %d not found", id), errors.WithCode(http.StatusNotFound))
	}

	if paper.ID != id {
		return nil, errors.New(
			fmt.Sprintf("ids do not match: %d (url) != %d (body)", id, paper.ID),
			errors.WithCode(http.StatusBadRequest),
		)
	}

	// Now we can check the permissions
	if !isIn(id, user.CanEdit) {
		return nil, errors.New(
			fmt.Sprintf("You are not allowed to edit Paper %d", id),
			errors.WithCode(http.StatusForbidden),
		)
	}

	err = h.Store.Upsert(&paper)
	if err != nil {
		return nil, err
	}

	err = h.Index.Index(&paper)
	if err != nil {
		return nil, err
	}

	for _, tag := range paper.Tags {
		err = h.TagIndex.Index(tag)
		if err != nil {
			return nil, err
		}
	}

	return map[string]interface{}{
		"data": paper,
	}, nil
}

func (h *PaperHandler) Delete(req *Request) (interface{}, error) {
	user, err := auth.UserFromContext(req.Context())
	if err != nil {
		return nil, err
	}

	id, err := strconv.Atoi(req.Param("id"))
	if err != nil {
		return nil, errors.New("id should be an integer", errors.WithCode(http.StatusBadRequest))
	}

	papers, err := h.Store.Get(id)
	if err != nil {
		return nil, errors.New(
			fmt.Sprintf("error retrieving paper %d", id),
			errors.WithCause(err),
		)
	} else if len(papers) == 0 {
		return nil, errors.New(fmt.Sprintf("Paper %d not found", id), errors.WithCode(http.StatusNotFound))
	}

	if !isIn(id, user.CanEdit) {
		return nil, errors.New(
			fmt.Sprintf("You are not allowed to delete Paper %d", id),
			errors.WithCode(http.StatusForbidden),
		)
	}

	err = h.Index.Delete(id)
	if err != nil {
		return nil, errors.New(
			fmt.Sprintf("error deleting paper from the index %d", id),
			errors.WithCause(err),
		)
	}

	err = h.Store.Delete(id)
	if err != nil {
		return nil, errors.New(
			fmt.Sprintf("error deleting paper in the database %d", id),
			errors.WithCause(err),
		)
	}

	return map[string]interface{}{
		"data": "ok",
	}, nil
}

// ------------------------------------------------------------------------------------------
// Helpers

func isIn(i int, a []int) bool {
	for _, e := range a {
		if e == i {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>// (C) Copyright 2016 Hewlett Packard Enterprise Development LP
//
// 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 oneview

import (
	"github.com/HewlettPackard/oneview-golang/ov"
	"github.com/HewlettPackard/oneview-golang/utils"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceEthernetNetwork() *schema.Resource {
	return &schema.Resource{
		Create: resourceEthernetNetworkCreate,
		Read:   resourceEthernetNetworkRead,
		Update: resourceEthernetNetworkUpdate,
		Delete: resourceEthernetNetworkDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
			},
			"vlan_id": {
				Type:     schema.TypeInt,
				Required: true,
				//				ForceNew: true,
			},
			"purpose": {
				Type:     schema.TypeString,
				Optional: true,
				Default:  "General",
			},
			"private_network": {
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},
			"smart_link": {
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},
			"ethernet_network_type": {
				Type:     schema.TypeString,
				Optional: true,
				Default:  "Tagged",
			},
			"type": {
				Type:     schema.TypeString,
				Optional: true,
				Default:  "ethernet-networkV3",
			},
			"connection_template_uri": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"created": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"modified": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"description": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"uri": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"status": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"category": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"state": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"fabric_uri": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"eTag": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"scopesUri": {
				Optional: true,
				Type:     schema.TypeString,
				Computed: true,
			},
			"initial_scope_uris": {
				Optional: true,
				Type:     schema.TypeSet,
				Elem: &schema.Schema{
					Type: schema.TypeString,
				},
				Set: schema.HashString,
			},
		},
	}
}

func resourceEthernetNetworkCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	eNet := ov.EthernetNetwork{
		Name:                d.Get("name").(string),
		VlanId:              d.Get("vlan_id").(int),
		Purpose:             d.Get("purpose").(string),
		SmartLink:           d.Get("smart_link").(bool),
		PrivateNetwork:      d.Get("private_network").(bool),
		EthernetNetworkType: d.Get("ethernet_network_type").(string),
		Type:                d.Get("type").(string),
		Description:         utils.NewNstring(d.Get("description").(string)),
	}
	if val, ok := d.GetOk("initial_scope_uris"); ok {
		rawInitialScopeUris := val.(*schema.Set).List()
		initialScopeUris := make([]utils.Nstring, len(rawInitialScopeUris))
		for i, raw := range rawInitialScopeUris {
			initialScopeUris[i] = utils.Nstring(raw.(string))
		}
		eNet.InitialScopeUris = initialScopeUris
	}

	eNetError := config.ovClient.CreateEthernetNetwork(eNet)
	d.SetId(d.Get("name").(string))
	if eNetError != nil {
		d.SetId("")
		return eNetError
	}
	return resourceEthernetNetworkRead(d, meta)
}

func resourceEthernetNetworkRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	eNet, err := config.ovClient.GetEthernetNetworkByName(d.Id())
	if err != nil || eNet.URI.IsNil() {
		d.SetId("")
		return nil
	}
	d.Set("name", eNet.Name)
	d.Set("vlan_id", eNet.VlanId)
	d.Set("purpose", eNet.Purpose)
	d.Set("smart_link", eNet.SmartLink)
	d.Set("private_network", eNet.PrivateNetwork)
	d.Set("ethernet_network_type", eNet.EthernetNetworkType)
	d.Set("type", eNet.Type)
	d.Set("created", eNet.Created)
	d.Set("modified", eNet.Modified)
	d.Set("uri", eNet.URI.String())
	d.Set("connection_template_uri", eNet.ConnectionTemplateUri.String())
	d.Set("status", eNet.Status)
	d.Set("category", eNet.Category)
	d.Set("state", eNet.State)
	d.Set("fabric_uri", eNet.FabricUri.String())
	d.Set("eTag", eNet.ETAG)
	d.Set("scopesUri", eNet.ScopesUri.String())
	d.Set("initial_scope_uris", eNet.InitialScopeUris)

	return nil
}

func resourceEthernetNetworkUpdate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	newENet := ov.EthernetNetwork{
		ETAG:                  d.Get("eTag").(string),
		URI:                   utils.NewNstring(d.Get("uri").(string)),
		VlanId:                d.Get("vlan_id").(int),
		Purpose:               d.Get("purpose").(string),
		Name:                  d.Get("name").(string),
		PrivateNetwork:        d.Get("private_network").(bool),
		SmartLink:             d.Get("smart_link").(bool),
		ConnectionTemplateUri: utils.NewNstring(d.Get("connection_template_uri").(string)),
		Type: d.Get("type").(string),
	}

	err := config.ovClient.UpdateEthernetNetwork(newENet)
	if err != nil {
		return err
	}
	d.SetId(d.Get("name").(string))

	return resourceEthernetNetworkRead(d, meta)
}

func resourceEthernetNetworkDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	err := config.ovClient.DeleteEthernetNetwork(d.Get("name").(string))
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>Uncommented Force new line in resource file<commit_after>// (C) Copyright 2016 Hewlett Packard Enterprise Development LP
//
// 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 oneview

import (
	"github.com/HewlettPackard/oneview-golang/ov"
	"github.com/HewlettPackard/oneview-golang/utils"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceEthernetNetwork() *schema.Resource {
	return &schema.Resource{
		Create: resourceEthernetNetworkCreate,
		Read:   resourceEthernetNetworkRead,
		Update: resourceEthernetNetworkUpdate,
		Delete: resourceEthernetNetworkDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
			},
			"vlan_id": {
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},
			"purpose": {
				Type:     schema.TypeString,
				Optional: true,
				Default:  "General",
			},
			"private_network": {
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},
			"smart_link": {
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},
			"ethernet_network_type": {
				Type:     schema.TypeString,
				Optional: true,
				Default:  "Tagged",
			},
			"type": {
				Type:     schema.TypeString,
				Optional: true,
				Default:  "ethernet-networkV3",
			},
			"connection_template_uri": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"created": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"modified": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"description": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"uri": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"status": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"category": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"state": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"fabric_uri": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"eTag": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"scopesUri": {
				Optional: true,
				Type:     schema.TypeString,
				Computed: true,
			},
			"initial_scope_uris": {
				Optional: true,
				Type:     schema.TypeSet,
				Elem: &schema.Schema{
					Type: schema.TypeString,
				},
				Set: schema.HashString,
			},
		},
	}
}

func resourceEthernetNetworkCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	eNet := ov.EthernetNetwork{
		Name:                d.Get("name").(string),
		VlanId:              d.Get("vlan_id").(int),
		Purpose:             d.Get("purpose").(string),
		SmartLink:           d.Get("smart_link").(bool),
		PrivateNetwork:      d.Get("private_network").(bool),
		EthernetNetworkType: d.Get("ethernet_network_type").(string),
		Type:                d.Get("type").(string),
		Description:         utils.NewNstring(d.Get("description").(string)),
	}
	if val, ok := d.GetOk("initial_scope_uris"); ok {
		rawInitialScopeUris := val.(*schema.Set).List()
		initialScopeUris := make([]utils.Nstring, len(rawInitialScopeUris))
		for i, raw := range rawInitialScopeUris {
			initialScopeUris[i] = utils.Nstring(raw.(string))
		}
		eNet.InitialScopeUris = initialScopeUris
	}

	eNetError := config.ovClient.CreateEthernetNetwork(eNet)
	d.SetId(d.Get("name").(string))
	if eNetError != nil {
		d.SetId("")
		return eNetError
	}
	return resourceEthernetNetworkRead(d, meta)
}

func resourceEthernetNetworkRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	eNet, err := config.ovClient.GetEthernetNetworkByName(d.Id())
	if err != nil || eNet.URI.IsNil() {
		d.SetId("")
		return nil
	}
	d.Set("name", eNet.Name)
	d.Set("vlan_id", eNet.VlanId)
	d.Set("purpose", eNet.Purpose)
	d.Set("smart_link", eNet.SmartLink)
	d.Set("private_network", eNet.PrivateNetwork)
	d.Set("ethernet_network_type", eNet.EthernetNetworkType)
	d.Set("type", eNet.Type)
	d.Set("created", eNet.Created)
	d.Set("modified", eNet.Modified)
	d.Set("uri", eNet.URI.String())
	d.Set("connection_template_uri", eNet.ConnectionTemplateUri.String())
	d.Set("status", eNet.Status)
	d.Set("category", eNet.Category)
	d.Set("state", eNet.State)
	d.Set("fabric_uri", eNet.FabricUri.String())
	d.Set("eTag", eNet.ETAG)
	d.Set("scopesUri", eNet.ScopesUri.String())
	d.Set("initial_scope_uris", eNet.InitialScopeUris)

	return nil
}

func resourceEthernetNetworkUpdate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	newENet := ov.EthernetNetwork{
		ETAG:                  d.Get("eTag").(string),
		URI:                   utils.NewNstring(d.Get("uri").(string)),
		VlanId:                d.Get("vlan_id").(int),
		Purpose:               d.Get("purpose").(string),
		Name:                  d.Get("name").(string),
		PrivateNetwork:        d.Get("private_network").(bool),
		SmartLink:             d.Get("smart_link").(bool),
		ConnectionTemplateUri: utils.NewNstring(d.Get("connection_template_uri").(string)),
		Type: d.Get("type").(string),
	}

	err := config.ovClient.UpdateEthernetNetwork(newENet)
	if err != nil {
		return err
	}
	d.SetId(d.Get("name").(string))

	return resourceEthernetNetworkRead(d, meta)
}

func resourceEthernetNetworkDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	err := config.ovClient.DeleteEthernetNetwork(d.Get("name").(string))
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package meter_test

import (
	"testing"
	"time"

	meter "github.com/alxarch/go-meter"
	"github.com/go-redis/redis"
)

var redisOptions = &redis.Options{Addr: ":6379"}
var redisClient = redis.NewClient(redisOptions)

func Test_Persist(t *testing.T) {
	f := meter.NewFilter(meter.ResolutionDaily, meter.Daily)
	e := meter.NewEvent("foo", []string{}, f)
	e.Log(2)
	now := time.Now()
	e.Persist(now, redisClient)
	key := meter.ResolutionDaily.Key(e.EventNameLabels(nil), now)
	defer redisClient.Del(key)
	result, err := redisClient.HGetAll(key).Result()
	if err != nil {
		t.Error(err)
	}
	if n := result["*"]; n != "2" {
		t.Errorf("Invalid count %s", n)
	}

}
<commit_msg>More tests<commit_after>package meter_test

import (
	"testing"
	"time"

	meter "github.com/alxarch/go-meter"
	"github.com/go-redis/redis"
)

var redisOptions = &redis.Options{Addr: ":6379"}
var redisClient = redis.NewClient(redisOptions)

func Test_Persist(t *testing.T) {
	dim := []string{"bar"}
	f := meter.NewFilter(meter.ResolutionDaily, meter.Daily, dim)
	e := meter.NewEvent("foo", []string{}, f)
	if has := e.HasLabel("baz"); has {
		t.Error("Haslabel error")
	}
	if has := e.HasLabel("bar"); !has {
		t.Error("Haslabel error")
	}
	e.Log(1)
	e.Log(1, "bar", "baz")
	now := time.Now()
	e.Persist(now, redisClient)
	key := meter.ResolutionDaily.Key(e.EventNameLabels(nil), now)
	defer redisClient.Del(key)
	result, err := redisClient.HGetAll(key).Result()
	if err != nil {
		t.Error(err)
	}
	if n := result["*"]; n != "2" {
		t.Errorf("Invalid count %s", n)
	}

}
<|endoftext|>


<commit_before>package appdash

import (
	"encoding/json"
	"reflect"
	"sort"
	"testing"
	"time"
)

func TestMarshalEvent(t *testing.T) {
	e := dummyEvent{
		A: "a",
		B: "b",
		C: 1,
		D: map[string]string{"k1": "v1", "k2": "v2"},
		E: "e",
		F: dummyEventF{
			G: "g",
			H: map[string]string{"k3": "v3", "k4": "v4"},
		},
	}
	as, err := MarshalEvent(e)
	if err != nil {
		t.Fatal(err)
	}

	want := Annotations{
		{Key: "A", Value: []byte("a")},
		{Key: "B", Value: []byte("b")},
		{Key: "C", Value: []byte("1")},
		{Key: "D.k1", Value: []byte("v1")},
		{Key: "D.k2", Value: []byte("v2")},
		{Key: "e", Value: []byte("e")},
		{Key: "F.G", Value: []byte("g")},
		{Key: "F.H.k3", Value: []byte("v3")},
		{Key: "F.H.k4", Value: []byte("v4")},
		{Key: "_schema:dummy"},
	}

	sort.Sort(annotations(as))
	sort.Sort(annotations(want))

	if !reflect.DeepEqual(as, want) {
		t.Errorf("got annotations\n%s\n\nwant\n%s", as, want)
	}
}

func TestUnmarshalEvent(t *testing.T) {
	as := Annotations{
		{Key: "A", Value: []byte("a")},
		{Key: "B", Value: []byte("b")},
		{Key: "C", Value: []byte("1")},
		{Key: "D.k1", Value: []byte("v1")},
		{Key: "D.k2", Value: []byte("v2")},
		{Key: "e", Value: []byte("e")},
		{Key: "F.G", Value: []byte("g")},
		{Key: "F.H.k3", Value: []byte("v3")},
		{Key: "F.H.k4", Value: []byte("v4")},
		{Key: "_schema:dummy"},
	}

	var e dummyEvent
	if err := UnmarshalEvent(as, &e); err != nil {
		t.Fatal(err)
	}

	want := dummyEvent{
		A: "a",
		B: "b",
		C: 1,
		D: map[string]string{"k1": "v1", "k2": "v2"},
		E: "e",
		F: dummyEventF{
			G: "g",
			H: map[string]string{"k3": "v3", "k4": "v4"},
		},
	}

	if !reflect.DeepEqual(e, want) {
		t.Errorf("got event\n%+v\n\nwant\n%+v", e, want)
	}
}

func TestUnmarshalEvents(t *testing.T) {
	origRegisteredEvents := registeredEvents
	defer func() {
		registeredEvents = origRegisteredEvents
	}()

	for k := range registeredEvents {
		delete(registeredEvents, k)
	}
	RegisterEvent(dummyEvent{})
	RegisterEvent(dummyEvent2{})

	anns := Annotations{
		{Key: "A", Value: []byte("a")},
		{Key: "X", Value: []byte("x")},
		{Key: "_schema:dummy"},
		{Key: "_schema:dummy2"},
	}
	var events []Event
	if err := UnmarshalEvents(anns, &events); err != nil {
		t.Fatal(err)
	}

	want := []Event{
		dummyEvent{A: "a"},
		dummyEvent2{A: "a", X: "x"},
	}
	if !reflect.DeepEqual(events, want) {
		t.Errorf("got events %#v, want %#v", events, want)
	}
}

func TestSpanName(t *testing.T) {
	e := spanName{"foo"}

	anns, err := MarshalEvent(e)
	if err != nil {
		t.Fatal(err)
	}

	span := Span{Annotations: anns}
	if want := "foo"; span.Name() != want {
		t.Errorf("got span name == %q, want %q", span.Name(), want)
	}
}

func TestMsg(t *testing.T) {
	e := Msg("foo")

	j, err := json.Marshal(e)
	if err != nil {
		t.Error(err)
	}

	got := string(j)
	want := `{"Msg":"foo"}`
	if got != want {
		t.Errorf("got %#v, want %#v", got, want)
	}
}

func TestMsg_Schema(t *testing.T) {
	e := Msg("foo")

	if e.Schema() != "msg" {
		t.Errorf("Unwant schema: %v", e.Schema())
	}
}

func TestLog(t *testing.T) {
	e := Log("foo").(logEvent)

	e.Time = time.Unix(123456789, 0).In(time.UTC)

	j, err := json.Marshal(e)
	if err != nil {
		t.Error(err)
	}

	got := string(j)
	want := `{"Msg":"foo","Time":"1973-11-29T21:33:09Z"}`
	if got != want {
		t.Errorf("got %#v, want %#v", got, want)
	}
}

func TestLog_Schema(t *testing.T) {
	e := Log("foo")

	if e.Schema() != "log" {
		t.Errorf("Unwant schema: %v", e.Schema())
	}
}

type dummyEvent struct {
	A, B string
	C    int
	D    map[string]string
	E    string `trace:"e"`
	F    dummyEventF
}

type dummyEventF struct {
	G string
	H map[string]string
}

func (dummyEvent) Schema() string { return "dummy" }

type dummyEvent2 struct{ A, X string }

func (dummyEvent2) Schema() string { return "dummy2" }
<commit_msg>Add a benchmark for MarshalEvent.<commit_after>package appdash

import (
	"encoding/json"
	"reflect"
	"sort"
	"testing"
	"time"
)

func TestMarshalEvent(t *testing.T) {
	e := dummyEvent{
		A: "a",
		B: "b",
		C: 1,
		D: map[string]string{"k1": "v1", "k2": "v2"},
		E: "e",
		F: dummyEventF{
			G: "g",
			H: map[string]string{"k3": "v3", "k4": "v4"},
		},
	}
	as, err := MarshalEvent(e)
	if err != nil {
		t.Fatal(err)
	}

	want := Annotations{
		{Key: "A", Value: []byte("a")},
		{Key: "B", Value: []byte("b")},
		{Key: "C", Value: []byte("1")},
		{Key: "D.k1", Value: []byte("v1")},
		{Key: "D.k2", Value: []byte("v2")},
		{Key: "e", Value: []byte("e")},
		{Key: "F.G", Value: []byte("g")},
		{Key: "F.H.k3", Value: []byte("v3")},
		{Key: "F.H.k4", Value: []byte("v4")},
		{Key: "_schema:dummy"},
	}

	sort.Sort(annotations(as))
	sort.Sort(annotations(want))

	if !reflect.DeepEqual(as, want) {
		t.Errorf("got annotations\n%s\n\nwant\n%s", as, want)
	}
}

func TestUnmarshalEvent(t *testing.T) {
	as := Annotations{
		{Key: "A", Value: []byte("a")},
		{Key: "B", Value: []byte("b")},
		{Key: "C", Value: []byte("1")},
		{Key: "D.k1", Value: []byte("v1")},
		{Key: "D.k2", Value: []byte("v2")},
		{Key: "e", Value: []byte("e")},
		{Key: "F.G", Value: []byte("g")},
		{Key: "F.H.k3", Value: []byte("v3")},
		{Key: "F.H.k4", Value: []byte("v4")},
		{Key: "_schema:dummy"},
	}

	var e dummyEvent
	if err := UnmarshalEvent(as, &e); err != nil {
		t.Fatal(err)
	}

	want := dummyEvent{
		A: "a",
		B: "b",
		C: 1,
		D: map[string]string{"k1": "v1", "k2": "v2"},
		E: "e",
		F: dummyEventF{
			G: "g",
			H: map[string]string{"k3": "v3", "k4": "v4"},
		},
	}

	if !reflect.DeepEqual(e, want) {
		t.Errorf("got event\n%+v\n\nwant\n%+v", e, want)
	}
}

func TestUnmarshalEvents(t *testing.T) {
	origRegisteredEvents := registeredEvents
	defer func() {
		registeredEvents = origRegisteredEvents
	}()

	for k := range registeredEvents {
		delete(registeredEvents, k)
	}
	RegisterEvent(dummyEvent{})
	RegisterEvent(dummyEvent2{})

	anns := Annotations{
		{Key: "A", Value: []byte("a")},
		{Key: "X", Value: []byte("x")},
		{Key: "_schema:dummy"},
		{Key: "_schema:dummy2"},
	}
	var events []Event
	if err := UnmarshalEvents(anns, &events); err != nil {
		t.Fatal(err)
	}

	want := []Event{
		dummyEvent{A: "a"},
		dummyEvent2{A: "a", X: "x"},
	}
	if !reflect.DeepEqual(events, want) {
		t.Errorf("got events %#v, want %#v", events, want)
	}
}

func TestSpanName(t *testing.T) {
	e := spanName{"foo"}

	anns, err := MarshalEvent(e)
	if err != nil {
		t.Fatal(err)
	}

	span := Span{Annotations: anns}
	if want := "foo"; span.Name() != want {
		t.Errorf("got span name == %q, want %q", span.Name(), want)
	}
}

func TestMsg(t *testing.T) {
	e := Msg("foo")

	j, err := json.Marshal(e)
	if err != nil {
		t.Error(err)
	}

	got := string(j)
	want := `{"Msg":"foo"}`
	if got != want {
		t.Errorf("got %#v, want %#v", got, want)
	}
}

func TestMsg_Schema(t *testing.T) {
	e := Msg("foo")

	if e.Schema() != "msg" {
		t.Errorf("Unwant schema: %v", e.Schema())
	}
}

func TestLog(t *testing.T) {
	e := Log("foo").(logEvent)

	e.Time = time.Unix(123456789, 0).In(time.UTC)

	j, err := json.Marshal(e)
	if err != nil {
		t.Error(err)
	}

	got := string(j)
	want := `{"Msg":"foo","Time":"1973-11-29T21:33:09Z"}`
	if got != want {
		t.Errorf("got %#v, want %#v", got, want)
	}
}

func TestLog_Schema(t *testing.T) {
	e := Log("foo")

	if e.Schema() != "log" {
		t.Errorf("Unwant schema: %v", e.Schema())
	}
}

type dummyEvent struct {
	A, B string
	C    int
	D    map[string]string
	E    string `trace:"e"`
	F    dummyEventF
}

type dummyEventF struct {
	G string
	H map[string]string
}

func (dummyEvent) Schema() string { return "dummy" }

type dummyEvent2 struct{ A, X string }

func (dummyEvent2) Schema() string { return "dummy2" }

func BenchmarkMarshalEvent(b *testing.B) {
	e := dummyEvent{
		A: "a",
		B: "b",
		C: 1,
		D: map[string]string{"k1": "v1", "k2": "v2"},
		E: "e",
		F: dummyEventF{
			G: "g",
			H: map[string]string{"k3": "v3", "k4": "v4"},
		},
	}
	for i := 0; i < b.N; i++ {
		_, err := MarshalEvent(e)
		if err != nil {
			b.Fatal(err)
		}
	}
}
<|endoftext|>


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

// Package authsnippets contains Google Cloud authentication snippets.
package authsnippets

import (
	"context"
	"fmt"
	"log"

	"cloud.google.com/go/storage"
	"golang.org/x/oauth2/google"
	cloudkms "google.golang.org/api/cloudkms/v1"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"
)

// [START auth_cloud_implicit]

// implicit uses Application Default Credentials to authenticate.
func implicit() {
	ctx := context.Background()

	// For API packages whose import path is starting with "cloud.google.com/go",
	// such as cloud.google.com/go/storage in this case, if there are no credentials
	// provided, the client library will look for credentials in the environment.
	storageClient, err := storage.NewClient(ctx)
	if err != nil {
		log.Fatal(err)
	}

	it := storageClient.Buckets(ctx, "project-id")
	for {
		bucketAttrs, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(bucketAttrs.Name)
	}

	// For packages whose import path is starting with "google.golang.org/api",
	// such as google.golang.org/api/cloudkms/v1, use the
	// golang.org/x/oauth2/google package as shown below.
	oauthClient, err := google.DefaultClient(ctx, cloudkms.CloudPlatformScope)
	if err != nil {
		log.Fatal(err)
	}

	kmsService, err := cloudkms.New(oauthClient)
	if err != nil {
		log.Fatal(err)
	}

	_ = kmsService
}

// [END auth_cloud_implicit]

// [START auth_cloud_explicit]

// explicit reads credentials from the specified path.
func explicit(jsonPath, projectID string) {
	ctx := context.Background()
	client, err := storage.NewClient(ctx, option.WithCredentialsFile(jsonPath))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Buckets:")
	it := client.Buckets(ctx, projectID)
	for {
		battrs, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(battrs.Name)
	}
}

// [END auth_cloud_explicit]

// [START auth_cloud_explicit_compute_engine]
// [START auth_cloud_explicit_app_engine]

// explicitDefault finds the default credentials.
//
// It is very uncommon to need to explicitly get the default credentials in Go.
// Most of the time, client libraries can use Application Default Credentials
// without having to pass the credentials in directly. See implicit above.
func explicitDefault(projectID string) {
	ctx := context.Background()

	creds, err := google.FindDefaultCredentials(ctx, storage.ScopeReadOnly)
	if err != nil {
		log.Fatal(err)
	}
	client, err := storage.NewClient(ctx, option.WithCredentials(creds))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Buckets:")
	it := client.Buckets(ctx, projectID)
	for {
		battrs, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(battrs.Name)
	}
}

// [END auth_cloud_explicit_compute_engine]
// [END auth_cloud_explicit_app_engine]
<commit_msg>auth: new method NewService fetches default credentials (#978)<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package authsnippets contains Google Cloud authentication snippets.
package authsnippets

import (
	"context"
	"fmt"
	"log"

	"cloud.google.com/go/storage"
	"golang.org/x/oauth2/google"
	cloudkms "google.golang.org/api/cloudkms/v1"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"
)

// [START auth_cloud_implicit]

// implicit uses Application Default Credentials to authenticate.
func implicit() {
	ctx := context.Background()

	// For API packages whose import path is starting with "cloud.google.com/go",
	// such as cloud.google.com/go/storage in this case, if there are no credentials
	// provided, the client library will look for credentials in the environment.
	storageClient, err := storage.NewClient(ctx)
	if err != nil {
		log.Fatal(err)
	}

	it := storageClient.Buckets(ctx, "project-id")
	for {
		bucketAttrs, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(bucketAttrs.Name)
	}

	// For packages whose import path is starting with "google.golang.org/api",
	// such as google.golang.org/api/cloudkms/v1, use NewService to create the client.
	kmsService, err := cloudkms.NewService(ctx)
	if err != nil {
		log.Fatal(err)
	}

	_ = kmsService
}

// [END auth_cloud_implicit]

// [START auth_cloud_explicit]

// explicit reads credentials from the specified path.
func explicit(jsonPath, projectID string) {
	ctx := context.Background()
	client, err := storage.NewClient(ctx, option.WithCredentialsFile(jsonPath))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Buckets:")
	it := client.Buckets(ctx, projectID)
	for {
		battrs, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(battrs.Name)
	}
}

// [END auth_cloud_explicit]

// [START auth_cloud_explicit_compute_engine]
// [START auth_cloud_explicit_app_engine]

// explicitDefault finds the default credentials.
//
// It is very uncommon to need to explicitly get the default credentials in Go.
// Most of the time, client libraries can use Application Default Credentials
// without having to pass the credentials in directly. See implicit above.
func explicitDefault(projectID string) {
	ctx := context.Background()

	creds, err := google.FindDefaultCredentials(ctx, storage.ScopeReadOnly)
	if err != nil {
		log.Fatal(err)
	}
	client, err := storage.NewClient(ctx, option.WithCredentials(creds))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Buckets:")
	it := client.Buckets(ctx, projectID)
	for {
		battrs, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(battrs.Name)
	}
}

// [END auth_cloud_explicit_compute_engine]
// [END auth_cloud_explicit_app_engine]
<|endoftext|>


<commit_before>package experiment

import (
	"errors"
	"math/rand"
	"time"
)

type (
	// BeforeFunc represents the function that gets run before the experiment
	// starts. This function will only run if the experiment should run. The
	// functionality should be defined by the user.
	BeforeFunc func() error

	// CandidateFunc represents a function that is implemented by a candidate.
	// The value returned is the value that will be used to compare data.
	CandidateFunc func() (interface{}, error)

	// CleanFunc represents the function that cleans up the output data. This
	// function will only be called for candidates that did not error.
	CleanFunc func(interface{}) interface{}

	// CompareFunc represents the function that takes two candidates and knows
	// how to compare them. The functionality is implemented by the user. This
	// function will only be called for candidates that did not error.
	CompareFunc func(interface{}, interface{}) bool
)

var (
	// ErrControlCandidate is returned when a candidate is initiated with
	// control as it's name.
	ErrControlCandidate = errors.New("Can't use a candidate with the name 'control'")

	// ErrCandidatePanic represents the error that a candidate panicked.
	ErrCandidatePanic = errors.New("candidate panicked")
)

// Experiment represents a new refactoring experiment. This is where you'll
// define your control and candidates on and this will run the experiment
// according to the configuration.
type Experiment struct {
	Config *Config

	shouldRun    bool
	candidates   map[string]CandidateFunc
	observations map[string]*Observation

	before  BeforeFunc
	compare CompareFunc
	clean   CleanFunc
}

// New creates a new Experiment with the given configuration options.
func New(cfgs ...ConfigFunc) *Experiment {
	cfg := &Config{}
	for _, c := range cfgs {
		c(cfg)
	}

	return &Experiment{
		Config:       cfg,
		shouldRun:    cfg.Percentage > 0 && rand.Intn(100) <= cfg.Percentage,
		candidates:   map[string]CandidateFunc{},
		observations: map[string]*Observation{},
	}
}

// Before filter to do expensive setup only when the experiment is going to run.
// This will be skipped if the experiment doesn't need to run. A good use case
// would be to do a deep copy of a struct.
func (e *Experiment) Before(fnc BeforeFunc) {
	e.before = fnc
}

// Control represents the control function, this resembles the old or current
// implementation. This function will always run, regardless of the
// configuration percentage or overwrites. If this function panics, the
// application will panic.
// The output of this function will be the base to what all the candidates will
// be compared to.
func (e *Experiment) Control(fnc CandidateFunc) {
	e.candidates["control"] = fnc
}

// Candidate represents a refactoring solution. The order of candidates is
// randomly determined.
// If the concurrent configuration is given, candidates will run concurrently.
// If a candidate panics, your application will not panic, but the candidate
// will be marked as failed.
// If the name is control, this will error and not add the candidate.
func (e *Experiment) Candidate(name string, fnc CandidateFunc) error {
	if name == "control" {
		return ErrControlCandidate
	}

	e.candidates[name] = fnc
	return nil
}

// Compare represents the comparison functionality between a control and a
// candidate.
func (e *Experiment) Compare(fnc CompareFunc) {
	e.compare = fnc
}

// Clean will cleanup the state of a candidate (control included). This is done
// so the state could be cleaned up before storing for later comparison.
func (e *Experiment) Clean(fnc CleanFunc) {
	e.clean = fnc
}

// Force lets you overwrite the percentage. If set to true, the candidates will
// definitely run.
func (e *Experiment) Force(f bool) {
	if f {
		e.shouldRun = true
	}
}

// Ignore lets you decide if the experiment should be ignored this run or not.
// If set to true, the candidates will not run.
func (e *Experiment) Ignore(i bool) {
	if i {
		e.shouldRun = false
	}
}

// Run runs all the candidates and control in a random order. The value of the
// control function will be returned.
// If the concurrency configuration is given, this will return as soon as the
// control has finished running.
func (e *Experiment) Run() (interface{}, error) {
	// don't run the candidates, just the control
	if !e.shouldRun {
		fnc := e.candidates["control"]
		return fnc()
	}

	if e.before != nil {
		e.before()
	}

	cChan := make(chan *Observation)
	go e.run(cChan)

	obs := <-cChan
	return obs.Value, obs.Error
}

func (e *Experiment) run(cChan chan *Observation) {
	if e.Config.Concurrency {
		e.runConcurrent(cChan)
	} else {
		e.runSequential(cChan)
	}
}

func (e *Experiment) runConcurrent(cChan chan *Observation) {
	obsChan := make(chan *Observation)
	for k, v := range e.candidates {
		go func(name string, fnc CandidateFunc) {
			runCandidate(name, fnc, obsChan)
		}(k, v)
	}

	for range e.candidates {
		obs := <-obsChan

		if obs.Name == "control" {
			cChan <- obs
		}
		e.observations[obs.Name] = obs
	}

	e.conclude()
}

func (e *Experiment) runSequential(cChan chan *Observation) {
	obsChan := make(chan *Observation)
	for k, v := range e.candidates {
		go func(name string, fnc CandidateFunc) {
			runCandidate(k, v, obsChan)
		}(k, v)

		obs := <-obsChan
		e.observations[obs.Name] = obs
	}

	e.conclude()

	cChan <- e.observations["control"]
}

func (e *Experiment) conclude() {
	control := e.observations["control"]

	if e.compare != nil {
		for k, o := range e.observations {
			if k == "control" {
				continue
			}

			if o.Error == nil {
				o.Success = e.compare(control.Value, o.Value)
			}
		}
	}

	for _, o := range e.observations {
		if o.Error == nil {
			if e.clean != nil {
				o.CleanValue = e.clean(o.Value)
			} else {
				o.CleanValue = o.Value
			}
		}
	}

	if e.Config.Publisher != nil {
		for _, o := range e.observations {
			e.Config.Publisher.Publish(*o)
		}
	}
}

func runCandidate(name string, fnc CandidateFunc, obsChan chan *Observation) {
	start := time.Now()

	defer func() {
		if name == "control" {
			return
		}

		if r := recover(); r != nil {
			end := time.Now()

			obsChan <- &Observation{
				Name:     name,
				Panic:    r,
				Error:    ErrCandidatePanic,
				Duration: end.Sub(start),
			}
		}
	}()

	v, err := fnc()
	end := time.Now()

	obsChan <- &Observation{
		Name:     name,
		Value:    v,
		Error:    err,
		Duration: end.Sub(start),
	}
}
<commit_msg>Return the before error when it occurs.<commit_after>package experiment

import (
	"errors"
	"math/rand"
	"time"
)

type (
	// BeforeFunc represents the function that gets run before the experiment
	// starts. This function will only run if the experiment should run. The
	// functionality should be defined by the user.
	BeforeFunc func() error

	// CandidateFunc represents a function that is implemented by a candidate.
	// The value returned is the value that will be used to compare data.
	CandidateFunc func() (interface{}, error)

	// CleanFunc represents the function that cleans up the output data. This
	// function will only be called for candidates that did not error.
	CleanFunc func(interface{}) interface{}

	// CompareFunc represents the function that takes two candidates and knows
	// how to compare them. The functionality is implemented by the user. This
	// function will only be called for candidates that did not error.
	CompareFunc func(interface{}, interface{}) bool
)

var (
	// ErrControlCandidate is returned when a candidate is initiated with
	// control as it's name.
	ErrControlCandidate = errors.New("Can't use a candidate with the name 'control'")

	// ErrCandidatePanic represents the error that a candidate panicked.
	ErrCandidatePanic = errors.New("candidate panicked")
)

// Experiment represents a new refactoring experiment. This is where you'll
// define your control and candidates on and this will run the experiment
// according to the configuration.
type Experiment struct {
	Config *Config

	shouldRun    bool
	candidates   map[string]CandidateFunc
	observations map[string]*Observation

	before  BeforeFunc
	compare CompareFunc
	clean   CleanFunc
}

// New creates a new Experiment with the given configuration options.
func New(cfgs ...ConfigFunc) *Experiment {
	cfg := &Config{}
	for _, c := range cfgs {
		c(cfg)
	}

	return &Experiment{
		Config:       cfg,
		shouldRun:    cfg.Percentage > 0 && rand.Intn(100) <= cfg.Percentage,
		candidates:   map[string]CandidateFunc{},
		observations: map[string]*Observation{},
	}
}

// Before filter to do expensive setup only when the experiment is going to run.
// This will be skipped if the experiment doesn't need to run. A good use case
// would be to do a deep copy of a struct.
func (e *Experiment) Before(fnc BeforeFunc) {
	e.before = fnc
}

// Control represents the control function, this resembles the old or current
// implementation. This function will always run, regardless of the
// configuration percentage or overwrites. If this function panics, the
// application will panic.
// The output of this function will be the base to what all the candidates will
// be compared to.
func (e *Experiment) Control(fnc CandidateFunc) {
	e.candidates["control"] = fnc
}

// Candidate represents a refactoring solution. The order of candidates is
// randomly determined.
// If the concurrent configuration is given, candidates will run concurrently.
// If a candidate panics, your application will not panic, but the candidate
// will be marked as failed.
// If the name is control, this will error and not add the candidate.
func (e *Experiment) Candidate(name string, fnc CandidateFunc) error {
	if name == "control" {
		return ErrControlCandidate
	}

	e.candidates[name] = fnc
	return nil
}

// Compare represents the comparison functionality between a control and a
// candidate.
func (e *Experiment) Compare(fnc CompareFunc) {
	e.compare = fnc
}

// Clean will cleanup the state of a candidate (control included). This is done
// so the state could be cleaned up before storing for later comparison.
func (e *Experiment) Clean(fnc CleanFunc) {
	e.clean = fnc
}

// Force lets you overwrite the percentage. If set to true, the candidates will
// definitely run.
func (e *Experiment) Force(f bool) {
	if f {
		e.shouldRun = true
	}
}

// Ignore lets you decide if the experiment should be ignored this run or not.
// If set to true, the candidates will not run.
func (e *Experiment) Ignore(i bool) {
	if i {
		e.shouldRun = false
	}
}

// Run runs all the candidates and control in a random order. The value of the
// control function will be returned.
// If the concurrency configuration is given, this will return as soon as the
// control has finished running.
func (e *Experiment) Run() (interface{}, error) {
	// don't run the candidates, just the control
	if !e.shouldRun {
		fnc := e.candidates["control"]
		return fnc()
	}

	if e.before != nil {
		if err := e.before(); err != nil {
			return nil, err
		}
	}

	cChan := make(chan *Observation)
	go e.run(cChan)

	obs := <-cChan
	return obs.Value, obs.Error
}

func (e *Experiment) run(cChan chan *Observation) {
	if e.Config.Concurrency {
		e.runConcurrent(cChan)
	} else {
		e.runSequential(cChan)
	}
}

func (e *Experiment) runConcurrent(cChan chan *Observation) {
	obsChan := make(chan *Observation)
	for k, v := range e.candidates {
		go func(name string, fnc CandidateFunc) {
			runCandidate(name, fnc, obsChan)
		}(k, v)
	}

	for range e.candidates {
		obs := <-obsChan

		if obs.Name == "control" {
			cChan <- obs
		}
		e.observations[obs.Name] = obs
	}

	e.conclude()
}

func (e *Experiment) runSequential(cChan chan *Observation) {
	obsChan := make(chan *Observation)
	for k, v := range e.candidates {
		go func(name string, fnc CandidateFunc) {
			runCandidate(k, v, obsChan)
		}(k, v)

		obs := <-obsChan
		e.observations[obs.Name] = obs
	}

	e.conclude()

	cChan <- e.observations["control"]
}

func (e *Experiment) conclude() {
	control := e.observations["control"]

	if e.compare != nil {
		for k, o := range e.observations {
			if k == "control" {
				continue
			}

			if o.Error == nil {
				o.Success = e.compare(control.Value, o.Value)
			}
		}
	}

	for _, o := range e.observations {
		if o.Error == nil {
			if e.clean != nil {
				o.CleanValue = e.clean(o.Value)
			} else {
				o.CleanValue = o.Value
			}
		}
	}

	if e.Config.Publisher != nil {
		for _, o := range e.observations {
			e.Config.Publisher.Publish(*o)
		}
	}
}

func runCandidate(name string, fnc CandidateFunc, obsChan chan *Observation) {
	start := time.Now()

	defer func() {
		if name == "control" {
			return
		}

		if r := recover(); r != nil {
			end := time.Now()

			obsChan <- &Observation{
				Name:     name,
				Panic:    r,
				Error:    ErrCandidatePanic,
				Duration: end.Sub(start),
			}
		}
	}()

	v, err := fnc()
	end := time.Now()

	obsChan <- &Observation{
		Name:     name,
		Value:    v,
		Error:    err,
		Duration: end.Sub(start),
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"io/ioutil"
	"time"
	"net/http"
	"flapjack"
	"encoding/json"
	"gopkg.in/alecthomas/kingpin.v1"
	"github.com/go-martini/martini"
)

// State is a basic representation of a Flapjack event, with some extra field.
// The extra fields handle state expiry.
// Find more at https://github.com/flapjack/flapjack/wiki/DATA_STRUCTURES
type State struct {
	flapjack.Event
	TTL	int64  `json:"ttl"`
}

// handler caches
func CreateState(updates chan State, w http.ResponseWriter, r *http.Request) {
	var state State

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		message := "Error: Couldn't read request body: %s\n"
		log.Printf(message, err)
		fmt.Fprintf(w, message, err)
		return
	}

	err = json.Unmarshal(body, &state)
	if err != nil {
		message := "Error: Couldn't read request body: %s\n"
		log.Println(message, err)
		fmt.Fprintf(w, message, err)
		return
	}

	// Populate a time if none has been set.
	if state.Time == 0 {
		state.Time = time.Now().Unix()
	}

	if len(state.Type) == 0 {
		state.Type = "service"
	}

	if state.TTL == 0 {
		state.TTL = 300
	}

	updates <- state

	json, _ := json.Marshal(state)
	message := "Caching state: %s\n"
	log.Printf(message, json)
	fmt.Fprintf(w, message, json)
}

// cacheState stores a cache of event state to be sent to Flapjack.
// The event state is queried later when submitting events periodically
// to Flapjack.
func cacheState(updates chan State, state map[string]State) {
	for ns := range updates {
		key := ns.Entity + ":" + ns.Check
		state[key] = ns
	}
}

// submitCachedState periodically samples the cached state, sends it to Flapjack.
func submitCachedState(states map[string]State, config Config) {
	transport, err := flapjack.Dial(config.Server, config.Database)
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		os.Exit(1)
	}

	for {
		log.Printf("Number of cached states: %d\n", len(states))
		for id, state := range(states) {
			now := time.Now().Unix()
			event := flapjack.Event{
				Entity:  state.Entity,
				Check:   state.Check,
				Type:    state.Type,
				State:   state.State,
				Summary: state.Summary,
				Time:    now,
			}

			// Stale state sends UNKNOWNs
			if now - state.Time > state.TTL {
				log.Printf("State for %s is stale. Sending UNKNOWN.\n", id)
				event.State = "UNKNOWN"
				event.Summary = fmt.Sprintf("httpbroker: Cached state is stale (>%ds old)", state.TTL)
			}
			if config.Debug {
				log.Printf("Sending event data for %s\n", id)
			}
			transport.Send(event)
		}
		time.Sleep(config.Interval)
	}
}

var (
	port		= kingpin.Flag("port", "Address to bind HTTP server (default 3090)").Default("3090").OverrideDefaultFromEnvar("PORT").String()
	server		= kingpin.Flag("server", "Redis server to connect to (default localhost:6380)").Default("localhost:6380").String()
	database	= kingpin.Flag("database", "Redis database to connect to (default 0)").Int() // .Default("13").Int()
	interval	= kingpin.Flag("interval", "How often to submit events (default 10s)").Default("10s").Duration()
	debug		= kingpin.Flag("debug", "Enable verbose output (default false)").Bool()
)

type Config struct {
	Port		string
	Server		string
	Database	int
	Interval	time.Duration
	Debug		bool
}

func main() {
	kingpin.Version("0.0.1")
	kingpin.Parse()

	config := Config{
		Server: 	*server,
		Database: 	*database,
		Interval: 	*interval,
		Debug:		*debug,
		Port: 		":" + *port,
	}
	if config.Debug {
		log.Printf("Booting with config: %+v\n", config)
	}

	updates := make(chan State)
	state := map[string]State{}

	go cacheState(updates, state)
	go submitCachedState(state, config)

	m := martini.Classic()
	m.Group("/state", func(r martini.Router) {
		r.Post("", func(res http.ResponseWriter, req *http.Request) {
			CreateState(updates, res, req)
		})
		r.Get("", func() []byte {
			data, _ := json.Marshal(state)
			return data
		})
	})

	log.Fatal(http.ListenAndServe(config.Port, m))
}
<commit_msg>Ignore TTL if negative number, allowing users to opt-out of TTLs<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"io/ioutil"
	"time"
	"net/http"
	"flapjack"
	"encoding/json"
	"gopkg.in/alecthomas/kingpin.v1"
	"github.com/go-martini/martini"
)

// State is a basic representation of a Flapjack event, with some extra field.
// The extra fields handle state expiry.
// Find more at https://github.com/flapjack/flapjack/wiki/DATA_STRUCTURES
type State struct {
	flapjack.Event
	TTL	int64  `json:"ttl"`
}

// handler caches
func CreateState(updates chan State, w http.ResponseWriter, r *http.Request) {
	var state State

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		message := "Error: Couldn't read request body: %s\n"
		log.Printf(message, err)
		fmt.Fprintf(w, message, err)
		return
	}

	err = json.Unmarshal(body, &state)
	if err != nil {
		message := "Error: Couldn't read request body: %s\n"
		log.Println(message, err)
		fmt.Fprintf(w, message, err)
		return
	}

	// Populate a time if none has been set.
	if state.Time == 0 {
		state.Time = time.Now().Unix()
	}

	if len(state.Type) == 0 {
		state.Type = "service"
	}

	if state.TTL == 0 {
		state.TTL = 300
	}

	updates <- state

	json, _ := json.Marshal(state)
	message := "Caching state: %s\n"
	log.Printf(message, json)
	fmt.Fprintf(w, message, json)
}

// cacheState stores a cache of event state to be sent to Flapjack.
// The event state is queried later when submitting events periodically
// to Flapjack.
func cacheState(updates chan State, state map[string]State) {
	for ns := range updates {
		key := ns.Entity + ":" + ns.Check
		state[key] = ns
	}
}

// submitCachedState periodically samples the cached state, sends it to Flapjack.
func submitCachedState(states map[string]State, config Config) {
	transport, err := flapjack.Dial(config.Server, config.Database)
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		os.Exit(1)
	}

	for {
		log.Printf("Number of cached states: %d\n", len(states))
		for id, state := range(states) {
			now := time.Now().Unix()
			event := flapjack.Event{
				Entity:  state.Entity,
				Check:   state.Check,
				Type:    state.Type,
				State:   state.State,
				Summary: state.Summary,
				Time:    now,
			}

			// Stale state sends UNKNOWNs
			if state.TTL >= 0 && now - state.Time > state.TTL {
				log.Printf("State for %s is stale. Sending UNKNOWN.\n", id)
				event.State = "UNKNOWN"
				event.Summary = fmt.Sprintf("httpbroker: Cached state is stale (>%ds old)", state.TTL)
			}
			if config.Debug {
				log.Printf("Sending event data for %s\n", id)
			}
			transport.Send(event)
		}
		time.Sleep(config.Interval)
	}
}

var (
	port		= kingpin.Flag("port", "Address to bind HTTP server (default 3090)").Default("3090").OverrideDefaultFromEnvar("PORT").String()
	server		= kingpin.Flag("server", "Redis server to connect to (default localhost:6380)").Default("localhost:6380").String()
	database	= kingpin.Flag("database", "Redis database to connect to (default 0)").Int() // .Default("13").Int()
	interval	= kingpin.Flag("interval", "How often to submit events (default 10s)").Default("10s").Duration()
	debug		= kingpin.Flag("debug", "Enable verbose output (default false)").Bool()
)

type Config struct {
	Port		string
	Server		string
	Database	int
	Interval	time.Duration
	Debug		bool
}

func main() {
	kingpin.Version("0.0.1")
	kingpin.Parse()

	config := Config{
		Server: 	*server,
		Database: 	*database,
		Interval: 	*interval,
		Debug:		*debug,
		Port: 		":" + *port,
	}
	if config.Debug {
		log.Printf("Booting with config: %+v\n", config)
	}

	updates := make(chan State)
	state := map[string]State{}

	go cacheState(updates, state)
	go submitCachedState(state, config)

	m := martini.Classic()
	m.Group("/state", func(r martini.Router) {
		r.Post("", func(res http.ResponseWriter, req *http.Request) {
			CreateState(updates, res, req)
		})
		r.Get("", func() []byte {
			data, _ := json.Marshal(state)
			return data
		})
	})

	log.Fatal(http.ListenAndServe(config.Port, m))
}
<|endoftext|>