<commit_before>package utils

import (
	"errors"
	"sync"
	"time"
)

func defaultDelete (x interface{}) {}

const poolCleanupDelay time.Duration = time.Second * 10

var (
	allPoolsMutex sync.Mutex
	allPools []*Pool
)

func cleanupLoop() {
	for {
		<-time.After(poolCleanupDelay)

		allPoolsMutex.Lock()
		pools := make([]*Pool, len(allPools))
		copy(pools, allPools)
		allPoolsMutex.Unlock()

		for _, pool := range pools {
			pool.Cleanup()
		}
	}
}

func init() {
	go cleanupLoop()
}

type Pool struct {
	new         func() interface{}
	delete      func(interface{})

	storage     chan interface{}
}

func NewPool(new func() interface{}, delete func(interface{}), size int) (p *Pool) {
	if size <= 0 {
		panic(errors.New("pool size error"))
	}

	if delete == nil {
		delete = defaultDelete
	}

	p = &Pool{
		new: new,
		delete: delete,
		storage: make(chan interface{}, size),
	}

	allPoolsMutex.Lock()
	allPools = append(allPools, p)
	allPoolsMutex.Unlock()

	return p
}

func (p *Pool) Get() (x interface{}) {
	select {
	case x = <- p.storage:
		return x
	default:
	}

	return p.new()
}

func (p *Pool) Put(x interface{}) {
	select {
	case p.storage <- x:
	default:
		p.delete(x)
	}
}

func (p *Pool) Cleanup() {
	for x := range p.storage {
		p.delete(x)
	}
}<commit_msg>修正pool cleanup的循环错误<commit_after>package utils

import (
	"errors"
	"sync"
	"time"
)

func defaultDelete (x interface{}) {}

const poolCleanupDelay time.Duration = time.Second * 10

var (
	allPoolsMutex sync.Mutex
	allPools []*Pool
)

func cleanupLoop() {
	for {
		<-time.After(poolCleanupDelay)

		allPoolsMutex.Lock()
		pools := make([]*Pool, len(allPools))
		copy(pools, allPools)
		allPoolsMutex.Unlock()

		for _, pool := range pools {
			pool.Cleanup()
		}
	}
}

func init() {
	go cleanupLoop()
}

type Pool struct {
	new         func() interface{}
	delete      func(interface{})

	storage     chan interface{}
}

func NewPool(new func() interface{}, delete func(interface{}), size int) (p *Pool) {
	if size <= 0 {
		panic(errors.New("pool size error"))
	}

	if delete == nil {
		delete = defaultDelete
	}

	p = &Pool{
		new: new,
		delete: delete,
		storage: make(chan interface{}, size),
	}

	allPoolsMutex.Lock()
	allPools = append(allPools, p)
	allPoolsMutex.Unlock()

	return p
}

func (p *Pool) Get() (x interface{}) {
	select {
	case x = <- p.storage:
		return x
	default:
	}

	return p.new()
}

func (p *Pool) Put(x interface{}) {
	select {
	case p.storage <- x:
	default:
		p.delete(x)
	}
}

func (p *Pool) Cleanup() {
	DONE:
	for {
		select {
		case x := <- p.storage:
			p.delete(x)
		default:
			break DONE
		}
	}
}<|endoftext|>


<commit_before>package metrics

import "testing"

func TestEventEquals(t *testing.T) {
	e1 := &Event{
		Name: "foo",
		Labels: map[string]string{
			"volume": "baz",
		},
		Value: "bar",
	}
	if !e1.Equals(e1) {
		t.Fatal("Expected event to equal itself")
	}

	e2 := &Event{
		Name: "foo",
		Labels: map[string]string{
			"volume": "baz",
		},
		Value: "qux",
	}
	if !e1.Equals(e2) {
		t.Fatal("Expected event e1 to equal e2 (different value)")
	}

	e3 := &Event{
		Name: "qux",
		Labels: map[string]string{
			"volume": "baz",
		},
		Value: "bar",
	}
	if e1.Equals(e3) {
		t.Fatal("Expected event e1 to not equal e3 (different name)")
	}

	e4 := &Event{
		Name: "foo",
		Labels: map[string]string{
			"volume": "qux",
		},
		Value: "bar",
	}
	if e1.Equals(e4) {
		t.Fatal("Expected event e1 to not equal e4 (different volume)")
	}
}

func TestEventString(t *testing.T) {
	e := &Event{
		Name: "foo",
		Labels: map[string]string{
			"volume":   "baz",
			"instance": "qux",
		},
		Value: "bar",
	}
	expected := "foo{volume=\"baz\",instance=\"qux\"} bar"
	if e.String() != expected {
		t.Fatalf("Expected %s, got %s", expected, e.String())
	}
}

func TestNewMetrics(t *testing.T) {
	p := NewMetrics("foo", "http://foo:9091")

	if p.Instance != "foo" {
		t.Fatalf("Expected instance to be foo, got %s", p.Instance)
	}

	if p.PushgatewayURL != "http://foo:9091" {
		t.Fatalf("Expected URL to be http://foo:9091, got %s", p.PushgatewayURL)
	}

	if len(p.Metrics) != 0 {
		t.Fatal("Expected empty Metrics array, got size %i", len(p.Metrics))
	}
}

func TestNewMetric(t *testing.T) {
	p := NewMetrics("foo", "http://foo:9091")
	m := p.NewMetric("bar", "qux")

	if len(p.Metrics) != 1 {
		t.Fatalf("Expected 1 metric, got %i", len(p.Metrics))
	}

	if p.Metrics["bar"] != m {
		t.Fatal("Expected to find metric in handler")
	}

	if m.Name != "bar" {
		t.Fatalf("Expected name to be bar, got %s", m.Name)
	}

	if m.Type != "qux" {
		t.Fatalf("Expected type to be qux, got %s", m.Name)
	}
}

func TestParseEvent(t *testing.T) {
	if e := parseEvent(""); e != nil {
		t.Fatalf("Expected empty line to return nil, got %v", e)
	}

	if e := parseEvent("# HELP foo Some foo metric"); e != nil {
		t.Fatalf("Expected help line to return nil, got %v", e)
	}

	if e := parseEvent("# TYPE foo gauge"); e != nil {
		t.Fatalf("Expected type line to return nil, got %v", e)
	}

	if e := parseEvent("foo{bar=\"qux\"} 0"); e != nil {
		t.Fatalf("Expected non-conplicity event to return nil, got %v", e)
	}

	e := parseEvent("conplicity_foo{bar=\"qux\",baz=\"abc\"} 0")
	if e == nil {
		t.Fatal("Expected an event, got nil")
	}
	if e.Name != "conplicity_foo" {
		t.Fatalf("Expected event name to be conplicity_foo, got %s", e.Name)
	}
	if e.Value != "0" {
		t.Fatalf("Expected event value to be 0, got %s", e.Value)
	}
	if len(e.Labels) != 2 {
		t.Fatalf("Expected event to have two labels, got %s", len(e.Labels))
	}
	if e.Labels["bar"] != "qux" {
		t.Fatalf("Expected event's bar label to be \"qux\", got %s", e.Labels["bar"])
	}
}

func TestMetricUpdateEvent(t *testing.T) {
	m := &Metric{
		Name: "foo",
	}
	if len(m.Events) != 0 {
		t.Fatal("Expected no events, got %i", len(m.Events))
	}

	// Add event
	e1 := &Event{
		Name: "foo",
		Labels: map[string]string{
			"volume": "baz",
		},
		Value: "bar",
	}
	m.UpdateEvent(e1)
	if len(m.Events) != 1 {
		t.Fatal("Expected one event, got %i", len(m.Events))
	}
	if m.Events[0].Name != "foo" {
		t.Fatalf("Expected event name to be foo, got %s", m.Events[0].Name)
	}
	if m.Events[0].Value != "bar" {
		t.Fatalf("Expected event value to be bar, got %s", m.Events[0].Value)
	}

	// Update event
	e2 := &Event{
		Name: "foo",
		Labels: map[string]string{
			"volume": "baz",
		},
		Value: "qux",
	}
	m.UpdateEvent(e2)
	if len(m.Events) != 1 {
		t.Fatal("Expected one event, got %i", len(m.Events))
	}
	if m.Events[0].Name != "foo" {
		t.Fatalf("Expected event name to be foo, got %s", m.Events[0].Name)
	}
	if m.Events[0].Value != "qux" {
		t.Fatalf("Expected event value to be qux, got %s", m.Events[0].Value)
	}

	// Add new event
	e3 := &Event{
		Name: "bar",
		Labels: map[string]string{
			"volume": "baz",
		},
		Value: "quxx",
	}
	m.UpdateEvent(e3)
	if len(m.Events) != 2 {
		t.Fatal("Expected two events, got %i", len(m.Events))
	}
	if m.Events[1].Name != "bar" {
		t.Fatalf("Expected event name to be bar, got %s", m.Events[1].Name)
	}
	if m.Events[1].Value != "quxx" {
		t.Fatalf("Expected event value to be quxx, got %s", m.Events[1].Value)
	}
}
<commit_msg>Use Fatalf<commit_after>package metrics

import "testing"

func TestEventEquals(t *testing.T) {
	e1 := &Event{
		Name: "foo",
		Labels: map[string]string{
			"volume": "baz",
		},
		Value: "bar",
	}
	if !e1.Equals(e1) {
		t.Fatal("Expected event to equal itself")
	}

	e2 := &Event{
		Name: "foo",
		Labels: map[string]string{
			"volume": "baz",
		},
		Value: "qux",
	}
	if !e1.Equals(e2) {
		t.Fatal("Expected event e1 to equal e2 (different value)")
	}

	e3 := &Event{
		Name: "qux",
		Labels: map[string]string{
			"volume": "baz",
		},
		Value: "bar",
	}
	if e1.Equals(e3) {
		t.Fatal("Expected event e1 to not equal e3 (different name)")
	}

	e4 := &Event{
		Name: "foo",
		Labels: map[string]string{
			"volume": "qux",
		},
		Value: "bar",
	}
	if e1.Equals(e4) {
		t.Fatal("Expected event e1 to not equal e4 (different volume)")
	}
}

func TestEventString(t *testing.T) {
	e := &Event{
		Name: "foo",
		Labels: map[string]string{
			"volume":   "baz",
			"instance": "qux",
		},
		Value: "bar",
	}
	expected := "foo{volume=\"baz\",instance=\"qux\"} bar"
	if e.String() != expected {
		t.Fatalf("Expected %s, got %s", expected, e.String())
	}
}

func TestNewMetrics(t *testing.T) {
	p := NewMetrics("foo", "http://foo:9091")

	if p.Instance != "foo" {
		t.Fatalf("Expected instance to be foo, got %s", p.Instance)
	}

	if p.PushgatewayURL != "http://foo:9091" {
		t.Fatalf("Expected URL to be http://foo:9091, got %s", p.PushgatewayURL)
	}

	if len(p.Metrics) != 0 {
		t.Fatal("Expected empty Metrics array, got size %i", len(p.Metrics))
	}
}

func TestNewMetric(t *testing.T) {
	p := NewMetrics("foo", "http://foo:9091")
	m := p.NewMetric("bar", "qux")

	if len(p.Metrics) != 1 {
		t.Fatalf("Expected 1 metric, got %i", len(p.Metrics))
	}

	if p.Metrics["bar"] != m {
		t.Fatal("Expected to find metric in handler")
	}

	if m.Name != "bar" {
		t.Fatalf("Expected name to be bar, got %s", m.Name)
	}

	if m.Type != "qux" {
		t.Fatalf("Expected type to be qux, got %s", m.Name)
	}
}

func TestParseEvent(t *testing.T) {
	if e := parseEvent(""); e != nil {
		t.Fatalf("Expected empty line to return nil, got %v", e)
	}

	if e := parseEvent("# HELP foo Some foo metric"); e != nil {
		t.Fatalf("Expected help line to return nil, got %v", e)
	}

	if e := parseEvent("# TYPE foo gauge"); e != nil {
		t.Fatalf("Expected type line to return nil, got %v", e)
	}

	if e := parseEvent("foo{bar=\"qux\"} 0"); e != nil {
		t.Fatalf("Expected non-conplicity event to return nil, got %v", e)
	}

	e := parseEvent("conplicity_foo{bar=\"qux\",baz=\"abc\"} 0")
	if e == nil {
		t.Fatal("Expected an event, got nil")
	}
	if e.Name != "conplicity_foo" {
		t.Fatalf("Expected event name to be conplicity_foo, got %s", e.Name)
	}
	if e.Value != "0" {
		t.Fatalf("Expected event value to be 0, got %s", e.Value)
	}
	if len(e.Labels) != 2 {
		t.Fatalf("Expected event to have two labels, got %s", len(e.Labels))
	}
	if e.Labels["bar"] != "qux" {
		t.Fatalf("Expected event's bar label to be \"qux\", got %s", e.Labels["bar"])
	}
}

func TestMetricUpdateEvent(t *testing.T) {
	m := &Metric{
		Name: "foo",
	}
	if len(m.Events) != 0 {
		t.Fatalf("Expected no events, got %i", len(m.Events))
	}

	// Add event
	e1 := &Event{
		Name: "foo",
		Labels: map[string]string{
			"volume": "baz",
		},
		Value: "bar",
	}
	m.UpdateEvent(e1)
	if len(m.Events) != 1 {
		t.Fatalf("Expected one event, got %i", len(m.Events))
	}
	if m.Events[0].Name != "foo" {
		t.Fatalf("Expected event name to be foo, got %s", m.Events[0].Name)
	}
	if m.Events[0].Value != "bar" {
		t.Fatalf("Expected event value to be bar, got %s", m.Events[0].Value)
	}

	// Update event
	e2 := &Event{
		Name: "foo",
		Labels: map[string]string{
			"volume": "baz",
		},
		Value: "qux",
	}
	m.UpdateEvent(e2)
	if len(m.Events) != 1 {
		t.Fatalf("Expected one event, got %i", len(m.Events))
	}
	if m.Events[0].Name != "foo" {
		t.Fatalf("Expected event name to be foo, got %s", m.Events[0].Name)
	}
	if m.Events[0].Value != "qux" {
		t.Fatalf("Expected event value to be qux, got %s", m.Events[0].Value)
	}

	// Add new event
	e3 := &Event{
		Name: "bar",
		Labels: map[string]string{
			"volume": "baz",
		},
		Value: "quxx",
	}
	m.UpdateEvent(e3)
	if len(m.Events) != 2 {
		t.Fatalf("Expected two events, got %i", len(m.Events))
	}
	if m.Events[1].Name != "bar" {
		t.Fatalf("Expected event name to be bar, got %s", m.Events[1].Name)
	}
	if m.Events[1].Value != "quxx" {
		t.Fatalf("Expected event value to be quxx, got %s", m.Events[1].Value)
	}
}
<|endoftext|>


<commit_before>package govalidator

import "testing"

func TestContains(t *testing.T) {
	tests1 := []string{"abacada", "abacada", "abacada", "abacada"}
	tests2 := []string{"", "ritir", "a", "aca"}
	expected := []bool{true, false, true, true}
	for i := 0; i < len(tests1); i++ {
		result := Contains(tests1[i], tests2[i])
		if result != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", result)
			t.FailNow()
		}
	}
}

func TestMatches(t *testing.T) {
	tests1 := []string{"123456789", "abacada", "111222333", "abacaba"}
	tests2 := []string{"[0-9]+", "cab$", "((111|222|333)+)+", "((123+]"}
	expected := []bool{true, false, true, false}
	for i := 0; i < len(tests1); i++ {
		result := Matches(tests1[i], tests2[i])
		if result != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", result)
			t.FailNow()
		}
	}
}

func TestLeftTrim(t *testing.T) {
	tests1 := []string{"  \r\n\tfoo  \r\n\t   ", "010100201000"}
	tests2 := []string{"", "01"}
	expected := []string{"foo  \r\n\t   ", "201000"}
	for i := 0; i < len(tests1); i++ {
		result := LeftTrim(tests1[i], tests2[i])
		if result != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", result)
			t.FailNow()
		}
	}
}

func TestRightTrim(t *testing.T) {
	tests1 := []string{"  \r\n\tfoo  \r\n\t   ", "010100201000"}
	tests2 := []string{"", "01"}
	expected := []string{"  \r\n\tfoo", "0101002"}
	for i := 0; i < len(tests1); i++ {
		result := RightTrim(tests1[i], tests2[i])
		if result != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", result)
			t.FailNow()
		}
	}
}

func TestTrim(t *testing.T) {
	tests1 := []string{"  \r\n\tfoo  \r\n\t   ", "010100201000", "1234567890987654321"}
	tests2 := []string{"", "01", "1-8"}
	expected := []string{"foo", "2", "909"}
	for i := 0; i < len(tests1); i++ {
		result := Trim(tests1[i], tests2[i])
		if result != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", result)
			t.FailNow()
		}
	}
}

// This small example illustrate how to work with Trim function.
func ExampleTrim() {
	// Remove from left and right spaces and "\r", "\n", "\t" characters
	println(Trim("   \r\r\ntext\r   \t\n", "") == "text")
	// Remove from left and right characters that are between "1" and "8".
	// "1-8" is like full list "12345678".
	println(Trim("1234567890987654321", "1-8") == "909")
}

func TestWhiteList(t *testing.T) {
	tests1 := []string{"abcdef", "aaaaaaaaaabbbbbbbbbb", "a1b2c3", "   ", "a3a43a5a4a3a2a23a4a5a4a3a4"}
	tests2 := []string{"abc", "abc", "abc", "abc", "a-z"}
	expected := []string{"abc", "aaaaaaaaaabbbbbbbbbb", "abc", "", "aaaaaaaaaaaa"}
	for i := 0; i < len(tests1); i++ {
		result := WhiteList(tests1[i], tests2[i])
		if result != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", result)
			t.FailNow()
		}
	}
}

// This small example illustrate how to work with WhiteList function.
func ExampleWhiteList() {
	// Remove all characters from string ignoring characters between "a" and "z"
	println(WhiteList("a3a43a5a4a3a2a23a4a5a4a3a4", "a-z") == "aaaaaaaaaaaa")
}

func TestBlackList(t *testing.T) {
	tests1 := []string{"abcdef", "aaaaaaaaaabbbbbbbbbb", "a1b2c3", "   "}
	tests2 := []string{"abc", "abc", "abc", "abc"}
	expected := []string{"def", "", "123", "   "}
	for i := 0; i < len(tests1); i++ {
		result := BlackList(tests1[i], tests2[i])
		if result != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", result)
			t.FailNow()
		}
	}
}

func TestStripLow(t *testing.T) {
	tests1 := []string{"foo\x00", "\x7Ffoo\x02", "\x01\x09", "foo\x0A\x0D", "perch\u00e9", "\u20ac",
		"\u2206\x0A", "foo\x0A\x0D", "\x03foo\x0A\x0D"}
	tests2 := []bool{false, false, false, false, false, false, false, true, true}
	expected := []string{"foo", "foo", "", "foo", "perch\u00e9", "\u20ac", "\u2206", "foo\x0A\x0D", "foo\x0A\x0D"}
	for i := 0; i < len(tests1); i++ {
		result := StripLow(tests1[i], tests2[i])
		if result != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", result)
			t.FailNow()
		}
	}
}

func TestReplacePattern(t *testing.T) {
	tests1 := []string{"ab123ba", "abacaba", "httpftp://github.comio", "aaaaaaaaaa", "http123123ftp://git534543hub.comio"}
	tests2 := []string{"[0-9]+", "[0-9]+", "(ftp|io)", "a", "(ftp|io|[0-9]+)"}
	tests3 := []string{"aca", "aca", "", "", ""}
	expected := []string{"abacaba", "abacaba", "http://github.com", "", "http://github.com"}
	for i := 0; i < len(tests1); i++ {
		result := ReplacePattern(tests1[i], tests2[i], tests3[i])
		if result != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", result)
			t.FailNow()
		}
	}
}

// This small example illustrate how to work with ReplacePattern function.
func ExampleReplacePattern() {
	// Replace in "http123123ftp://git534543hub.comio" following (pattern "(ftp|io|[0-9]+)"):
	// - Sequence "ftp".
	// - Sequence "io".
	// - Sequence of digits.
	// with empty string.
	println(ReplacePattern("http123123ftp://git534543hub.comio", "(ftp|io|[0-9]+)", "") == "http://github.com")
}

func TestEscape(t *testing.T) {
	tests := []string{`<img alt="foo&bar">`}
	expected := []string{"<img alt="foo&bar">"}
	for i := 0; i < len(tests); i++ {
		res := Escape(tests[i])
		if res != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", res)
			t.FailNow()
		}
	}
}

func TestUnderscoreToCamelCase(t *testing.T) {
	tests := []string{"a_b_c", "my_func", "1ab_cd"}
	expected := []string{"ABC", "MyFunc", "1abCd"}
	for i := 0; i < len(tests); i++ {
		res := UnderscoreToCamelCase(tests[i])
		if res != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", res)
			t.FailNow()
		}
	}
}

func TestCamelCaseToUnderscore(t *testing.T) {
	tests := []string{"MyFunc", "ABC", "1B"}
	expected := []string{"my_func", "a_b_c", "1_b"}
	for i := 0; i < len(tests); i++ {
		res := CamelCaseToUnderscore(tests[i])
		if res != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", res)
			t.FailNow()
		}
	}
}

func TestReverse(t *testing.T) {
	tests := []string{"abc", "ｶﾀｶﾅ"}
	expected := []string{"cba", "ﾅｶﾀｶ"}
	for i := 0; i < len(tests); i++ {
		res := Reverse(tests[i])
		if res != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", res)
			t.FailNow()
		}
	}
}

func TestGetLines(t *testing.T) {
	tests := []string{"abc", "a\nb\nc"}
	expected := []([]string){{"abc"}, {"a", "b", "c"}}
	for i := 0; i < len(tests); i++ {
		res := GetLines(tests[i])
		for j := 0; j < len(res); j++ {
			if res[j] != expected[i][j] {
				t.Log("Case ", i, ": expected ", expected[i], " when result is ", res)
				t.FailNow()
			}
		}
	}
}

func TestGetLine(t *testing.T) {
	tests1 := []string{"abc", "a\nb\nc", "abc", "abacaba\n", "abc"}
	tests2 := []int{0, 0, -1, 1, 3}
	expected := []string{"abc", "a", "", "", ""}
	for i := 0; i < len(tests1); i++ {
		res, _ := GetLine(tests1[i], tests2[i])
		if res != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", res)
			t.FailNow()
		}
	}
}

func TestRemoveTags(t *testing.T) {
	tests := []string{"abc", "", "

Text

", `<a href="#">Link</a>`}
	expected := []string{"abc", "", "Text", "Link"}
	for i := 0; i < len(tests); i++ {
		res := RemoveTags(tests[i])
		if res != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", res)
			t.FailNow()
		}
	}
}

func TestSafeFileName(t *testing.T) {
	tests := []string{"abc", "123456789     '_-?ASDF@£$%£%^é.html", "ReadMe.md", "file:///c:/test.go", "../../../Hello World!.txt"}
	expected := []string{"abc", "123456789-asdf.html", "readme.md", "test.go", "hello-world.txt"}
	for i := 0; i < len(tests); i++ {
		res := SafeFileName(tests[i])
		if res != expected[i] {
			t.Log("Case ", i, ": expected ", expected[i], " when result is ", res)
			t.FailNow()
		}
	}
}

func TestNormalizeEmail(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param    string
		expected string
	}{
		{`test@me.com`, `test@me.com`},
		{`some.name@gmail.com`, `somename@gmail.com`},
		{`some.name@googlemail.com`, `somename@gmail.com`},
		{`some.name+extension@gmail.com`, `somename@gmail.com`},
		{`some.name+extension@googlemail.com`, `somename@gmail.com`},
		{`some.name.middlename+extension@gmail.com`, `somenamemiddlename@gmail.com`},
		{`some.name.middlename+extension@googlemail.com`, `somenamemiddlename@gmail.com`},
		{`some.name.midd.lena.me.+extension@gmail.com`, `somenamemiddlename@gmail.com`},
		{`some.name.midd.lena.me.+extension@googlemail.com`, `somenamemiddlename@gmail.com`},
		{`some.name+extension@unknown.com`, `some.name+extension@unknown.com`},
		{`hans@m端ller.com`, `hans@m端ller.com`},
	}
	for _, test := range tests {
		actual, err := NormalizeEmail(test.param)
		if actual != test.expected {
			t.Errorf("Expected NormalizeEmail(%q) to be %v, got %v, err %v", test.param, test.expected, actual, err)
		}
	}
}
<commit_msg>improved tests<commit_after>package govalidator

import (
	"reflect"
	"testing"
)

func TestContains(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param1   string
		param2   string
		expected bool
	}{
		{"abacada", "", true},
		{"abacada", "ritir", false},
		{"abacada", "a", true},
		{"abacada", "aca", true},
	}
	for _, test := range tests {
		actual := Contains(test.param1, test.param2)
		if actual != test.expected {
			t.Errorf("Expected Contains(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
		}
	}
}

func TestMatches(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param1   string
		param2   string
		expected bool
	}{
		{"123456789", "[0-9]+", true},
		{"abacada", "cab$", false},
		{"111222333", "((111|222|333)+)+", true},
		{"abacaba", "((123+]", false},
	}
	for _, test := range tests {
		actual := Matches(test.param1, test.param2)
		if actual != test.expected {
			t.Errorf("Expected Matches(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
		}
	}
}

func TestLeftTrim(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param1   string
		param2   string
		expected string
	}{
		{"  \r\n\tfoo  \r\n\t   ", "", "foo  \r\n\t   "},
		{"010100201000", "01", "201000"},
	}
	for _, test := range tests {
		actual := LeftTrim(test.param1, test.param2)
		if actual != test.expected {
			t.Errorf("Expected LeftTrim(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
		}
	}
}

func TestRightTrim(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param1   string
		param2   string
		expected string
	}{
		{"  \r\n\tfoo  \r\n\t   ", "", "  \r\n\tfoo"},
		{"010100201000", "01", "0101002"},
	}
	for _, test := range tests {
		actual := RightTrim(test.param1, test.param2)
		if actual != test.expected {
			t.Errorf("Expected RightTrim(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
		}
	}
}

func TestTrim(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param1   string
		param2   string
		expected string
	}{
		{"  \r\n\tfoo  \r\n\t   ", "", "foo"},
		{"010100201000", "01", "2"},
		{"1234567890987654321", "1-8", "909"},
	}
	for _, test := range tests {
		actual := Trim(test.param1, test.param2)
		if actual != test.expected {
			t.Errorf("Expected Trim(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
		}
	}
}

// This small example illustrate how to work with Trim function.
func ExampleTrim() {
	// Remove from left and right spaces and "\r", "\n", "\t" characters
	println(Trim("   \r\r\ntext\r   \t\n", "") == "text")
	// Remove from left and right characters that are between "1" and "8".
	// "1-8" is like full list "12345678".
	println(Trim("1234567890987654321", "1-8") == "909")
}

func TestWhiteList(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param1   string
		param2   string
		expected string
	}{
		{"abcdef", "abc", "abc"},
		{"aaaaaaaaaabbbbbbbbbb", "abc", "aaaaaaaaaabbbbbbbbbb"},
		{"a1b2c3", "abc", "abc"},
		{"   ", "abc", ""},
		{"a3a43a5a4a3a2a23a4a5a4a3a4", "a-z", "aaaaaaaaaaaa"},
	}
	for _, test := range tests {
		actual := WhiteList(test.param1, test.param2)
		if actual != test.expected {
			t.Errorf("Expected WhiteList(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
		}
	}
}

// This small example illustrate how to work with WhiteList function.
func ExampleWhiteList() {
	// Remove all characters from string ignoring characters between "a" and "z"
	println(WhiteList("a3a43a5a4a3a2a23a4a5a4a3a4", "a-z") == "aaaaaaaaaaaa")
}

func TestBlackList(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param1   string
		param2   string
		expected string
	}{
		{"abcdef", "abc", "def"},
		{"aaaaaaaaaabbbbbbbbbb", "abc", ""},
		{"a1b2c3", "abc", "123"},
		{"   ", "abc", "   "},
		{"a3a43a5a4a3a2a23a4a5a4a3a4", "a-z", "34354322345434"},
	}
	for _, test := range tests {
		actual := BlackList(test.param1, test.param2)
		if actual != test.expected {
			t.Errorf("Expected BlackList(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
		}
	}
}

func TestStripLow(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param1   string
		param2   bool
		expected string
	}{
		{"foo\x00", false, "foo"},
		{"\x7Ffoo\x02", false, "foo"},
		{"\x01\x09", false, ""},
		{"foo\x0A\x0D", false, "foo"},
		{"perch\u00e9", false, "perch\u00e9"},
		{"\u20ac", false, "\u20ac"},
		{"\u2206\x0A", false, "\u2206"},
		{"foo\x0A\x0D", true, "foo\x0A\x0D"},
		{"\x03foo\x0A\x0D", true, "foo\x0A\x0D"},
	}
	for _, test := range tests {
		actual := StripLow(test.param1, test.param2)
		if actual != test.expected {
			t.Errorf("Expected StripLow(%q,%t) to be %v, got %v", test.param1, test.param2, test.expected, actual)
		}
	}
}

func TestReplacePattern(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param1   string
		param2   string
		param3   string
		expected string
	}{
		{"ab123ba", "[0-9]+", "aca", "abacaba"},
		{"abacaba", "[0-9]+", "aca", "abacaba"},
		{"httpftp://github.comio", "(ftp|io)", "", "http://github.com"},
		{"aaaaaaaaaa", "a", "", ""},
		{"http123123ftp://git534543hub.comio", "(ftp|io|[0-9]+)", "", "http://github.com"},
	}
	for _, test := range tests {
		actual := ReplacePattern(test.param1, test.param2, test.param3)
		if actual != test.expected {
			t.Errorf("Expected ReplacePattern(%q,%q,%q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual)
		}
	}
}

// This small example illustrate how to work with ReplacePattern function.
func ExampleReplacePattern() {
	// Replace in "http123123ftp://git534543hub.comio" following (pattern "(ftp|io|[0-9]+)"):
	// - Sequence "ftp".
	// - Sequence "io".
	// - Sequence of digits.
	// with empty string.
	println(ReplacePattern("http123123ftp://git534543hub.comio", "(ftp|io|[0-9]+)", "") == "http://github.com")
}

func TestEscape(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param    string
		expected string
	}{
		{`<img alt="foo&bar">`, "<img alt="foo&bar">"},
	}
	for _, test := range tests {
		actual := Escape(test.param)
		if actual != test.expected {
			t.Errorf("Expected Escape(%q) to be %v, got %v", test.param, test.expected, actual)
		}
	}
}

func TestUnderscoreToCamelCase(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param    string
		expected string
	}{
		{"a_b_c", "ABC"},
		{"my_func", "MyFunc"},
		{"1ab_cd", "1abCd"},
	}
	for _, test := range tests {
		actual := UnderscoreToCamelCase(test.param)
		if actual != test.expected {
			t.Errorf("Expected UnderscoreToCamelCase(%q) to be %v, got %v", test.param, test.expected, actual)
		}
	}
}

func TestCamelCaseToUnderscore(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param    string
		expected string
	}{
		{"MyFunc", "my_func"},
		{"ABC", "a_b_c"},
		{"1B", "1_b"},
	}
	for _, test := range tests {
		actual := CamelCaseToUnderscore(test.param)
		if actual != test.expected {
			t.Errorf("Expected CamelCaseToUnderscore(%q) to be %v, got %v", test.param, test.expected, actual)
		}
	}
}

func TestReverse(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param    string
		expected string
	}{
		{"abc", "cba"},
		{"ｶﾀｶﾅ", "ﾅｶﾀｶ"},
	}
	for _, test := range tests {
		actual := Reverse(test.param)
		if actual != test.expected {
			t.Errorf("Expected Reverse(%q) to be %v, got %v", test.param, test.expected, actual)
		}
	}
}

func TestGetLines(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param    string
		expected []string
	}{
		{"abc", []string{"abc"}},
		{"a\nb\nc", []string{"a", "b", "c"}},
	}
	for _, test := range tests {
		actual := GetLines(test.param)
		if !reflect.DeepEqual(actual, test.expected) {
			t.Errorf("Expected GetLines(%q) to be %v, got %v", test.param, test.expected, actual)
		}
	}
}

func TestGetLine(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param1   string
		param2   int
		expected string
	}{
		{"abc", 0, "abc"},
		{"a\nb\nc", 0, "a"},
		{"abc", -1, ""},
		{"abacaba\n", 1, ""},
		{"abc", 3, ""},
	}
	for _, test := range tests {
		actual, _ := GetLine(test.param1, test.param2)
		if actual != test.expected {
			t.Errorf("Expected GetLine(%q, %d) to be %v, got %v", test.param1, test.param2, test.expected, actual)
		}
	}
}

func TestRemoveTags(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param    string
		expected string
	}{
		{"abc", "abc"},
		{"", ""},
		{"

Text

", "Text"},
		{`<a href="#">Link</a>`, "Link"},
	}
	for _, test := range tests {
		actual := RemoveTags(test.param)
		if actual != test.expected {
			t.Errorf("Expected RemoveTags(%q) to be %v, got %v", test.param, test.expected, actual)
		}
	}
}

func TestSafeFileName(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param    string
		expected string
	}{
		{"abc", "abc"},
		{"123456789     '_-?ASDF@£$%£%^é.html", "123456789-asdf.html"},
		{"ReadMe.md", "readme.md"},
		{"file:///c:/test.go", "test.go"},
		{"../../../Hello World!.txt", "hello-world.txt"},
	}
	for _, test := range tests {
		actual := SafeFileName(test.param)
		if actual != test.expected {
			t.Errorf("Expected SafeFileName(%q) to be %v, got %v", test.param, test.expected, actual)
		}
	}
}

func TestNormalizeEmail(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		param    string
		expected string
	}{
		{`test@me.com`, `test@me.com`},
		{`some.name@gmail.com`, `somename@gmail.com`},
		{`some.name@googlemail.com`, `somename@gmail.com`},
		{`some.name+extension@gmail.com`, `somename@gmail.com`},
		{`some.name+extension@googlemail.com`, `somename@gmail.com`},
		{`some.name.middlename+extension@gmail.com`, `somenamemiddlename@gmail.com`},
		{`some.name.middlename+extension@googlemail.com`, `somenamemiddlename@gmail.com`},
		{`some.name.midd.lena.me.+extension@gmail.com`, `somenamemiddlename@gmail.com`},
		{`some.name.midd.lena.me.+extension@googlemail.com`, `somenamemiddlename@gmail.com`},
		{`some.name+extension@unknown.com`, `some.name+extension@unknown.com`},
		{`hans@m端ller.com`, `hans@m端ller.com`},
	}
	for _, test := range tests {
		actual, err := NormalizeEmail(test.param)
		if actual != test.expected {
			t.Errorf("Expected NormalizeEmail(%q) to be %v, got %v, err %v", test.param, test.expected, actual, err)
		}
	}
}
<|endoftext|>


<commit_before>package limiter

import (
	"net"
	"net/http"
	"net/url"
	"testing"

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

// TestGetIP tests GetIP() function.
func TestGetIP(t *testing.T) {
	//
	// RemoteAddr
	//

	expected := net.ParseIP("8.8.8.8")

	r := http.Request{
		URL:        &url.URL{Path: "/"},
		Header:     http.Header{},
		RemoteAddr: "8.8.8.8:8888",
	}

	ip := GetIP(&r)
	assert.Equal(t, expected, ip)

	//
	// X-Forwarded-For
	//

	expected = net.ParseIP("9.9.9.9")

	r = http.Request{
		URL:        &url.URL{Path: "/foo"},
		Header:     http.Header{},
		RemoteAddr: "8.8.8.8:8888",
	}

	r.Header.Add("X-Forwarded-For", "9.9.9.9, 7.7.7.7, 6.6.6.6")
	ip = GetIP(&r)
	assert.Equal(t, expected, ip)

	//
	// X-Real-IP
	//

	expected = net.ParseIP("6.6.6.6")

	r = http.Request{
		URL:        &url.URL{Path: "/bar"},
		Header:     http.Header{},
		RemoteAddr: "8.8.8.8:8888",
	}

	r.Header.Add("X-Real-IP", "6.6.6.6")
	ip = GetIP(&r)
	assert.Equal(t, expected, ip)
}
<commit_msg>refactor: update unit test for utils<commit_after>package limiter_test

import (
	"fmt"
	"net"
	"net/http"
	"net/url"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/ulule/limiter"
)

func TestGetIP(t *testing.T) {
	is := require.New(t)

	request1 := &http.Request{
		URL:        &url.URL{Path: "/"},
		Header:     http.Header{},
		RemoteAddr: "8.8.8.8:8888",
	}

	request2 := &http.Request{
		URL:        &url.URL{Path: "/foo"},
		Header:     http.Header{},
		RemoteAddr: "8.8.8.8:8888",
	}
	request2.Header.Add("X-Forwarded-For", "9.9.9.9, 7.7.7.7, 6.6.6.6")

	request3 := &http.Request{
		URL:        &url.URL{Path: "/bar"},
		Header:     http.Header{},
		RemoteAddr: "8.8.8.8:8888",
	}
	request3.Header.Add("X-Real-IP", "6.6.6.6")

	scenarios := []struct {
		request  *http.Request
		expected net.IP
	}{
		{
			//
			// Scenario #1 : RemoteAddr
			//
			request:  request1,
			expected: net.ParseIP("8.8.8.8"),
		},
		{
			//
			// Scenario #2 : X-Forwarded-For
			//
			request:  request2,
			expected: net.ParseIP("9.9.9.9"),
		},
		{
			//
			// Scenario #3 : X-Real-IP
			//
			request:  request3,
			expected: net.ParseIP("6.6.6.6"),
		},
	}

	for i, scenario := range scenarios {
		message := fmt.Sprintf("Scenario #%d", (i + 1))
		ip := limiter.GetIP(scenario.request)
		is.Equal(scenario.expected, ip, message)
	}
}

func TestGetIPKey(t *testing.T) {
	is := require.New(t)

	request1 := &http.Request{
		URL:        &url.URL{Path: "/"},
		Header:     http.Header{},
		RemoteAddr: "8.8.8.8:8888",
	}

	request2 := &http.Request{
		URL:        &url.URL{Path: "/foo"},
		Header:     http.Header{},
		RemoteAddr: "8.8.8.8:8888",
	}
	request2.Header.Add("X-Forwarded-For", "9.9.9.9, 7.7.7.7, 6.6.6.6")

	request3 := &http.Request{
		URL:        &url.URL{Path: "/bar"},
		Header:     http.Header{},
		RemoteAddr: "8.8.8.8:8888",
	}
	request3.Header.Add("X-Real-IP", "6.6.6.6")

	scenarios := []struct {
		request  *http.Request
		expected string
	}{
		{
			//
			// Scenario #1 : RemoteAddr
			//
			request:  request1,
			expected: "8.8.8.8",
		},
		{
			//
			// Scenario #2 : X-Forwarded-For
			//
			request:  request2,
			expected: "9.9.9.9",
		},
		{
			//
			// Scenario #3 : X-Real-IP
			//
			request:  request3,
			expected: "6.6.6.6",
		},
	}

	for i, scenario := range scenarios {
		message := fmt.Sprintf("Scenario #%d", (i + 1))
		key := limiter.GetIPKey(scenario.request)
		is.Equal(scenario.expected, key, message)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/gob"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"sort"
	"strconv"
	"strings"
	"time"
)

const (
	ucdUrl        = "http://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt"
	indexFileName = "runefinder-index.gob"
)

type RuneSlice []rune

func (rs RuneSlice) Len() int           { return len(rs) }
func (rs RuneSlice) Less(i, j int) bool { return rs[i] < rs[j] }
func (rs RuneSlice) Swap(i, j int)      { rs[i], rs[j] = rs[j], rs[i] }

type RuneSet map[rune]struct{}

func (rs RuneSet) Put(key rune) {
	rs[key] = struct{}{} // zero-byte struct
}

func (rs RuneSet) Contains(key rune) bool {
	_, found := rs[key]
	return found
}

func (rs RuneSet) Intersection(other RuneSet) RuneSet {
	result := RuneSet{}
	for k := range rs {
		if other.Contains(k) {
			result.Put(k)
		}
	}
	return result
}

func (rs RuneSet) ToRuneSlice() RuneSlice {
	result := RuneSlice{}
	for uchar := range rs {
		result = append(result, uchar)
	}
	return result
}

func (rs RuneSet) String() string {
	sl := rs.ToRuneSlice()
	sort.Sort(sl)
	str := "❮"
	for i, uchar := range sl {
		if i > 0 {
			str += " "
		}
		str += fmt.Sprintf("U+%04X", uchar)
	}
	return str + "❯"
}

type RuneIndex struct {
	Characters map[string]RuneSet
	Names      map[rune]string
}

func progressDisplay(running <-chan bool) {
	for {
		select {
		case <-running:
			fmt.Println()
		case <-time.After(200 * time.Millisecond):
			fmt.Print(".")
		}
	}
}

func getUcdLines() []string {
	fmt.Printf("Index not found. Retrieving data from:\n%s\n", ucdUrl)
	running := make(chan bool)
	go progressDisplay(running)
	defer func() {
		running <- false
	}()
	response, err := http.Get(ucdUrl)
	if err != nil {
		log.Fatal("getUcdFile/http.Get:", err)
	}
	content, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Fatal("buildIndex/ioutil.ReadAll:", err)
	}
	defer response.Body.Close()
	return strings.Split(string(content), "\n")
}

func buildIndex(indexPath string) RuneIndex {
	var index RuneIndex
	index.Characters = map[string]RuneSet{}
	index.Names = map[rune]string{}

	for _, line := range getUcdLines() {
		var uchar rune
		fields := strings.Split(line, ";")
		if len(fields) >= 2 {
			code64, _ := strconv.ParseInt(fields[0], 16, 0)
			uchar = rune(code64)
			index.Names[uchar] = fields[1]
			words := strings.Split(strings.ToUpper(fields[1]), " ")
			for _, word := range words {
				existing, ok := index.Characters[word]
				if !ok {
					existing = RuneSet{}
				}
				existing.Put(uchar)
				index.Characters[word] = existing
			}
		}

	}
	indexFile, err := os.Create(indexPath)
	if err != nil {
		log.Printf("WARNING: Unable to save index file.")
	} else {
		defer indexFile.Close()
		encoder := gob.NewEncoder(indexFile)
		encoder.Encode(index)
	}
	return index
}

func getIndex() RuneIndex {
	indexDir, _ := os.Getwd()
	indexPath := path.Join(indexDir, indexFileName)
	if _, err := os.Stat(indexPath); os.IsNotExist(err) {
		return buildIndex(indexPath)
	}
	// load existing index
	indexFile, err := os.Open(indexPath)
	if err != nil {
		log.Fatal("getIndex/os.Open:", err)
	}
	defer indexFile.Close()

	var index RuneIndex

	decoder := gob.NewDecoder(indexFile)
	err = decoder.Decode(&index)
	if err != nil {
		log.Fatal("getIndex/Decode:", err)
	}
	return index
}

func findRunes(query []string, index RuneIndex) RuneSlice {
	commonRunes := RuneSet{}
	for i, word := range query {
		word = strings.ToUpper(word)
		found := index.Characters[word]
		if i == 0 {
			commonRunes = found
		} else {
			commonRunes = commonRunes.Intersection(found)
		}
		if len(commonRunes) == 0 {
			break
		}
	}
	result := commonRunes.ToRuneSlice()
	sort.Sort(result)
	return result
}

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage:  runefinder <word>\texample: runefinder cat")
		os.Exit(1)
	}
	words := os.Args[1:]

	index := getIndex()

	count := 0
	format := "U+%04X  %c \t%s\n"
	for _, uchar := range findRunes(words, index) {
		if uchar > 0xFFFF {
			format = "U+%5X %c \t%s\n"
		}
		fmt.Printf(format, uchar, uchar, index.Names[uchar])
		count++
	}
	fmt.Printf("%d characters found\n", count)
}
<commit_msg>separare saveIndex into new function<commit_after>package main

import (
	"encoding/gob"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"sort"
	"strconv"
	"strings"
	"time"
)

const (
	ucdUrl        = "http://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt"
	indexFileName = "runefinder-index.gob"
)

type RuneSlice []rune

func (rs RuneSlice) Len() int           { return len(rs) }
func (rs RuneSlice) Less(i, j int) bool { return rs[i] < rs[j] }
func (rs RuneSlice) Swap(i, j int)      { rs[i], rs[j] = rs[j], rs[i] }

type RuneSet map[rune]struct{}

func (rs RuneSet) Put(key rune) {
	rs[key] = struct{}{} // zero-byte struct
}

func (rs RuneSet) Contains(key rune) bool {
	_, found := rs[key]
	return found
}

func (rs RuneSet) Intersection(other RuneSet) RuneSet {
	result := RuneSet{}
	for k := range rs {
		if other.Contains(k) {
			result.Put(k)
		}
	}
	return result
}

func (rs RuneSet) ToRuneSlice() RuneSlice {
	result := RuneSlice{}
	for uchar := range rs {
		result = append(result, uchar)
	}
	return result
}

func (rs RuneSet) String() string {
	sl := rs.ToRuneSlice()
	sort.Sort(sl)
	str := "❮"
	for i, uchar := range sl {
		if i > 0 {
			str += " "
		}
		str += fmt.Sprintf("U+%04X", uchar)
	}
	return str + "❯"
}

type RuneIndex struct {
	Characters map[string]RuneSet
	Names      map[rune]string
}

func progressDisplay(running <-chan bool) {
	for {
		select {
		case <-running:
			fmt.Println()
		case <-time.After(200 * time.Millisecond):
			fmt.Print(".")
		}
	}
}

func getUcdLines() []string {
	fmt.Printf("Index not found. Retrieving data from:\n%s\n", ucdUrl)
	running := make(chan bool)
	go progressDisplay(running)
	defer func() {
		running <- false
	}()
	response, err := http.Get(ucdUrl)
	if err != nil {
		log.Fatal("getUcdFile/http.Get:", err)
	}
	content, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Fatal("buildIndex/ioutil.ReadAll:", err)
	}
	defer response.Body.Close()
	return strings.Split(string(content), "\n")
}

func buildIndex() RuneIndex {
	var index RuneIndex
	index.Characters = map[string]RuneSet{}
	index.Names = map[rune]string{}

	for _, line := range getUcdLines() {
		var uchar rune
		fields := strings.Split(line, ";")
		if len(fields) >= 2 {
			code64, _ := strconv.ParseInt(fields[0], 16, 0)
			uchar = rune(code64)
			index.Names[uchar] = fields[1]
			words := strings.Split(strings.ToUpper(fields[1]), " ")
			for _, word := range words {
				existing, ok := index.Characters[word]
				if !ok {
					existing = RuneSet{}
				}
				existing.Put(uchar)
				index.Characters[word] = existing
			}
		}

	}
	return index
}

func saveIndex(index RuneIndex, indexPath string) {
	indexFile, err := os.Create(indexPath)
	if err != nil {
		log.Printf("WARNING: Unable to save index file.")
	} else {
		defer indexFile.Close()
		encoder := gob.NewEncoder(indexFile)
		encoder.Encode(index)
	}
}

func getIndex() RuneIndex {
	var index RuneIndex
	indexDir, _ := os.Getwd()
	indexPath := path.Join(indexDir, indexFileName)
	if _, err := os.Stat(indexPath); os.IsNotExist(err) {
		index = buildIndex()
		// XXX do this async, but main() must wait for it to finish
		saveIndex(index, indexPath)
		return index
	}
	// load existing index
	indexFile, err := os.Open(indexPath)
	if err != nil {
		log.Fatal("getIndex/os.Open:", err)
	}
	defer indexFile.Close()

	decoder := gob.NewDecoder(indexFile)
	err = decoder.Decode(&index)
	if err != nil {
		log.Fatal("getIndex/Decode:", err)
	}
	return index
}

func findRunes(query []string, index RuneIndex) RuneSlice {
	commonRunes := RuneSet{}
	for i, word := range query {
		word = strings.ToUpper(word)
		found := index.Characters[word]
		if i == 0 {
			commonRunes = found
		} else {
			commonRunes = commonRunes.Intersection(found)
		}
		if len(commonRunes) == 0 {
			break
		}
	}
	result := commonRunes.ToRuneSlice()
	sort.Sort(result)
	return result
}

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage:  runefinder <word>\texample: runefinder cat")
		os.Exit(1)
	}
	words := os.Args[1:]

	index := getIndex()

	count := 0
	format := "U+%04X  %c \t%s\n"
	for _, uchar := range findRunes(words, index) {
		if uchar > 0xFFFF {
			format = "U+%5X %c \t%s\n"
		}
		fmt.Printf(format, uchar, uchar, index.Names[uchar])
		count++
	}
	fmt.Printf("%d characters found\n", count)
}
<|endoftext|>


<commit_before>package v3

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"path"
	"strings"
	"time"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	"github.com/cloudfoundry-incubator/cf-test-helpers/runner"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/assets"
	. "github.com/cloudfoundry/cf-acceptance-tests/helpers/v3_helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
	archive_helpers "github.com/pivotal-golang/archiver/extractor/test_helper"
)

var _ = Describe("buildpack", func() {
	var (
		appName       string
		appGuid       string
		buildpackName string
		buildpackGuid string
		packageGuid   string
		spaceGuid     string
		token         string
	)

	BeforeEach(func() {
		appName = generator.PrefixedRandomName("CATS-APP-")
		spaceGuid = GetSpaceGuidFromName(context.RegularUserContext().Space)
		appGuid = CreateApp(appName, spaceGuid, "{}")
		packageGuid = CreatePackage(appGuid)
		token = GetAuthToken()
		uploadUrl := fmt.Sprintf("%s/v3/packages/%s/upload", config.ApiEndpoint, packageGuid)
		UploadPackage(uploadUrl, assets.NewAssets().DoraZip, token)
		WaitForPackageToBeReady(packageGuid)

		buildpackName = generator.PrefixedRandomName("CATS-BP-")
		buildpackZip := createBuildpack()

		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("create-buildpack", buildpackName, buildpackZip, "999").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		})

		session := cf.Cf("curl", fmt.Sprintf("/v2/buildpacks?q=name:%s", buildpackName))
		bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
		var buildpack struct {
			Resources []struct {
				Metadata struct {
					Guid string `json:"guid"`
				} `json:"metadata"`
			} `json:"resources"`
		}
		json.Unmarshal(bytes, &buildpack)
		buildpackGuid = buildpack.Resources[0].Metadata.Guid
	})

	AfterEach(func() {
		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("delete-buildpack", buildpackName, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		})
	})

	XIt("Stages with a user specified admin buildpack", func() {
		dropletGuid := StagePackage(packageGuid, fmt.Sprintf(`{"buildpack":"%s"}`, buildpackName))

		logUrl := fmt.Sprintf("loggregator.%s/recent?app=%s", config.AppsDomain, dropletGuid)
		Eventually(func() *Session {
			session := runner.Curl(logUrl, "-H", fmt.Sprintf("Authorization: %s", token))
			Expect(session.Wait(DEFAULT_TIMEOUT)).To(Exit(0))
			return session
		}, 1*time.Minute, 10*time.Second).Should(Say("STAGED WITH CUSTOM BUILDPACK"))
	})

	XIt("Stages with a user specified github buildpack", func() {
		dropletGuid := StagePackage(packageGuid, `{"buildpack":"http://github.com/cloudfoundry/go-buildpack"}`)

		logUrl := fmt.Sprintf("loggregator.%s/recent?app=%s", config.AppsDomain, dropletGuid)
		Eventually(func() *Session {
			session := runner.Curl(logUrl, "-H", fmt.Sprintf("Authorization: %s", token))
			Expect(session.Wait(DEFAULT_TIMEOUT)).To(Exit(0))
			fmt.Println(string(session.Out.Contents()))
			return session
		}, 3*time.Minute, 10*time.Second).Should(Say("Cloning into"))
	})

	It("uses buildpack cache for staging", func() {
		firstDropletGuid := StagePackage(packageGuid, fmt.Sprintf(`{"buildpack":"%s"}`, buildpackName))
		dropletPath := fmt.Sprintf("/v3/droplets/%s", firstDropletGuid)
		Eventually(func() *Session {
			result := cf.Cf("curl", dropletPath).Wait(DEFAULT_TIMEOUT)
			if strings.Contains(string(result.Out.Contents()), "FAILED") {
				Fail("staging failed")
			}
			return result
		}, CF_PUSH_TIMEOUT).Should(Say("custom buildpack contents - cache not found"))

		// Wait for buildpack cache to be uploaded to blobstore.
		time.Sleep(DEFAULT_TIMEOUT)

		secondDropletGuid := StagePackage(packageGuid, fmt.Sprintf(`{"buildpack":"%s"}`, buildpackName))
		dropletPath = fmt.Sprintf("/v3/droplets/%s", secondDropletGuid)
		Eventually(func() *Session {
			result := cf.Cf("curl", dropletPath).Wait(DEFAULT_TIMEOUT)
			if strings.Contains(string(result.Out.Contents()), "FAILED") {
				Fail("staging failed")
			}
			if strings.Contains(string(result.Out.Contents()), "cache not found") {
				Fail("cache was not found")
			}
			return result
		}, CF_PUSH_TIMEOUT).Should(Say("custom buildpack contents - here's a cache"))

		Expect(secondDropletGuid).NotTo(Equal(firstDropletGuid))
	})
})

func createBuildpack() string {
	tmpPath, err := ioutil.TempDir("", "buildpack-cats")
	Expect(err).ToNot(HaveOccurred())

	buildpackArchivePath := path.Join(tmpPath, "buildpack.zip")

	archive_helpers.CreateZipArchive(buildpackArchivePath, []archive_helpers.ArchiveFile{
		{
			Name: "bin/compile",
			Body: `#!/usr/bin/env bash

echo "STAGED WITH CUSTOM BUILDPACK"

mkdir -p $1 $2
if [ -f "$2/cached-file" ]; then
cp $2/cached-file $1/content
else
echo "cache not found" > $1/content
fi

content=$(cat $1/content)
echo "web: while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "custom buildpack contents - $content"; } | nc -l \$PORT; done" > $1/Procfile

echo "here's a cache" > $2/cached-file
`,
		},
		{
			Name: "bin/detect",
			Body: `#!/bin/bash
echo no
exit 1
`,
		},
		{
			Name: "bin/release",
			Body: `#!/usr/bin/env bash

cat <<EOF
---
config_vars:
  PATH: bin:/usr/local/bin:/usr/bin:/bin
  FROM_BUILD_PACK: "yes"
default_process_types:
  web: while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "custom buildpack contents - $content"; } | nc -l \$PORT; done
EOF
`,
		},
	})

	return buildpackArchivePath
}
<commit_msg>Changed buildpacks_test.go to use lifecycle request<commit_after>package v3

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"path"
	"strings"
	"time"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	"github.com/cloudfoundry-incubator/cf-test-helpers/runner"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/assets"
	. "github.com/cloudfoundry/cf-acceptance-tests/helpers/v3_helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
	archive_helpers "github.com/pivotal-golang/archiver/extractor/test_helper"
)

var _ = Describe("buildpack", func() {
	var (
		appName       string
		appGuid       string
		buildpackName string
		buildpackGuid string
		packageGuid   string
		spaceGuid     string
		token         string
	)

	BeforeEach(func() {
		appName = generator.PrefixedRandomName("CATS-APP-")
		spaceGuid = GetSpaceGuidFromName(context.RegularUserContext().Space)
		appGuid = CreateApp(appName, spaceGuid, "{}")
		packageGuid = CreatePackage(appGuid)
		token = GetAuthToken()
		uploadUrl := fmt.Sprintf("%s/v3/packages/%s/upload", config.ApiEndpoint, packageGuid)
		UploadPackage(uploadUrl, assets.NewAssets().DoraZip, token)
		WaitForPackageToBeReady(packageGuid)

		buildpackName = generator.PrefixedRandomName("CATS-BP-")
		buildpackZip := createBuildpack()

		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("create-buildpack", buildpackName, buildpackZip, "999").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		})

		session := cf.Cf("curl", fmt.Sprintf("/v2/buildpacks?q=name:%s", buildpackName))
		bytes := session.Wait(DEFAULT_TIMEOUT).Out.Contents()
		var buildpack struct {
			Resources []struct {
				Metadata struct {
					Guid string `json:"guid"`
				} `json:"metadata"`
			} `json:"resources"`
		}
		json.Unmarshal(bytes, &buildpack)
		buildpackGuid = buildpack.Resources[0].Metadata.Guid
	})

	AfterEach(func() {
		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("delete-buildpack", buildpackName, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		})
	})

	XIt("Stages with a user specified admin buildpack", func() {
		dropletGuid := StagePackage(packageGuid, fmt.Sprintf(`{"buildpack":"%s"}`, buildpackName))

		logUrl := fmt.Sprintf("loggregator.%s/recent?app=%s", config.AppsDomain, dropletGuid)
		Eventually(func() *Session {
			session := runner.Curl(logUrl, "-H", fmt.Sprintf("Authorization: %s", token))
			Expect(session.Wait(DEFAULT_TIMEOUT)).To(Exit(0))
			return session
		}, 1*time.Minute, 10*time.Second).Should(Say("STAGED WITH CUSTOM BUILDPACK"))
	})

	XIt("Stages with a user specified github buildpack", func() {
		dropletGuid := StagePackage(packageGuid, `{"buildpack":"http://github.com/cloudfoundry/go-buildpack"}`)

		logUrl := fmt.Sprintf("loggregator.%s/recent?app=%s", config.AppsDomain, dropletGuid)
		Eventually(func() *Session {
			session := runner.Curl(logUrl, "-H", fmt.Sprintf("Authorization: %s", token))
			Expect(session.Wait(DEFAULT_TIMEOUT)).To(Exit(0))
			fmt.Println(string(session.Out.Contents()))
			return session
		}, 3*time.Minute, 10*time.Second).Should(Say("Cloning into"))
	})

	It("uses buildpack cache for staging", func() {
		firstDropletGuid := StagePackage(packageGuid, fmt.Sprintf(`{"lifecycle":{ "type" : "buildpack", "data" : { "buildpack": "%s" } }}`, buildpackName))
		dropletPath := fmt.Sprintf("/v3/droplets/%s", firstDropletGuid)
		Eventually(func() *Session {
			result := cf.Cf("curl", dropletPath).Wait(DEFAULT_TIMEOUT)
			if strings.Contains(string(result.Out.Contents()), "FAILED") {
				Fail("staging failed")
			}
			return result
		}, CF_PUSH_TIMEOUT).Should(Say("custom buildpack contents - cache not found"))

		// Wait for buildpack cache to be uploaded to blobstore.
		time.Sleep(DEFAULT_TIMEOUT)

		secondDropletGuid := StagePackage(packageGuid, fmt.Sprintf(`{"lifecycle":{ "type" : "buildpack", "data" : { "buildpack": "%s" } }}`, buildpackName))
		dropletPath = fmt.Sprintf("/v3/droplets/%s", secondDropletGuid)
		Eventually(func() *Session {
			result := cf.Cf("curl", dropletPath).Wait(DEFAULT_TIMEOUT)
			if strings.Contains(string(result.Out.Contents()), "FAILED") {
				Fail("staging failed")
			}
			if strings.Contains(string(result.Out.Contents()), "cache not found") {
				Fail("cache was not found")
			}
			return result
		}, CF_PUSH_TIMEOUT).Should(Say("custom buildpack contents - here's a cache"))

		Expect(secondDropletGuid).NotTo(Equal(firstDropletGuid))
	})
})

func createBuildpack() string {
	tmpPath, err := ioutil.TempDir("", "buildpack-cats")
	Expect(err).ToNot(HaveOccurred())

	buildpackArchivePath := path.Join(tmpPath, "buildpack.zip")

	archive_helpers.CreateZipArchive(buildpackArchivePath, []archive_helpers.ArchiveFile{
		{
			Name: "bin/compile",
			Body: `#!/usr/bin/env bash

echo "STAGED WITH CUSTOM BUILDPACK"

mkdir -p $1 $2
if [ -f "$2/cached-file" ]; then
cp $2/cached-file $1/content
else
echo "cache not found" > $1/content
fi

content=$(cat $1/content)
echo "web: while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "custom buildpack contents - $content"; } | nc -l \$PORT; done" > $1/Procfile

echo "here's a cache" > $2/cached-file
`,
		},
		{
			Name: "bin/detect",
			Body: `#!/bin/bash
echo no
exit 1
`,
		},
		{
			Name: "bin/release",
			Body: `#!/usr/bin/env bash

cat <<EOF
---
config_vars:
  PATH: bin:/usr/local/bin:/usr/bin:/bin
  FROM_BUILD_PACK: "yes"
default_process_types:
  web: while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "custom buildpack contents - $content"; } | nc -l \$PORT; done
EOF
`,
		},
	})

	return buildpackArchivePath
}
<|endoftext|>


<commit_before>package middleware

import (
	"github.com/gin-gonic/gin"
	"time"

	u "github.com/techjanitor/pram-get/utils"
)

// requesttype holds the data we want to capture
type RequestType struct {
	Ib        string
	Ip        string
	User      uint
	Path      string
	Status    int
	Latency   time.Duration
	Useragent string
	Referer   string
	Country   string
}

// Analytics will log requests in the database
func Analytics() gin.HandlerFunc {
	return func(c *gin.Context) {
		req := c.Request
		// get userdata from session middleware
		userdata := c.MustGet("userdata").(u.User)
		// Start timer
		start := time.Now()
		// get request path
		path := req.URL.Path

		// Process request
		c.Next()

		// get the ib
		ib := c.Param("ib")

		// Stop timer
		end := time.Now()
		// get request latency
		latency := end.Sub(start)

		// set our data
		request := RequestType{
			Ib:        ib,
			Ip:        c.ClientIP(),
			User:      userdata.Id,
			Path:      path,
			Status:    c.Writer.Status(),
			Latency:   latency,
			Useragent: req.UserAgent(),
			Referer:   req.Referer(),
			Country:   req.Header.Get("CF-IPCountry"),
		}

		// Get Database handle
		db, err := u.GetDb()
		if err != nil {
			c.Error(err)
			c.Abort()
			return
		}

		// prepare query for analytics table
		ps1, err := db.Prepare("INSERT INTO analytics (ib_id, user_id, request_ip, request_path, request_status, request_referer, request_latency, request_ua, request_country, request_time) VALUES (?,?,?,?,?,?,?,?,?,NOW())")
		if err != nil {
			c.Error(err)
			c.Abort()
			return
		}

		// input data
		_, err = ps1.Exec(request.Ib, request.User, request.Ip, request.Path, request.Status, request.Referer, request.Latency, request.Useragent, request.Country)
		if err != nil {
			c.Error(err)
			c.Abort()
			return
		}

	}
}
<commit_msg>add analytics middleware<commit_after>package middleware

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"time"

	u "github.com/techjanitor/pram-get/utils"
)

// requesttype holds the data we want to capture
type RequestType struct {
	Ib        string
	Ip        string
	User      uint
	Path      string
	Status    int
	Latency   time.Duration
	Useragent string
	Referer   string
	Country   string
}

// Analytics will log requests in the database
func Analytics() gin.HandlerFunc {
	return func(c *gin.Context) {
		req := c.Request
		// get userdata from session middleware
		userdata := c.MustGet("userdata").(u.User)
		// Start timer
		start := time.Now()
		// get request path
		path := req.URL.Path

		// Process request
		c.Next()

		// get the ib
		ib := c.Param("ib")

		// Stop timer
		end := time.Now()
		// get request latency
		latency := fmt.Sprintf("%13v", end.Sub(start))

		// set our data
		request := RequestType{
			Ib:        ib,
			Ip:        c.ClientIP(),
			User:      userdata.Id,
			Path:      path,
			Status:    c.Writer.Status(),
			Latency:   latency,
			Useragent: req.UserAgent(),
			Referer:   req.Referer(),
			Country:   req.Header.Get("CF-IPCountry"),
		}

		// Get Database handle
		db, err := u.GetDb()
		if err != nil {
			c.Error(err)
			c.Abort()
			return
		}

		// prepare query for analytics table
		ps1, err := db.Prepare("INSERT INTO analytics (ib_id, user_id, request_ip, request_path, request_status, request_referer, request_latency, request_ua, request_country, request_time) VALUES (?,?,?,?,?,?,?,?,?,NOW())")
		if err != nil {
			c.Error(err)
			c.Abort()
			return
		}

		// input data
		_, err = ps1.Exec(request.Ib, request.User, request.Ip, request.Path, request.Status, request.Referer, request.Latency, request.Useragent, request.Country)
		if err != nil {
			c.Error(err)
			c.Abort()
			return
		}

	}
}
<|endoftext|>


<commit_before><commit_msg>fix start World method: flag started error<commit_after><|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes 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 main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"testing"

	"github.com/ghodss/yaml"
	prow_config "k8s.io/test-infra/prow/config"
	config_pb "k8s.io/test-infra/testgrid/config"
	"path/filepath"
)

type SQConfig struct {
	Data map[string]string `yaml:"data,omitempty"`
}

var (
	companies = []string{
		"canonical",
		"cri-o",
		"istio",
		"google",
		"kopeio",
		"tectonic",
		"redhat",
	}
	orgs = []string{
		"presubmits",
		"sig",
		"wg",
	}
	prefixes = [][]string{orgs, companies}
)

// Shared testgrid config, loaded at TestMain.
var cfg *config_pb.Configuration

func TestMain(m *testing.M) {
	//make sure we can parse config.yaml
	yamlData, err := ioutil.ReadFile("../../config.yaml")
	if err != nil {
		fmt.Printf("IO Error : Cannot Open File config.yaml")
		os.Exit(1)
	}

	c := Config{}
	if err := c.Update(yamlData); err != nil {
		fmt.Printf("Yaml2Proto - Conversion Error %v", err)
		os.Exit(1)
	}

	cfg, err = c.Raw()
	if err != nil {
		fmt.Printf("Error validating config: %v", err)
		os.Exit(1)
	}

	os.Exit(m.Run())
}

func TestConfig(t *testing.T) {
	// testgroup - occurrence map, validate testgroups
	testgroupMap := make(map[string]int32)

	for testgroupidx, testgroup := range cfg.TestGroups {
		// All testgroup must have a name and a query
		if testgroup.Name == "" || testgroup.GcsPrefix == "" {
			t.Errorf("Testgroup %v: - Must have a name and query", testgroupidx)
		}

		// All testgroup must not have duplicated names
		if testgroupMap[testgroup.Name] > 0 {
			t.Errorf("Duplicated Testgroup: %v", testgroup.Name)
		} else {
			testgroupMap[testgroup.Name] = 1
		}

		if !testgroup.IsExternal {
			t.Errorf("Testgroup %v: IsExternal should always be true!", testgroup.Name)
		}
		if !testgroup.UseKubernetesClient {
			t.Errorf("Testgroup %v: UseKubernetesClient should always be true!", testgroup.Name)
		}

		if strings.HasPrefix(testgroup.GcsPrefix, "kubernetes-jenkins/logs/") {
			// The expectation is that testgroup.Name is the name of a Prow job and the GCSPrefix
			// follows the convention kubernetes-jenkins/logs/.../jobName
			// The final part of the prefix should be the job name.
			expected := filepath.Join(filepath.Dir(testgroup.GcsPrefix), testgroup.Name)
			if expected != testgroup.GcsPrefix {
				t.Errorf("Kubernetes Testgroup %v GcsPrefix; Got %v; Want %v", testgroup.Name, testgroup.GcsPrefix, expected)
			}
		}

		if testgroup.TestNameConfig != nil {
			if testgroup.TestNameConfig.NameFormat == "" {
				t.Errorf("Testgroup %v: NameFormat must not be empty!", testgroup.Name)
			}

			if len(testgroup.TestNameConfig.NameElements) != strings.Count(testgroup.TestNameConfig.NameFormat, "%") {
				t.Errorf("Testgroup %v: TestNameConfig must have number NameElement equal to format count in NameFormat!", testgroup.Name)
			}
		}

		// All PR testgroup has num_columns_recent equals 20
		if strings.HasPrefix(testgroup.GcsPrefix, "kubernetes-jenkins/pr-logs/directory/") {
			if testgroup.NumColumnsRecent < 20 {
				t.Errorf("Testgroup %v: num_columns_recent: must be greater than 20 for presubmit jobs!", testgroup.Name)
			}
		}
	}

	// dashboard name set
	dashboardmap := make(map[string]bool)

	for dashboardidx, dashboard := range cfg.Dashboards {
		// All dashboard must have a name
		if dashboard.Name == "" {
			t.Errorf("Dashboard %v: - Must have a name", dashboardidx)
		}

		found := false
		for _, kind := range prefixes {
			for _, prefix := range kind {
				if strings.HasPrefix(dashboard.Name, prefix+"-") || dashboard.Name == prefix {
					found = true
					break
				}
			}
			if found {
				break
			}
		}
		if !found {
			t.Errorf("Dashboard %v: must prefix with one of: %v", dashboard.Name, prefixes)
		}

		// All dashboard must not have duplicated names
		if dashboardmap[dashboard.Name] {
			t.Errorf("Duplicated dashboard: %v", dashboard.Name)
		} else {
			dashboardmap[dashboard.Name] = true
		}

		// All dashboard must have at least one tab
		if len(dashboard.DashboardTab) == 0 {
			t.Errorf("Dashboard %v: - Must have more than one dashboardtab", dashboard.Name)
		}

		// dashboardtab name set, to check duplicated tabs within each dashboard
		dashboardtabmap := make(map[string]bool)

		// All notifications in dashboard must have a summary
		if len(dashboard.Notifications) != 0 {
			for notificationindex, notification := range dashboard.Notifications {
				if notification.Summary == "" {
					t.Errorf("Notification %v in dashboard %v: - Must have a summary", notificationindex, dashboard.Name)
				}
			}
		}

		for tabindex, dashboardtab := range dashboard.DashboardTab {

			// All dashboardtab must have a name and a testgroup
			if dashboardtab.Name == "" || dashboardtab.TestGroupName == "" {
				t.Errorf("Dashboard %v, tab %v: - Must have a name and a testgroup name", dashboard.Name, tabindex)
			}

			// All dashboardtab within a dashboard must not have duplicated names
			if dashboardtabmap[dashboardtab.Name] {
				t.Errorf("Duplicated dashboardtab: %v", dashboardtab.Name)
			} else {
				dashboardtabmap[dashboardtab.Name] = true
			}

			// All testgroup in dashboard must be defined in testgroups
			if testgroupMap[dashboardtab.TestGroupName] == 0 {
				t.Errorf("Dashboard %v, tab %v: - Testgroup %v must be defined first",
					dashboard.Name, dashboardtab.Name, dashboardtab.TestGroupName)
			} else {
				testgroupMap[dashboardtab.TestGroupName] += 1
			}

			if dashboardtab.AlertOptions != nil && (dashboardtab.AlertOptions.AlertStaleResultsHours != 0 || dashboardtab.AlertOptions.NumFailuresToAlert != 0) {
				for _, testgroup := range cfg.TestGroups {
					// Disallow alert options in tab but not group.
					// Disallow different alert options in tab vs. group.
					if testgroup.Name == dashboardtab.TestGroupName {
						if testgroup.AlertStaleResultsHours == 0 {
							t.Errorf("Cannot define alert_stale_results_hours in DashboardTab %v and not TestGroup %v.", dashboardtab.Name, dashboardtab.TestGroupName)
						}
						if testgroup.NumFailuresToAlert == 0 {
							t.Errorf("Cannot define num_failures_to_alert in DashboardTab %v and not TestGroup %v.", dashboardtab.Name, dashboardtab.TestGroupName)
						}
						if testgroup.AlertStaleResultsHours != dashboardtab.AlertOptions.AlertStaleResultsHours {
							t.Errorf("alert_stale_results_hours for DashboardTab %v must match TestGroup %v.", dashboardtab.Name, dashboardtab.TestGroupName)
						}
						if testgroup.NumFailuresToAlert != dashboardtab.AlertOptions.NumFailuresToAlert {
							t.Errorf("num_failures_to_alert for DashboardTab %v must match TestGroup %v.", dashboardtab.Name, dashboardtab.TestGroupName)
						}
					}
				}
			}
		}
	}

	// No dup of dashboard groups, and no dup dashboard in a dashboard group
	groups := make(map[string]bool)
	tabs := make(map[string]string)

	for idx, dashboardGroup := range cfg.DashboardGroups {
		// All dashboard must have a name
		if dashboardGroup.Name == "" {
			t.Errorf("DashboardGroup %v: - DashboardGroup must have a name", idx)
		}

		found := false
		for _, kind := range prefixes {
			for _, prefix := range kind {
				if strings.HasPrefix(dashboardGroup.Name, prefix+"-") || prefix == dashboardGroup.Name {
					found = true
					break
				}
			}
			if found {
				break
			}
		}
		if !found {
			t.Errorf("Dashboard group %v: must prefix with one of: %v", dashboardGroup.Name, prefixes)
		}

		// All dashboardgroup must not have duplicated names
		if _, ok := groups[dashboardGroup.Name]; ok {
			t.Errorf("Duplicated dashboard: %v", dashboardGroup.Name)
		} else {
			groups[dashboardGroup.Name] = true
		}

		if _, ok := dashboardmap[dashboardGroup.Name]; ok {
			t.Errorf("%v is both a dashboard and dashboard group name.", dashboardGroup.Name)
		}

		for _, dashboard := range dashboardGroup.DashboardNames {
			// All dashboard must not have duplicated names
			if exist, ok := tabs[dashboard]; ok {
				t.Errorf("Duplicated dashboard %v in dashboard group %v and %v", dashboard, exist, dashboardGroup.Name)
			} else {
				tabs[dashboard] = dashboardGroup.Name
			}

			if _, ok := dashboardmap[dashboard]; !ok {
				t.Errorf("Dashboard %v needs to be defined before adding to a dashboard group!", dashboard)
			}

			if !strings.HasPrefix(dashboard, dashboardGroup.Name+"-") {
				t.Errorf("Dashboard %v in group %v must have the group name as a prefix", dashboard, dashboardGroup.Name)
			}
		}
	}

	// All Testgroup should be mapped to one or more tabs
	for testgroupname, occurrence := range testgroupMap {
		if occurrence == 1 {
			t.Errorf("Testgroup %v - defined but not used in any dashboards", testgroupname)
		}
	}

	// make sure items in sq-blocking dashboard matches sq configmap
	sqJobPool := []string{}
	for _, d := range cfg.Dashboards {
		if d.Name != "sq-blocking" {
			continue
		}

		for _, tab := range d.DashboardTab {
			for _, t := range cfg.TestGroups {
				if t.Name == tab.TestGroupName {
					job := strings.TrimPrefix(t.GcsPrefix, "kubernetes-jenkins/logs/")
					sqJobPool = append(sqJobPool, job)
					break
				}
			}
		}
	}

	sqConfigPath := "../../../mungegithub/submit-queue/deployment/kubernetes/configmap.yaml"
	configData, err := ioutil.ReadFile(sqConfigPath)
	if err != nil {
		t.Errorf("Read Buffer Error for SQ Data : %v", err)
	}

	sqData := &SQConfig{}
	err = yaml.Unmarshal([]byte(configData), &sqData)
	if err != nil {
		t.Errorf("Unmarshal Error for SQ Data : %v", err)
	}

	for _, testgridJob := range sqJobPool {
		t.Errorf("Err : testgrid job %v not found in SQ config", testgridJob)
	}

	sqNonBlockingJobs := strings.Split(sqData.Data["nonblocking-jobs"], ",")
	for _, sqJob := range sqNonBlockingJobs {
		if sqJob == "" { // ignore empty list of jobs
			continue
		}
		found := false
		for _, testgroup := range cfg.TestGroups {
			if testgroup.Name == sqJob {
				found = true
				break
			}
		}

		if !found {
			t.Errorf("Err : %v not found in testgrid config", sqJob)
		}
	}
}

func TestJobsTestgridEntryMatch(t *testing.T) {
	prowPath := "../../../prow/config.yaml"

	jobs := make(map[string]bool)

	prowConfig, err := prow_config.Load(prowPath)
	if err != nil {
		t.Fatalf("Could not load prow configs: %v\n", err)
	}

	// Also check k/k presubmit, prow postsubmit and periodic jobs
	for _, job := range prowConfig.AllPresubmits([]string{
		"google/cadvisor",
		"kubeflow/kubeflow",
		"kubernetes/kubernetes",
		"kubernetes/test-infra",
		"kubernetes/cluster-registry",
		"kubernetes/federation",
		"kubernetes/kops",
		"kubernetes/heapster",
		"kubernetes/charts",
		"tensorflow/k8s",
		"tensorflow/minigo",
	}) {
		jobs[job.Name] = false
	}

	for _, job := range prowConfig.AllPostsubmits([]string{}) {
		jobs[job.Name] = false
	}

	for _, job := range prowConfig.AllPeriodics() {
		jobs[job.Name] = false
	}

	// For now anything outsite k8s-jenkins/(pr-)logs are considered to be fine
	testgroups := make(map[string]bool)
	for _, testgroup := range cfg.TestGroups {
		if strings.Contains(testgroup.GcsPrefix, "kubernetes-jenkins/logs/") {
			// The convention is that the job name is the final part of the GcsPrefix
			job := filepath.Base(testgroup.GcsPrefix)
			testgroups[job] = false
		}

		if strings.Contains(testgroup.GcsPrefix, "kubernetes-jenkins/pr-logs/directory/") {
			job := strings.TrimPrefix(testgroup.GcsPrefix, "kubernetes-jenkins/pr-logs/directory/")
			testgroups[job] = false
		}
	}

	// Cross check
	// -- Each job need to have a match testgrid group
	for job := range jobs {
		if _, ok := testgroups[job]; ok {
			testgroups[job] = true
			jobs[job] = true
		}
	}

	// Conclusion
	badjobs := []string{}
	for job, valid := range jobs {
		if !valid {
			badjobs = append(badjobs, job)
			fmt.Printf("Job %v does not have a matching testgrid testgroup\n", job)
		}
	}

	badconfigs := []string{}
	for testgroup, valid := range testgroups {
		if !valid {
			badconfigs = append(badconfigs, testgroup)
			fmt.Printf("Testgrid group %v does not have a matching jenkins or prow job\n", testgroup)
		}
	}

	if len(badconfigs) > 0 {
		fmt.Printf("Total bad config(s) - %v\n", len(badconfigs))
	}

	if len(badjobs) > 0 {
		fmt.Printf("Total bad job(s) - %v\n", len(badjobs))
	}

	if len(badconfigs) > 0 || len(badjobs) > 0 {
		t.Fatal("Failed with invalid config or job entries")
	}
}
<commit_msg>Clarifying no name/query error in config test<commit_after>/*
Copyright 2016 The Kubernetes 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 main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"testing"

	"github.com/ghodss/yaml"
	prow_config "k8s.io/test-infra/prow/config"
	config_pb "k8s.io/test-infra/testgrid/config"
	"path/filepath"
)

type SQConfig struct {
	Data map[string]string `yaml:"data,omitempty"`
}

var (
	companies = []string{
		"canonical",
		"cri-o",
		"istio",
		"google",
		"kopeio",
		"tectonic",
		"redhat",
	}
	orgs = []string{
		"presubmits",
		"sig",
		"wg",
	}
	prefixes = [][]string{orgs, companies}
)

// Shared testgrid config, loaded at TestMain.
var cfg *config_pb.Configuration

func TestMain(m *testing.M) {
	//make sure we can parse config.yaml
	yamlData, err := ioutil.ReadFile("../../config.yaml")
	if err != nil {
		fmt.Printf("IO Error : Cannot Open File config.yaml")
		os.Exit(1)
	}

	c := Config{}
	if err := c.Update(yamlData); err != nil {
		fmt.Printf("Yaml2Proto - Conversion Error %v", err)
		os.Exit(1)
	}

	cfg, err = c.Raw()
	if err != nil {
		fmt.Printf("Error validating config: %v", err)
		os.Exit(1)
	}

	os.Exit(m.Run())
}

func TestConfig(t *testing.T) {
	// testgroup - occurrence map, validate testgroups
	testgroupMap := make(map[string]int32)

	for testgroupidx, testgroup := range cfg.TestGroups {
		// All testgroup must have a name and a query
		if testgroup.Name == "" || testgroup.GcsPrefix == "" {
			t.Errorf("Testgroup #%v (Name: '%v', Query: '%v'): - Must have a name and query",
				testgroupidx, testgroup.Name, testgroup.GcsPrefix)
		}

		// All testgroup must not have duplicated names
		if testgroupMap[testgroup.Name] > 0 {
			t.Errorf("Duplicated Testgroup: %v", testgroup.Name)
		} else {
			testgroupMap[testgroup.Name] = 1
		}

		if !testgroup.IsExternal {
			t.Errorf("Testgroup %v: IsExternal should always be true!", testgroup.Name)
		}
		if !testgroup.UseKubernetesClient {
			t.Errorf("Testgroup %v: UseKubernetesClient should always be true!", testgroup.Name)
		}

		if strings.HasPrefix(testgroup.GcsPrefix, "kubernetes-jenkins/logs/") {
			// The expectation is that testgroup.Name is the name of a Prow job and the GCSPrefix
			// follows the convention kubernetes-jenkins/logs/.../jobName
			// The final part of the prefix should be the job name.
			expected := filepath.Join(filepath.Dir(testgroup.GcsPrefix), testgroup.Name)
			if expected != testgroup.GcsPrefix {
				t.Errorf("Kubernetes Testgroup %v GcsPrefix; Got %v; Want %v", testgroup.Name, testgroup.GcsPrefix, expected)
			}
		}

		if testgroup.TestNameConfig != nil {
			if testgroup.TestNameConfig.NameFormat == "" {
				t.Errorf("Testgroup %v: NameFormat must not be empty!", testgroup.Name)
			}

			if len(testgroup.TestNameConfig.NameElements) != strings.Count(testgroup.TestNameConfig.NameFormat, "%") {
				t.Errorf("Testgroup %v: TestNameConfig must have number NameElement equal to format count in NameFormat!", testgroup.Name)
			}
		}

		// All PR testgroup has num_columns_recent equals 20
		if strings.HasPrefix(testgroup.GcsPrefix, "kubernetes-jenkins/pr-logs/directory/") {
			if testgroup.NumColumnsRecent < 20 {
				t.Errorf("Testgroup %v: num_columns_recent: must be greater than 20 for presubmit jobs!", testgroup.Name)
			}
		}
	}

	// dashboard name set
	dashboardmap := make(map[string]bool)

	for dashboardidx, dashboard := range cfg.Dashboards {
		// All dashboard must have a name
		if dashboard.Name == "" {
			t.Errorf("Dashboard %v: - Must have a name", dashboardidx)
		}

		found := false
		for _, kind := range prefixes {
			for _, prefix := range kind {
				if strings.HasPrefix(dashboard.Name, prefix+"-") || dashboard.Name == prefix {
					found = true
					break
				}
			}
			if found {
				break
			}
		}
		if !found {
			t.Errorf("Dashboard %v: must prefix with one of: %v", dashboard.Name, prefixes)
		}

		// All dashboard must not have duplicated names
		if dashboardmap[dashboard.Name] {
			t.Errorf("Duplicated dashboard: %v", dashboard.Name)
		} else {
			dashboardmap[dashboard.Name] = true
		}

		// All dashboard must have at least one tab
		if len(dashboard.DashboardTab) == 0 {
			t.Errorf("Dashboard %v: - Must have more than one dashboardtab", dashboard.Name)
		}

		// dashboardtab name set, to check duplicated tabs within each dashboard
		dashboardtabmap := make(map[string]bool)

		// All notifications in dashboard must have a summary
		if len(dashboard.Notifications) != 0 {
			for notificationindex, notification := range dashboard.Notifications {
				if notification.Summary == "" {
					t.Errorf("Notification %v in dashboard %v: - Must have a summary", notificationindex, dashboard.Name)
				}
			}
		}

		for tabindex, dashboardtab := range dashboard.DashboardTab {

			// All dashboardtab must have a name and a testgroup
			if dashboardtab.Name == "" || dashboardtab.TestGroupName == "" {
				t.Errorf("Dashboard %v, tab %v: - Must have a name and a testgroup name", dashboard.Name, tabindex)
			}

			// All dashboardtab within a dashboard must not have duplicated names
			if dashboardtabmap[dashboardtab.Name] {
				t.Errorf("Duplicated dashboardtab: %v", dashboardtab.Name)
			} else {
				dashboardtabmap[dashboardtab.Name] = true
			}

			// All testgroup in dashboard must be defined in testgroups
			if testgroupMap[dashboardtab.TestGroupName] == 0 {
				t.Errorf("Dashboard %v, tab %v: - Testgroup %v must be defined first",
					dashboard.Name, dashboardtab.Name, dashboardtab.TestGroupName)
			} else {
				testgroupMap[dashboardtab.TestGroupName] += 1
			}

			if dashboardtab.AlertOptions != nil && (dashboardtab.AlertOptions.AlertStaleResultsHours != 0 || dashboardtab.AlertOptions.NumFailuresToAlert != 0) {
				for _, testgroup := range cfg.TestGroups {
					// Disallow alert options in tab but not group.
					// Disallow different alert options in tab vs. group.
					if testgroup.Name == dashboardtab.TestGroupName {
						if testgroup.AlertStaleResultsHours == 0 {
							t.Errorf("Cannot define alert_stale_results_hours in DashboardTab %v and not TestGroup %v.", dashboardtab.Name, dashboardtab.TestGroupName)
						}
						if testgroup.NumFailuresToAlert == 0 {
							t.Errorf("Cannot define num_failures_to_alert in DashboardTab %v and not TestGroup %v.", dashboardtab.Name, dashboardtab.TestGroupName)
						}
						if testgroup.AlertStaleResultsHours != dashboardtab.AlertOptions.AlertStaleResultsHours {
							t.Errorf("alert_stale_results_hours for DashboardTab %v must match TestGroup %v.", dashboardtab.Name, dashboardtab.TestGroupName)
						}
						if testgroup.NumFailuresToAlert != dashboardtab.AlertOptions.NumFailuresToAlert {
							t.Errorf("num_failures_to_alert for DashboardTab %v must match TestGroup %v.", dashboardtab.Name, dashboardtab.TestGroupName)
						}
					}
				}
			}
		}
	}

	// No dup of dashboard groups, and no dup dashboard in a dashboard group
	groups := make(map[string]bool)
	tabs := make(map[string]string)

	for idx, dashboardGroup := range cfg.DashboardGroups {
		// All dashboard must have a name
		if dashboardGroup.Name == "" {
			t.Errorf("DashboardGroup %v: - DashboardGroup must have a name", idx)
		}

		found := false
		for _, kind := range prefixes {
			for _, prefix := range kind {
				if strings.HasPrefix(dashboardGroup.Name, prefix+"-") || prefix == dashboardGroup.Name {
					found = true
					break
				}
			}
			if found {
				break
			}
		}
		if !found {
			t.Errorf("Dashboard group %v: must prefix with one of: %v", dashboardGroup.Name, prefixes)
		}

		// All dashboardgroup must not have duplicated names
		if _, ok := groups[dashboardGroup.Name]; ok {
			t.Errorf("Duplicated dashboard: %v", dashboardGroup.Name)
		} else {
			groups[dashboardGroup.Name] = true
		}

		if _, ok := dashboardmap[dashboardGroup.Name]; ok {
			t.Errorf("%v is both a dashboard and dashboard group name.", dashboardGroup.Name)
		}

		for _, dashboard := range dashboardGroup.DashboardNames {
			// All dashboard must not have duplicated names
			if exist, ok := tabs[dashboard]; ok {
				t.Errorf("Duplicated dashboard %v in dashboard group %v and %v", dashboard, exist, dashboardGroup.Name)
			} else {
				tabs[dashboard] = dashboardGroup.Name
			}

			if _, ok := dashboardmap[dashboard]; !ok {
				t.Errorf("Dashboard %v needs to be defined before adding to a dashboard group!", dashboard)
			}

			if !strings.HasPrefix(dashboard, dashboardGroup.Name+"-") {
				t.Errorf("Dashboard %v in group %v must have the group name as a prefix", dashboard, dashboardGroup.Name)
			}
		}
	}

	// All Testgroup should be mapped to one or more tabs
	for testgroupname, occurrence := range testgroupMap {
		if occurrence == 1 {
			t.Errorf("Testgroup %v - defined but not used in any dashboards", testgroupname)
		}
	}

	// make sure items in sq-blocking dashboard matches sq configmap
	sqJobPool := []string{}
	for _, d := range cfg.Dashboards {
		if d.Name != "sq-blocking" {
			continue
		}

		for _, tab := range d.DashboardTab {
			for _, t := range cfg.TestGroups {
				if t.Name == tab.TestGroupName {
					job := strings.TrimPrefix(t.GcsPrefix, "kubernetes-jenkins/logs/")
					sqJobPool = append(sqJobPool, job)
					break
				}
			}
		}
	}

	sqConfigPath := "../../../mungegithub/submit-queue/deployment/kubernetes/configmap.yaml"
	configData, err := ioutil.ReadFile(sqConfigPath)
	if err != nil {
		t.Errorf("Read Buffer Error for SQ Data : %v", err)
	}

	sqData := &SQConfig{}
	err = yaml.Unmarshal([]byte(configData), &sqData)
	if err != nil {
		t.Errorf("Unmarshal Error for SQ Data : %v", err)
	}

	for _, testgridJob := range sqJobPool {
		t.Errorf("Err : testgrid job %v not found in SQ config", testgridJob)
	}

	sqNonBlockingJobs := strings.Split(sqData.Data["nonblocking-jobs"], ",")
	for _, sqJob := range sqNonBlockingJobs {
		if sqJob == "" { // ignore empty list of jobs
			continue
		}
		found := false
		for _, testgroup := range cfg.TestGroups {
			if testgroup.Name == sqJob {
				found = true
				break
			}
		}

		if !found {
			t.Errorf("Err : %v not found in testgrid config", sqJob)
		}
	}
}

func TestJobsTestgridEntryMatch(t *testing.T) {
	prowPath := "../../../prow/config.yaml"

	jobs := make(map[string]bool)

	prowConfig, err := prow_config.Load(prowPath)
	if err != nil {
		t.Fatalf("Could not load prow configs: %v\n", err)
	}

	// Also check k/k presubmit, prow postsubmit and periodic jobs
	for _, job := range prowConfig.AllPresubmits([]string{
		"google/cadvisor",
		"kubeflow/kubeflow",
		"kubernetes/kubernetes",
		"kubernetes/test-infra",
		"kubernetes/cluster-registry",
		"kubernetes/federation",
		"kubernetes/kops",
		"kubernetes/heapster",
		"kubernetes/charts",
		"tensorflow/k8s",
		"tensorflow/minigo",
	}) {
		jobs[job.Name] = false
	}

	for _, job := range prowConfig.AllPostsubmits([]string{}) {
		jobs[job.Name] = false
	}

	for _, job := range prowConfig.AllPeriodics() {
		jobs[job.Name] = false
	}

	// For now anything outsite k8s-jenkins/(pr-)logs are considered to be fine
	testgroups := make(map[string]bool)
	for _, testgroup := range cfg.TestGroups {
		if strings.Contains(testgroup.GcsPrefix, "kubernetes-jenkins/logs/") {
			// The convention is that the job name is the final part of the GcsPrefix
			job := filepath.Base(testgroup.GcsPrefix)
			testgroups[job] = false
		}

		if strings.Contains(testgroup.GcsPrefix, "kubernetes-jenkins/pr-logs/directory/") {
			job := strings.TrimPrefix(testgroup.GcsPrefix, "kubernetes-jenkins/pr-logs/directory/")
			testgroups[job] = false
		}
	}

	// Cross check
	// -- Each job need to have a match testgrid group
	for job := range jobs {
		if _, ok := testgroups[job]; ok {
			testgroups[job] = true
			jobs[job] = true
		}
	}

	// Conclusion
	badjobs := []string{}
	for job, valid := range jobs {
		if !valid {
			badjobs = append(badjobs, job)
			fmt.Printf("Job %v does not have a matching testgrid testgroup\n", job)
		}
	}

	badconfigs := []string{}
	for testgroup, valid := range testgroups {
		if !valid {
			badconfigs = append(badconfigs, testgroup)
			fmt.Printf("Testgrid group %v does not have a matching jenkins or prow job\n", testgroup)
		}
	}

	if len(badconfigs) > 0 {
		fmt.Printf("Total bad config(s) - %v\n", len(badconfigs))
	}

	if len(badjobs) > 0 {
		fmt.Printf("Total bad job(s) - %v\n", len(badjobs))
	}

	if len(badconfigs) > 0 || len(badjobs) > 0 {
		t.Fatal("Failed with invalid config or job entries")
	}
}
<|endoftext|>