<commit_before>// (C) 2017 Julian Andres Klode <jak@jak-linux.org>
// Licensed under the 2-Clause BSD license, see LICENSE for more information.
package parser

import (
	"reflect"
	"sort"
	"testing"

	"github.com/julian-klode/lingolang/permission"
)

// testCases contains tests for the permission parser.
var testCases = map[string]permission.Permission{
	"123":     nil,
	"!":       nil,
	"a !":     nil,
	"a error": nil,
	"":        nil,
	"oe":      nil,
	"or":      permission.Owned | permission.Read,
	"ow":      permission.Owned | permission.Write,
	"orwR":    permission.Owned | permission.Read | permission.Write | permission.ExclRead,
	"orR":     permission.Owned | permission.Read | permission.ExclRead,
	"owW":     permission.Owned | permission.Write | permission.ExclWrite,
	"om":      permission.Owned | permission.Mutable,
	"ov":      permission.Owned | permission.Value,
	"a":       permission.Any,
	"on":      permission.Owned,
	"n":       permission.None,
	"m [":     nil,
	"m [1":    nil,
	"m []":    nil,
	"m [1]":   nil,
	"m [] a": &permission.ArraySlicePermission{
		BasePermission:    permission.Mutable,
		ElementPermission: permission.Any,
	},
	"m [1] a": &permission.ArraySlicePermission{
		BasePermission:    permission.Mutable,
		ElementPermission: permission.Any,
	},
	"m map[v]l": &permission.MapPermission{
		BasePermission:  permission.Mutable,
		KeyPermission:   permission.Value,
		ValuePermission: permission.LinearValue,
	},
	"n map":         nil,
	"n map [":       nil,
	"n map [error]": nil,
	"n map [n":      nil,
	"n map [n]":     nil,
	"m chan l": &permission.ChanPermission{
		BasePermission:    permission.Mutable,
		ElementPermission: permission.LinearValue,
	},
	"m chan":       nil,
	"m chan error": nil,
	"m * l": &permission.PointerPermission{
		BasePermission: permission.Mutable,
		Target:         permission.LinearValue,
	},
	"error":     nil,
	"m * error": nil,
	"m func (v) a": &permission.FuncPermission{
		BasePermission: permission.Mutable,
		Receivers:      nil,
		Params:         []permission.Permission{permission.Value},
		Results:        []permission.Permission{permission.Any},
	},
	"m (m) func (v) a": &permission.FuncPermission{
		BasePermission: permission.Mutable,
		Receivers:      []permission.Permission{permission.Mutable},
		Params:         []permission.Permission{permission.Value},
		Results:        []permission.Permission{permission.Any},
	},
	"m (m) func (v, l) a": &permission.FuncPermission{
		BasePermission: permission.Mutable,
		Receivers:      []permission.Permission{permission.Mutable},
		Params:         []permission.Permission{permission.Value, permission.LinearValue},
		Results:        []permission.Permission{permission.Any},
	},
	"m (m) func (v, l) (a)": &permission.FuncPermission{
		BasePermission: permission.Mutable,
		Receivers:      []permission.Permission{permission.Mutable},
		Params:         []permission.Permission{permission.Value, permission.LinearValue},
		Results:        []permission.Permission{permission.Any},
	},
	"m (m) func (v, l) (a, n)": &permission.FuncPermission{
		BasePermission: permission.Mutable,
		Receivers:      []permission.Permission{permission.Mutable},
		Params:         []permission.Permission{permission.Value, permission.LinearValue},
		Results:        []permission.Permission{permission.Any, permission.None},
	},
	"m (m) func (v, l)": &permission.FuncPermission{
		BasePermission: permission.Mutable,
		Receivers:      []permission.Permission{permission.Mutable},
		Params:         []permission.Permission{permission.Value, permission.LinearValue},
		Results:        nil,
	},
	"m (m) func ()": &permission.FuncPermission{
		BasePermission: permission.Mutable,
		Receivers:      []permission.Permission{permission.Mutable},
		Params:         nil,
		Results:        nil,
	},
	"m () func (v, l)":       nil,
	"m (m":                   nil,
	"m (m)":                  nil,
	"m (m) func":             nil,
	"m (m) func (":           nil,
	"m (m) func (v":          nil,
	"m (m) func (v,)":        nil,
	"m (m) func (v) error":   nil,
	"m (m) func (v) (error)": nil,
	"m (m) func (v) (v,)":    nil,
	"m (m) func (v) (v !)":   nil,
	"m (m) func (v) (v":      nil,
	"m (m) func (v) hello":   nil,
	// Interface
	"m interface {}": &permission.InterfacePermission{
		BasePermission: permission.Mutable,
	},
	"l interface {}": &permission.InterfacePermission{
		BasePermission: permission.LinearValue,
	},
	"l interface {r; w}": &permission.InterfacePermission{
		BasePermission: permission.LinearValue,
		Methods: []permission.Permission{
			permission.Read,
			permission.Write,
		},
	},
	"m interface {":   nil,
	"m interface {a":  nil,
	"m interface }":   nil,
	"error interface": nil,
	"interface error": nil,
	"{}":              nil,
	"m struct {}":     nil,
	"m struct":        nil,
	"m struct {":      nil,
	"m struct }":      nil,
	"m struct v":      nil,
	"m struct {v}": &permission.StructPermission{
		BasePermission: permission.Mutable,
		Fields: []permission.Permission{
			permission.Value,
		},
	},
	"m struct {v; l}": &permission.StructPermission{
		BasePermission: permission.Mutable,
		Fields: []permission.Permission{
			permission.Value,
			permission.LinearValue,
		},
	},
}

func helper() (perm permission.Permission, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = r.(error)
		}
	}()
	perm = NewParser("error").parseBasePermission()
	return perm, nil
}

func TestParser(t *testing.T) {
	for input, expected := range testCases {
		input := input
		expected := expected
		t.Run(input, func(t *testing.T) {
			perm, err := NewParser(input).Parse()
			if !reflect.DeepEqual(perm, expected) {
				t.Errorf("Input %s: Unexpected permission %v, expected %v - error: %v", input, perm, expected, err)
			}
		})
	}

	perm, err := helper()
	if err == nil {
		t.Errorf("Input 'error' parsed to valid base permission %v", perm)
	}
}

func BenchmarkParser(b *testing.B) {
	keys := make([]string, 0, len(testCases))
	for input := range testCases {
		keys = append(keys, input)
	}
	sort.Strings(keys)

	for _, input := range keys {
		expected := testCases[input]
		if expected == nil {
			continue
		}
		input := input
		b.Run(input, func(b *testing.B) {
			for i := 0; i < b.N; i++ {
				NewParser(input).Parse()
			}
		})
	}
}
<commit_msg>parser_test: Add tests with incomplete runes<commit_after>// (C) 2017 Julian Andres Klode <jak@jak-linux.org>
// Licensed under the 2-Clause BSD license, see LICENSE for more information.
package parser

import (
	"reflect"
	"sort"
	"testing"

	"github.com/julian-klode/lingolang/permission"
)

// testCases contains tests for the permission parser.
var testCases = map[string]permission.Permission{
	"123":     nil,
	"!":       nil,
	"\xc2":    nil, // incomplete rune at beginning
	"a\xc2":   nil, // incomplete rune in word
	"a !":     nil,
	"a error": nil,
	"":        nil,
	"oe":      nil,
	"or":      permission.Owned | permission.Read,
	"ow":      permission.Owned | permission.Write,
	"orwR":    permission.Owned | permission.Read | permission.Write | permission.ExclRead,
	"orR":     permission.Owned | permission.Read | permission.ExclRead,
	"owW":     permission.Owned | permission.Write | permission.ExclWrite,
	"om":      permission.Owned | permission.Mutable,
	"ov":      permission.Owned | permission.Value,
	"a":       permission.Any,
	"on":      permission.Owned,
	"n":       permission.None,
	"m [":     nil,
	"m [1":    nil,
	"m []":    nil,
	"m [1]":   nil,
	"m [] a": &permission.ArraySlicePermission{
		BasePermission:    permission.Mutable,
		ElementPermission: permission.Any,
	},
	"m [1] a": &permission.ArraySlicePermission{
		BasePermission:    permission.Mutable,
		ElementPermission: permission.Any,
	},
	"m map[v]l": &permission.MapPermission{
		BasePermission:  permission.Mutable,
		KeyPermission:   permission.Value,
		ValuePermission: permission.LinearValue,
	},
	"n map":         nil,
	"n map [":       nil,
	"n map [error]": nil,
	"n map [n":      nil,
	"n map [n]":     nil,
	"m chan l": &permission.ChanPermission{
		BasePermission:    permission.Mutable,
		ElementPermission: permission.LinearValue,
	},
	"m chan":       nil,
	"m chan error": nil,
	"m * l": &permission.PointerPermission{
		BasePermission: permission.Mutable,
		Target:         permission.LinearValue,
	},
	"error":     nil,
	"m * error": nil,
	"m func (v) a": &permission.FuncPermission{
		BasePermission: permission.Mutable,
		Receivers:      nil,
		Params:         []permission.Permission{permission.Value},
		Results:        []permission.Permission{permission.Any},
	},
	"m (m) func (v) a": &permission.FuncPermission{
		BasePermission: permission.Mutable,
		Receivers:      []permission.Permission{permission.Mutable},
		Params:         []permission.Permission{permission.Value},
		Results:        []permission.Permission{permission.Any},
	},
	"m (m) func (v, l) a": &permission.FuncPermission{
		BasePermission: permission.Mutable,
		Receivers:      []permission.Permission{permission.Mutable},
		Params:         []permission.Permission{permission.Value, permission.LinearValue},
		Results:        []permission.Permission{permission.Any},
	},
	"m (m) func (v, l) (a)": &permission.FuncPermission{
		BasePermission: permission.Mutable,
		Receivers:      []permission.Permission{permission.Mutable},
		Params:         []permission.Permission{permission.Value, permission.LinearValue},
		Results:        []permission.Permission{permission.Any},
	},
	"m (m) func (v, l) (a, n)": &permission.FuncPermission{
		BasePermission: permission.Mutable,
		Receivers:      []permission.Permission{permission.Mutable},
		Params:         []permission.Permission{permission.Value, permission.LinearValue},
		Results:        []permission.Permission{permission.Any, permission.None},
	},
	"m (m) func (v, l)": &permission.FuncPermission{
		BasePermission: permission.Mutable,
		Receivers:      []permission.Permission{permission.Mutable},
		Params:         []permission.Permission{permission.Value, permission.LinearValue},
		Results:        nil,
	},
	"m (m) func ()": &permission.FuncPermission{
		BasePermission: permission.Mutable,
		Receivers:      []permission.Permission{permission.Mutable},
		Params:         nil,
		Results:        nil,
	},
	"m () func (v, l)":       nil,
	"m (m":                   nil,
	"m (m)":                  nil,
	"m (m) func":             nil,
	"m (m) func (":           nil,
	"m (m) func (v":          nil,
	"m (m) func (v,)":        nil,
	"m (m) func (v) error":   nil,
	"m (m) func (v) (error)": nil,
	"m (m) func (v) (v,)":    nil,
	"m (m) func (v) (v !)":   nil,
	"m (m) func (v) (v":      nil,
	"m (m) func (v) hello":   nil,
	// Interface
	"m interface {}": &permission.InterfacePermission{
		BasePermission: permission.Mutable,
	},
	"l interface {}": &permission.InterfacePermission{
		BasePermission: permission.LinearValue,
	},
	"l interface {r; w}": &permission.InterfacePermission{
		BasePermission: permission.LinearValue,
		Methods: []permission.Permission{
			permission.Read,
			permission.Write,
		},
	},
	"m interface {":   nil,
	"m interface {a":  nil,
	"m interface }":   nil,
	"error interface": nil,
	"interface error": nil,
	"{}":              nil,
	"m struct {}":     nil,
	"m struct":        nil,
	"m struct {":      nil,
	"m struct }":      nil,
	"m struct v":      nil,
	"m struct {v}": &permission.StructPermission{
		BasePermission: permission.Mutable,
		Fields: []permission.Permission{
			permission.Value,
		},
	},
	"m struct {v; l}": &permission.StructPermission{
		BasePermission: permission.Mutable,
		Fields: []permission.Permission{
			permission.Value,
			permission.LinearValue,
		},
	},
}

func helper() (perm permission.Permission, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = r.(error)
		}
	}()
	perm = NewParser("error").parseBasePermission()
	return perm, nil
}

func TestParser(t *testing.T) {
	for input, expected := range testCases {
		input := input
		expected := expected
		t.Run(input, func(t *testing.T) {
			perm, err := NewParser(input).Parse()
			if !reflect.DeepEqual(perm, expected) {
				t.Errorf("Input %s: Unexpected permission %v, expected %v - error: %v", input, perm, expected, err)
			}
		})
	}

	perm, err := helper()
	if err == nil {
		t.Errorf("Input 'error' parsed to valid base permission %v", perm)
	}
}

func BenchmarkParser(b *testing.B) {
	keys := make([]string, 0, len(testCases))
	for input := range testCases {
		keys = append(keys, input)
	}
	sort.Strings(keys)

	for _, input := range keys {
		expected := testCases[input]
		if expected == nil {
			continue
		}
		input := input
		b.Run(input, func(b *testing.B) {
			for i := 0; i < b.N; i++ {
				NewParser(input).Parse()
			}
		})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"
)

const (
	OpGet         = "/get"
	OpSet         = "/post"
	OpInfo        = "._info"
	OpDelete      = "/delete"
	OpAllKeys     = "_all"
	OpUptime      = "_uptime"
	OpCursorFirst = "_first"
	OpCursorLast  = "_last"
	OpCursorNext  = "._next"
	OpCursorPrev  = "._prev"
	OpPrefixMatch = "._match"
	OpBulkUnjar   = "_bulk_unjar"
)

func httpGet(w http.ResponseWriter, op Operation) *HTTPError {
	value := op.Database.Unjar(op.Keys[0])
	// Check if the item existed
	if value == nil {
		return &HTTPError{Code: 404, Message: "These aren't your ghosts."}
	}

	// Send value
	w.Header().Add("Content-Length", strconv.Itoa(len(value)))
	w.Write(value)
	return nil
}

func httpSet(w http.ResponseWriter, op Operation, r *http.Request) *HTTPError {
	value, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return &HTTPError{Code: 500, Message: "Your post body is messed up!"}
	}

	// Check if value already existed
	exists := op.Database.Exists(op.Keys[0])

	res := op.Database.Jar(op.Keys[0], value)
	if res == 0 {
		// Status 201 if created, 200 if updated
		if exists {
			w.WriteHeader(200)
		} else {
			w.WriteHeader(201)
		}
		fmt.Fprintf(w, "無駄")
	} else {
		return &HTTPError{Code: 500, Message: "Something went horribly wrong..."}
	}

	// Try to set expiration, if provided
	if eep, ok := r.Header["X-Olegdb-Use-By"]; ok {
		ep, err := strconv.Atoi(eep[0])
		if err != nil {
			return &HTTPError{Code: 500, Message: "The expiration format is wrong!"}
		}
		date := time.Unix(int64(ep), 0)
		op.Database.Spoil(op.Keys[0], date)
		// fmt.Fprintf(w, "\r\nThe jar is spoiling!")
	}

	return nil
}

func httpInfo(w http.ResponseWriter, op Operation) *HTTPError {
	// Does it even exists?
	if !op.Database.Exists(op.Keys[0]) {
		return &HTTPError{Code: 404, Message: "Key not found in database"}
	}

	// Get and set Expiration
	res, doesExpire := op.Database.Expiration(op.Keys[0])
	if doesExpire {
		w.Header().Add("Expires", strconv.Itoa(int(res.UTC().Unix())))
	}

	// Add Record count
	w.Header().Add("X-Olegdb-Rcrd-Cnt", strconv.Itoa(int(*op.Database.RecordCount)))

	// Send empty body
	fmt.Fprintf(w, "\r\n")
	return nil
}

func httpUptime(w http.ResponseWriter, op Operation) *HTTPError {
	res := op.Database.Uptime()

	fmt.Fprintf(w, "%d", res)
	return nil
}

func httpDelete(w http.ResponseWriter, op Operation) *HTTPError {
	res := op.Database.Scoop(op.Keys[0])
	if res != 0 {
		return &HTTPError{Code: 500, Message: "Something went horribly wrong..."}
	}

	fmt.Fprintf(w, "Key deleted successfully!")
	return nil
}

func httpMatch(w http.ResponseWriter, op Operation) *HTTPError {
	has, res := op.Database.PrefixMatch(op.Keys[0])
	if !has {
		return &HTTPError{Code: 404, Message: "No matches found"}
	}
	w.Header().Add("X-Olegdb-Num-Matches", strconv.Itoa(len(res)))
	content := strings.Join(res, "\n")
	w.Header().Add("Content-Length", strconv.Itoa(len(content)))
	fmt.Fprintf(w, content)
	return nil
}

func httpAll(w http.ResponseWriter, op Operation) *HTTPError {
	has, res := op.Database.DumpKeys()
	if !has {
		return &HTTPError{Code: 404, Message: "Could not dump keys. (Sharks om the beach?)"}
	}
	w.Header().Add("X-Olegdb-Num-Matches", strconv.Itoa(len(res)))
	content := strings.Join(res, "\n")
	w.Header().Add("Content-Length", strconv.Itoa(len(content)))
	fmt.Fprintf(w, content)
	return nil
}

func httpCurFirst(w http.ResponseWriter, op Operation) *HTTPError {
	has, key, data := op.Database.First()
	if !has {
		return &HTTPError{Code: 404, Message: "No records found"}
	}
	w.Header().Add("X-Olegdb-Key", key)
	w.Write(data)
	return nil
}

func httpCurLast(w http.ResponseWriter, op Operation) *HTTPError {
	has, key, data := op.Database.Last()
	if !has {
		return &HTTPError{Code: 404, Message: "No records found"}
	}
	w.Header().Add("X-Olegdb-Key", key)
	w.Write(data)
	return nil
}

func httpCurNext(w http.ResponseWriter, op Operation) *HTTPError {
	has, key, data := op.Database.Next(op.Keys[0])
	if !has {
		return &HTTPError{Code: 404, Message: "No records found"}
	}
	w.Header().Add("X-Olegdb-Key", key)
	w.Write(data)
	return nil
}

func httpCurPrev(w http.ResponseWriter, op Operation) *HTTPError {
	has, key, data := op.Database.Prev(op.Keys[0])
	if !has {
		return &HTTPError{Code: 404, Message: "No records found"}
	}
	w.Header().Add("X-Olegdb-Key", key)
	w.Write(data)
	return nil
}

func httpBulkUnjar(w http.ResponseWriter, op Operation) *HTTPError {
	matched_keys := op.Database.BulkUnjar(op.Keys)

	for _, key := range matched_keys {
		w.Write([]byte(fmt.Sprintf("%0d%s", len(key), key)))
	}
	return nil
}
<commit_msg>Pad out sizes correctly.<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"
)

const (
	OpGet         = "/get"
	OpSet         = "/post"
	OpInfo        = "._info"
	OpDelete      = "/delete"
	OpAllKeys     = "_all"
	OpUptime      = "_uptime"
	OpCursorFirst = "_first"
	OpCursorLast  = "_last"
	OpCursorNext  = "._next"
	OpCursorPrev  = "._prev"
	OpPrefixMatch = "._match"
	OpBulkUnjar   = "_bulk_unjar"
)

func httpGet(w http.ResponseWriter, op Operation) *HTTPError {
	value := op.Database.Unjar(op.Keys[0])
	// Check if the item existed
	if value == nil {
		return &HTTPError{Code: 404, Message: "These aren't your ghosts."}
	}

	// Send value
	w.Header().Add("Content-Length", strconv.Itoa(len(value)))
	w.Write(value)
	return nil
}

func httpSet(w http.ResponseWriter, op Operation, r *http.Request) *HTTPError {
	value, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return &HTTPError{Code: 500, Message: "Your post body is messed up!"}
	}

	// Check if value already existed
	exists := op.Database.Exists(op.Keys[0])

	res := op.Database.Jar(op.Keys[0], value)
	if res == 0 {
		// Status 201 if created, 200 if updated
		if exists {
			w.WriteHeader(200)
		} else {
			w.WriteHeader(201)
		}
		fmt.Fprintf(w, "無駄")
	} else {
		return &HTTPError{Code: 500, Message: "Something went horribly wrong..."}
	}

	// Try to set expiration, if provided
	if eep, ok := r.Header["X-Olegdb-Use-By"]; ok {
		ep, err := strconv.Atoi(eep[0])
		if err != nil {
			return &HTTPError{Code: 500, Message: "The expiration format is wrong!"}
		}
		date := time.Unix(int64(ep), 0)
		op.Database.Spoil(op.Keys[0], date)
		// fmt.Fprintf(w, "\r\nThe jar is spoiling!")
	}

	return nil
}

func httpInfo(w http.ResponseWriter, op Operation) *HTTPError {
	// Does it even exists?
	if !op.Database.Exists(op.Keys[0]) {
		return &HTTPError{Code: 404, Message: "Key not found in database"}
	}

	// Get and set Expiration
	res, doesExpire := op.Database.Expiration(op.Keys[0])
	if doesExpire {
		w.Header().Add("Expires", strconv.Itoa(int(res.UTC().Unix())))
	}

	// Add Record count
	w.Header().Add("X-Olegdb-Rcrd-Cnt", strconv.Itoa(int(*op.Database.RecordCount)))

	// Send empty body
	fmt.Fprintf(w, "\r\n")
	return nil
}

func httpUptime(w http.ResponseWriter, op Operation) *HTTPError {
	res := op.Database.Uptime()

	fmt.Fprintf(w, "%d", res)
	return nil
}

func httpDelete(w http.ResponseWriter, op Operation) *HTTPError {
	res := op.Database.Scoop(op.Keys[0])
	if res != 0 {
		return &HTTPError{Code: 500, Message: "Something went horribly wrong..."}
	}

	fmt.Fprintf(w, "Key deleted successfully!")
	return nil
}

func httpMatch(w http.ResponseWriter, op Operation) *HTTPError {
	has, res := op.Database.PrefixMatch(op.Keys[0])
	if !has {
		return &HTTPError{Code: 404, Message: "No matches found"}
	}
	w.Header().Add("X-Olegdb-Num-Matches", strconv.Itoa(len(res)))
	content := strings.Join(res, "\n")
	w.Header().Add("Content-Length", strconv.Itoa(len(content)))
	fmt.Fprintf(w, content)
	return nil
}

func httpAll(w http.ResponseWriter, op Operation) *HTTPError {
	has, res := op.Database.DumpKeys()
	if !has {
		return &HTTPError{Code: 404, Message: "Could not dump keys. (Sharks om the beach?)"}
	}
	w.Header().Add("X-Olegdb-Num-Matches", strconv.Itoa(len(res)))
	content := strings.Join(res, "\n")
	w.Header().Add("Content-Length", strconv.Itoa(len(content)))
	fmt.Fprintf(w, content)
	return nil
}

func httpCurFirst(w http.ResponseWriter, op Operation) *HTTPError {
	has, key, data := op.Database.First()
	if !has {
		return &HTTPError{Code: 404, Message: "No records found"}
	}
	w.Header().Add("X-Olegdb-Key", key)
	w.Write(data)
	return nil
}

func httpCurLast(w http.ResponseWriter, op Operation) *HTTPError {
	has, key, data := op.Database.Last()
	if !has {
		return &HTTPError{Code: 404, Message: "No records found"}
	}
	w.Header().Add("X-Olegdb-Key", key)
	w.Write(data)
	return nil
}

func httpCurNext(w http.ResponseWriter, op Operation) *HTTPError {
	has, key, data := op.Database.Next(op.Keys[0])
	if !has {
		return &HTTPError{Code: 404, Message: "No records found"}
	}
	w.Header().Add("X-Olegdb-Key", key)
	w.Write(data)
	return nil
}

func httpCurPrev(w http.ResponseWriter, op Operation) *HTTPError {
	has, key, data := op.Database.Prev(op.Keys[0])
	if !has {
		return &HTTPError{Code: 404, Message: "No records found"}
	}
	w.Header().Add("X-Olegdb-Key", key)
	w.Write(data)
	return nil
}

func httpBulkUnjar(w http.ResponseWriter, op Operation) *HTTPError {
	matched_keys := op.Database.BulkUnjar(op.Keys)

	for _, key := range matched_keys {
		w.Write([]byte(fmt.Sprintf("%08d%s", len(key), key)))
	}
	return nil
}
<|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 completion

import (
	"bytes"
	"io"

	"github.com/spf13/cobra"

	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/templates"
)

const defaultBoilerPlate = `
# 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.
`

var (
	completionLong = templates.LongDesc(i18n.T(`
		Output shell completion code for the specified shell (bash or zsh).
		The shell code must be evaluated to provide interactive
		completion of kubectl commands.  This can be done by sourcing it from
		the .bash_profile.

		Detailed instructions on how to do this are available here:
		https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion

		Note for zsh users: [1] zsh completions are only supported in versions of zsh >= 5.2`))

	completionExample = templates.Examples(i18n.T(`
		# Installing bash completion on macOS using homebrew
		## If running Bash 3.2 included with macOS
		    brew install bash-completion
		## or, if running Bash 4.1+
		    brew install bash-completion@2
		## If kubectl is installed via homebrew, this should start working immediately.
		## If you've installed via other means, you may need add the completion to your completion directory
		    kubectl completion bash > $(brew --prefix)/etc/bash_completion.d/kubectl

		# Installing bash completion on Linux
		## If bash-completion is not installed on Linux, please install the 'bash-completion' package
		## via your distribution's package manager.
		## Load the kubectl completion code for bash into the current shell
		    source <(kubectl completion bash)
		## Write bash completion code to a file and source if from .bash_profile
		    kubectl completion bash > ~/.kube/completion.bash.inc
		    printf "
		      # Kubectl shell completion
		      source '$HOME/.kube/completion.bash.inc'
		      " >> $HOME/.bash_profile
		    source $HOME/.bash_profile

		# Load the kubectl completion code for zsh[1] into the current shell
		    source <(kubectl completion zsh)
		# Set the kubectl completion code for zsh[1] to autoload on startup
		    kubectl completion zsh > "${fpath[1]}/_kubectl"`))
)

var (
	completionShells = map[string]func(out io.Writer, boilerPlate string, cmd *cobra.Command) error{
		"bash": runCompletionBash,
		"zsh":  runCompletionZsh,
	}
)

// NewCmdCompletion creates the `completion` command
func NewCmdCompletion(out io.Writer, boilerPlate string) *cobra.Command {
	shells := []string{}
	for s := range completionShells {
		shells = append(shells, s)
	}

	cmd := &cobra.Command{
		Use:                   "completion SHELL",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Output shell completion code for the specified shell (bash or zsh)"),
		Long:                  completionLong,
		Example:               completionExample,
		Run: func(cmd *cobra.Command, args []string) {
			err := RunCompletion(out, boilerPlate, cmd, args)
			cmdutil.CheckErr(err)
		},
		ValidArgs: shells,
	}

	return cmd
}

// RunCompletion checks given arguments and executes command
func RunCompletion(out io.Writer, boilerPlate string, cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		return cmdutil.UsageErrorf(cmd, "Shell not specified.")
	}
	if len(args) > 1 {
		return cmdutil.UsageErrorf(cmd, "Too many arguments. Expected only the shell type.")
	}
	run, found := completionShells[args[0]]
	if !found {
		return cmdutil.UsageErrorf(cmd, "Unsupported shell type %q.", args[0])
	}

	return run(out, boilerPlate, cmd.Parent())
}

func runCompletionBash(out io.Writer, boilerPlate string, kubectl *cobra.Command) error {
	if len(boilerPlate) == 0 {
		boilerPlate = defaultBoilerPlate
	}
	if _, err := out.Write([]byte(boilerPlate)); err != nil {
		return err
	}

	return kubectl.GenBashCompletion(out)
}

func runCompletionZsh(out io.Writer, boilerPlate string, kubectl *cobra.Command) error {
	zshHead := "#compdef kubectl\n"

	out.Write([]byte(zshHead))

	if len(boilerPlate) == 0 {
		boilerPlate = defaultBoilerPlate
	}
	if _, err := out.Write([]byte(boilerPlate)); err != nil {
		return err
	}

	zshInitialization := `
__kubectl_bash_source() {
	alias shopt=':'
	alias _expand=_bash_expand
	alias _complete=_bash_comp
	emulate -L sh
	setopt kshglob noshglob braceexpand

	source "$@"
}

__kubectl_type() {
	# -t is not supported by zsh
	if [ "$1" == "-t" ]; then
		shift

		# fake Bash 4 to disable "complete -o nospace". Instead
		# "compopt +-o nospace" is used in the code to toggle trailing
		# spaces. We don't support that, but leave trailing spaces on
		# all the time
		if [ "$1" = "__kubectl_compopt" ]; then
			echo builtin
			return 0
		fi
	fi
	type "$@"
}

__kubectl_compgen() {
	local completions w
	completions=( $(compgen "$@") ) || return $?

	# filter by given word as prefix
	while [[ "$1" = -* && "$1" != -- ]]; do
		shift
		shift
	done
	if [[ "$1" == -- ]]; then
		shift
	fi
	for w in "${completions[@]}"; do
		if [[ "${w}" = "$1"* ]]; then
			echo "${w}"
		fi
	done
}

__kubectl_compopt() {
	true # don't do anything. Not supported by bashcompinit in zsh
}

__kubectl_ltrim_colon_completions()
{
	if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
		# Remove colon-word prefix from COMPREPLY items
		local colon_word=${1%${1##*:}}
		local i=${#COMPREPLY[*]}
		while [[ $((--i)) -ge 0 ]]; do
			COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
		done
	fi
}

__kubectl_get_comp_words_by_ref() {
	cur="${COMP_WORDS[COMP_CWORD]}"
	prev="${COMP_WORDS[${COMP_CWORD}-1]}"
	words=("${COMP_WORDS[@]}")
	cword=("${COMP_CWORD[@]}")
}

__kubectl_filedir() {
	local RET OLD_IFS w qw

	__kubectl_debug "_filedir $@ cur=$cur"
	if [[ "$1" = \~* ]]; then
		# somehow does not work. Maybe, zsh does not call this at all
		eval echo "$1"
		return 0
	fi

	OLD_IFS="$IFS"
	IFS=$'\n'
	if [ "$1" = "-d" ]; then
		shift
		RET=( $(compgen -d) )
	else
		RET=( $(compgen -f) )
	fi
	IFS="$OLD_IFS"

	IFS="," __kubectl_debug "RET=${RET[@]} len=${#RET[@]}"

	for w in ${RET[@]}; do
		if [[ ! "${w}" = "${cur}"* ]]; then
			continue
		fi
		if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then
			qw="$(__kubectl_quote "${w}")"
			if [ -d "${w}" ]; then
				COMPREPLY+=("${qw}/")
			else
				COMPREPLY+=("${qw}")
			fi
		fi
	done
}

__kubectl_quote() {
    if [[ $1 == \'* || $1 == \"* ]]; then
        # Leave out first character
        printf %q "${1:1}"
    else
	printf %q "$1"
    fi
}

autoload -U +X bashcompinit && bashcompinit

# use word boundary patterns for BSD or GNU sed
LWORD='[[:<:]]'
RWORD='[[:>:]]'
if sed --help 2>&1 | grep -q GNU; then
	LWORD='\<'
	RWORD='\>'
fi

__kubectl_convert_bash_to_zsh() {
	sed \
	-e 's/declare -F/whence -w/' \
	-e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \
	-e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \
	-e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \
	-e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \
	-e "s/${LWORD}_filedir${RWORD}/__kubectl_filedir/g" \
	-e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__kubectl_get_comp_words_by_ref/g" \
	-e "s/${LWORD}__ltrim_colon_completions${RWORD}/__kubectl_ltrim_colon_completions/g" \
	-e "s/${LWORD}compgen${RWORD}/__kubectl_compgen/g" \
	-e "s/${LWORD}compopt${RWORD}/__kubectl_compopt/g" \
	-e "s/${LWORD}declare${RWORD}/builtin declare/g" \
	-e "s/\\\$(type${RWORD}/\$(__kubectl_type/g" \
	<<'BASH_COMPLETION_EOF'
`
	out.Write([]byte(zshInitialization))

	buf := new(bytes.Buffer)
	kubectl.GenBashCompletion(buf)
	out.Write(buf.Bytes())

	zshTail := `
BASH_COMPLETION_EOF
}

__kubectl_bash_source <(__kubectl_convert_bash_to_zsh)
_complete kubectl 2>/dev/null
`
	out.Write([]byte(zshTail))
	return nil
}
<commit_msg>Removed unnecessary _complete call which was silently failing and causing zsh completion to return a nonzero exit code Removed unnecessary _complete and _expand aliases for zsh completion<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 completion

import (
	"bytes"
	"io"

	"github.com/spf13/cobra"

	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/templates"
)

const defaultBoilerPlate = `
# 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.
`

var (
	completionLong = templates.LongDesc(i18n.T(`
		Output shell completion code for the specified shell (bash or zsh).
		The shell code must be evaluated to provide interactive
		completion of kubectl commands.  This can be done by sourcing it from
		the .bash_profile.

		Detailed instructions on how to do this are available here:
		https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion

		Note for zsh users: [1] zsh completions are only supported in versions of zsh >= 5.2`))

	completionExample = templates.Examples(i18n.T(`
		# Installing bash completion on macOS using homebrew
		## If running Bash 3.2 included with macOS
		    brew install bash-completion
		## or, if running Bash 4.1+
		    brew install bash-completion@2
		## If kubectl is installed via homebrew, this should start working immediately.
		## If you've installed via other means, you may need add the completion to your completion directory
		    kubectl completion bash > $(brew --prefix)/etc/bash_completion.d/kubectl

		# Installing bash completion on Linux
		## If bash-completion is not installed on Linux, please install the 'bash-completion' package
		## via your distribution's package manager.
		## Load the kubectl completion code for bash into the current shell
		    source <(kubectl completion bash)
		## Write bash completion code to a file and source if from .bash_profile
		    kubectl completion bash > ~/.kube/completion.bash.inc
		    printf "
		      # Kubectl shell completion
		      source '$HOME/.kube/completion.bash.inc'
		      " >> $HOME/.bash_profile
		    source $HOME/.bash_profile

		# Load the kubectl completion code for zsh[1] into the current shell
		    source <(kubectl completion zsh)
		# Set the kubectl completion code for zsh[1] to autoload on startup
		    kubectl completion zsh > "${fpath[1]}/_kubectl"`))
)

var (
	completionShells = map[string]func(out io.Writer, boilerPlate string, cmd *cobra.Command) error{
		"bash": runCompletionBash,
		"zsh":  runCompletionZsh,
	}
)

// NewCmdCompletion creates the `completion` command
func NewCmdCompletion(out io.Writer, boilerPlate string) *cobra.Command {
	shells := []string{}
	for s := range completionShells {
		shells = append(shells, s)
	}

	cmd := &cobra.Command{
		Use:                   "completion SHELL",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Output shell completion code for the specified shell (bash or zsh)"),
		Long:                  completionLong,
		Example:               completionExample,
		Run: func(cmd *cobra.Command, args []string) {
			err := RunCompletion(out, boilerPlate, cmd, args)
			cmdutil.CheckErr(err)
		},
		ValidArgs: shells,
	}

	return cmd
}

// RunCompletion checks given arguments and executes command
func RunCompletion(out io.Writer, boilerPlate string, cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		return cmdutil.UsageErrorf(cmd, "Shell not specified.")
	}
	if len(args) > 1 {
		return cmdutil.UsageErrorf(cmd, "Too many arguments. Expected only the shell type.")
	}
	run, found := completionShells[args[0]]
	if !found {
		return cmdutil.UsageErrorf(cmd, "Unsupported shell type %q.", args[0])
	}

	return run(out, boilerPlate, cmd.Parent())
}

func runCompletionBash(out io.Writer, boilerPlate string, kubectl *cobra.Command) error {
	if len(boilerPlate) == 0 {
		boilerPlate = defaultBoilerPlate
	}
	if _, err := out.Write([]byte(boilerPlate)); err != nil {
		return err
	}

	return kubectl.GenBashCompletion(out)
}

func runCompletionZsh(out io.Writer, boilerPlate string, kubectl *cobra.Command) error {
	zshHead := "#compdef kubectl\n"

	out.Write([]byte(zshHead))

	if len(boilerPlate) == 0 {
		boilerPlate = defaultBoilerPlate
	}
	if _, err := out.Write([]byte(boilerPlate)); err != nil {
		return err
	}

	zshInitialization := `
__kubectl_bash_source() {
	alias shopt=':'
	emulate -L sh
	setopt kshglob noshglob braceexpand

	source "$@"
}

__kubectl_type() {
	# -t is not supported by zsh
	if [ "$1" == "-t" ]; then
		shift

		# fake Bash 4 to disable "complete -o nospace". Instead
		# "compopt +-o nospace" is used in the code to toggle trailing
		# spaces. We don't support that, but leave trailing spaces on
		# all the time
		if [ "$1" = "__kubectl_compopt" ]; then
			echo builtin
			return 0
		fi
	fi
	type "$@"
}

__kubectl_compgen() {
	local completions w
	completions=( $(compgen "$@") ) || return $?

	# filter by given word as prefix
	while [[ "$1" = -* && "$1" != -- ]]; do
		shift
		shift
	done
	if [[ "$1" == -- ]]; then
		shift
	fi
	for w in "${completions[@]}"; do
		if [[ "${w}" = "$1"* ]]; then
			echo "${w}"
		fi
	done
}

__kubectl_compopt() {
	true # don't do anything. Not supported by bashcompinit in zsh
}

__kubectl_ltrim_colon_completions()
{
	if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
		# Remove colon-word prefix from COMPREPLY items
		local colon_word=${1%${1##*:}}
		local i=${#COMPREPLY[*]}
		while [[ $((--i)) -ge 0 ]]; do
			COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
		done
	fi
}

__kubectl_get_comp_words_by_ref() {
	cur="${COMP_WORDS[COMP_CWORD]}"
	prev="${COMP_WORDS[${COMP_CWORD}-1]}"
	words=("${COMP_WORDS[@]}")
	cword=("${COMP_CWORD[@]}")
}

__kubectl_filedir() {
	local RET OLD_IFS w qw

	__kubectl_debug "_filedir $@ cur=$cur"
	if [[ "$1" = \~* ]]; then
		# somehow does not work. Maybe, zsh does not call this at all
		eval echo "$1"
		return 0
	fi

	OLD_IFS="$IFS"
	IFS=$'\n'
	if [ "$1" = "-d" ]; then
		shift
		RET=( $(compgen -d) )
	else
		RET=( $(compgen -f) )
	fi
	IFS="$OLD_IFS"

	IFS="," __kubectl_debug "RET=${RET[@]} len=${#RET[@]}"

	for w in ${RET[@]}; do
		if [[ ! "${w}" = "${cur}"* ]]; then
			continue
		fi
		if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then
			qw="$(__kubectl_quote "${w}")"
			if [ -d "${w}" ]; then
				COMPREPLY+=("${qw}/")
			else
				COMPREPLY+=("${qw}")
			fi
		fi
	done
}

__kubectl_quote() {
    if [[ $1 == \'* || $1 == \"* ]]; then
        # Leave out first character
        printf %q "${1:1}"
    else
	printf %q "$1"
    fi
}

autoload -U +X bashcompinit && bashcompinit

# use word boundary patterns for BSD or GNU sed
LWORD='[[:<:]]'
RWORD='[[:>:]]'
if sed --help 2>&1 | grep -q GNU; then
	LWORD='\<'
	RWORD='\>'
fi

__kubectl_convert_bash_to_zsh() {
	sed \
	-e 's/declare -F/whence -w/' \
	-e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \
	-e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \
	-e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \
	-e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \
	-e "s/${LWORD}_filedir${RWORD}/__kubectl_filedir/g" \
	-e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__kubectl_get_comp_words_by_ref/g" \
	-e "s/${LWORD}__ltrim_colon_completions${RWORD}/__kubectl_ltrim_colon_completions/g" \
	-e "s/${LWORD}compgen${RWORD}/__kubectl_compgen/g" \
	-e "s/${LWORD}compopt${RWORD}/__kubectl_compopt/g" \
	-e "s/${LWORD}declare${RWORD}/builtin declare/g" \
	-e "s/\\\$(type${RWORD}/\$(__kubectl_type/g" \
	<<'BASH_COMPLETION_EOF'
`
	out.Write([]byte(zshInitialization))

	buf := new(bytes.Buffer)
	kubectl.GenBashCompletion(buf)
	out.Write(buf.Bytes())

	zshTail := `
BASH_COMPLETION_EOF
}

__kubectl_bash_source <(__kubectl_convert_bash_to_zsh)
`
	out.Write([]byte(zshTail))
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Kubernetes Authors All rights reserved.

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 types

import (
	"fmt"
	"strconv"
	"strings"
	"time"
)

const (
	DefaultCoolDownTime       = 2 * time.Minute
	DefaultHealthCheckTimeout = 10 * time.Second
	CmdTimeout                = 10 * time.Second
	UptimeTimeLayout          = "Mon 2006-01-02 15:04:05 UTC"
	LogParsingTimeLayout      = "2006-01-02 15:04:05"

	DefaultCriCtl        = "/usr/bin/crictl"
	DefaultCriSocketPath = "unix:///var/run/containerd/containerd.sock"

	KubeletComponent  = "kubelet"
	CRIComponent      = "cri"
	DockerComponent   = "docker"
	ContainerdService = "containerd"

	KubeletHealthCheckEndpoint = "http://127.0.0.1:10248/healthz"

	LogPatternFlagSeparator = ":"
)

type HealthChecker interface {
	CheckHealth() (bool, error)
}

// LogPatternFlag defines the flag for log pattern health check.
// It contains a map of <log pattern> to <failure threshold for the pattern>
type LogPatternFlag struct {
	logPatternCountMap map[string]int
}

// String implements the String function for flag.Value interface
func (lpf *LogPatternFlag) String() string {
	result := ""
	for k, v := range lpf.logPatternCountMap {
		if result != "" {
			result += " "
		}
		result += fmt.Sprintf("%v:%v", k, v)
	}
	return result
}

// Set implements the Set function for flag.Value interface
func (lpf *LogPatternFlag) Set(value string) error {
	if lpf.logPatternCountMap == nil {
		lpf.logPatternCountMap = make(map[string]int)
	}
	items := strings.Split(value, ",")
	for _, item := range items {
		val := strings.SplitN(item, LogPatternFlagSeparator, 2)
		if len(val) != 2 {
			return fmt.Errorf("invalid format of the flag value: %v", val)
		}
		countThreshold, err := strconv.Atoi(val[0])
		if err != nil || countThreshold == 0 {
			return fmt.Errorf("invalid format for the flag value: %v: %v", val, err)
		}
		pattern := val[1]
		if pattern == "" {
			return fmt.Errorf("invalid format for the flag value: %v: %v", val, err)
		}
		lpf.logPatternCountMap[pattern] = countThreshold
	}
	return nil
}

// Type implements the Type function for flag.Value interface
func (lpf *LogPatternFlag) Type() string {
	return "logPatternFlag"
}

// GetLogPatternCountMap returns the stored log count map
func (lpf *LogPatternFlag) GetLogPatternCountMap() map[string]int {
	return lpf.logPatternCountMap
}
<commit_msg>Fix for flaky unit test in health checker<commit_after>/*
Copyright 2020 The Kubernetes Authors All rights reserved.

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 types

import (
	"fmt"
	"sort"
	"strconv"
	"strings"
	"time"
)

const (
	DefaultCoolDownTime       = 2 * time.Minute
	DefaultHealthCheckTimeout = 10 * time.Second
	CmdTimeout                = 10 * time.Second
	UptimeTimeLayout          = "Mon 2006-01-02 15:04:05 UTC"
	LogParsingTimeLayout      = "2006-01-02 15:04:05"

	DefaultCriCtl        = "/usr/bin/crictl"
	DefaultCriSocketPath = "unix:///var/run/containerd/containerd.sock"

	KubeletComponent  = "kubelet"
	CRIComponent      = "cri"
	DockerComponent   = "docker"
	ContainerdService = "containerd"

	KubeletHealthCheckEndpoint = "http://127.0.0.1:10248/healthz"

	LogPatternFlagSeparator = ":"
)

type HealthChecker interface {
	CheckHealth() (bool, error)
}

// LogPatternFlag defines the flag for log pattern health check.
// It contains a map of <log pattern> to <failure threshold for the pattern>
type LogPatternFlag struct {
	logPatternCountMap map[string]int
}

// String implements the String function for flag.Value interface
// Returns a space separated sorted by keys string of map values.
func (lpf *LogPatternFlag) String() string {
	result := ""
	var keys []string
	for k := range lpf.logPatternCountMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		if result != "" {
			result += " "
		}
		result += fmt.Sprintf("%v:%v", k, lpf.logPatternCountMap[k])
	}
	return result
}

// Set implements the Set function for flag.Value interface
func (lpf *LogPatternFlag) Set(value string) error {
	if lpf.logPatternCountMap == nil {
		lpf.logPatternCountMap = make(map[string]int)
	}
	items := strings.Split(value, ",")
	for _, item := range items {
		val := strings.SplitN(item, LogPatternFlagSeparator, 2)
		if len(val) != 2 {
			return fmt.Errorf("invalid format of the flag value: %v", val)
		}
		countThreshold, err := strconv.Atoi(val[0])
		if err != nil || countThreshold == 0 {
			return fmt.Errorf("invalid format for the flag value: %v: %v", val, err)
		}
		pattern := val[1]
		if pattern == "" {
			return fmt.Errorf("invalid format for the flag value: %v: %v", val, err)
		}
		lpf.logPatternCountMap[pattern] = countThreshold
	}
	return nil
}

// Type implements the Type function for flag.Value interface
func (lpf *LogPatternFlag) Type() string {
	return "logPatternFlag"
}

// GetLogPatternCountMap returns the stored log count map
func (lpf *LogPatternFlag) GetLogPatternCountMap() map[string]int {
	return lpf.logPatternCountMap
}
<|endoftext|>


<commit_before>package v7

import (
	"fmt"

	"code.cloudfoundry.org/cli/actor/actionerror"
	"code.cloudfoundry.org/cli/actor/sharedaction"
	"code.cloudfoundry.org/cli/actor/v7action"
	"code.cloudfoundry.org/cli/command"
	"code.cloudfoundry.org/cli/command/flag"
	"code.cloudfoundry.org/cli/command/v7/shared"
	"code.cloudfoundry.org/clock"
)

//go:generate counterfeiter . DeletePrivateDomainActor

type DeletePrivateDomainActor interface {
	DeleteDomain(domain v7action.Domain) (v7action.Warnings, error)
	GetDomainByName(domainName string) (v7action.Domain, v7action.Warnings, error)
}

type DeletePrivateDomainCommand struct {
	RequiredArgs    flag.Domain `positional-args:"yes"`
	Force           bool        `short:"f" description:"Force deletion without confirmation"`
	usage           interface{} `usage:"CF_NAME delete-private-domain DOMAIN [-f]"`
	relatedCommands interface{} `related_commands:"delete-shared-domain, domains, unshare-private-domain"`

	UI          command.UI
	Config      command.Config
	SharedActor command.SharedActor
	Actor       DeletePrivateDomainActor
}

func (cmd *DeletePrivateDomainCommand) Setup(config command.Config, ui command.UI) error {
	cmd.UI = ui
	cmd.Config = config
	cmd.SharedActor = sharedaction.NewActor(config)

	ccClient, _, err := shared.GetNewClientsAndConnectToCF(config, ui, "")
	if err != nil {
		return err
	}
	cmd.Actor = v7action.NewActor(ccClient, config, nil, nil, clock.NewClock())

	return nil
}

func (cmd DeletePrivateDomainCommand) Execute(args []string) error {
	domainName := cmd.RequiredArgs.Domain
	err := cmd.SharedActor.CheckTarget(true, false)
	if err != nil {
		return err
	}

	currentUser, err := cmd.Config.CurrentUser()
	if err != nil {
		return err
	}

	domain, warnings, err := cmd.Actor.GetDomainByName(domainName)
	cmd.UI.DisplayWarningsV7(warnings)

	cmd.UI.DisplayTextWithFlavor("Deleting private domain {{.DomainName}} as {{.Username}}...", map[string]interface{}{
		"DomainName": domainName,
		"Username":   currentUser.Name,
	})

	if err != nil {
		if _, ok := err.(actionerror.DomainNotFoundError); ok {
			cmd.UI.DisplayTextWithFlavor("Deleting private domain {{.DomainName}} as {{.Username}}...", map[string]interface{}{
				"DomainName": domainName,
				"Username":   currentUser.Name,
			})
			cmd.UI.DisplayWarningV7("Domain '{{.DomainName}}' does not exist.", map[string]interface{}{
				"DomainName": cmd.RequiredArgs.Domain,
			})
			cmd.UI.DisplayOK()
			return nil
		}
		return err
	}

	if domain.Shared() {
		return fmt.Errorf("Domain '%s' is a shared domain, not a private domain.", domainName)
	}

	cmd.UI.DisplayText("Deleting the private domain will remove associated routes which will make apps with this domain unreachable.")

	if !cmd.Force {
		response, promptErr := cmd.UI.DisplayBoolPrompt(false, "Really delete the private domain {{.DomainName}}?", map[string]interface{}{
			"DomainName": domainName,
		})

		if promptErr != nil {
			return promptErr
		}

		if !response {
			cmd.UI.DisplayText("'{{.DomainName}}' has not been deleted.", map[string]interface{}{
				"DomainName": domainName,
			})
			return nil
		}
	}
	cmd.UI.DisplayTextWithFlavor("Deleting private domain {{.DomainName}} as {{.Username}}...", map[string]interface{}{
		"DomainName": domainName,
		"Username":   currentUser.Name,
	})

	warnings, err = cmd.Actor.DeleteDomain(domain)
	cmd.UI.DisplayWarningsV7(warnings)

	if err != nil {
		return err
	}

	cmd.UI.DisplayOK()

	cmd.UI.DisplayText("TIP: Run 'cf domains' to view available domains.")

	return nil
}
<commit_msg>Fix gofmt<commit_after>package v7

import (
	"fmt"

	"code.cloudfoundry.org/cli/actor/actionerror"
	"code.cloudfoundry.org/cli/actor/sharedaction"
	"code.cloudfoundry.org/cli/actor/v7action"
	"code.cloudfoundry.org/cli/command"
	"code.cloudfoundry.org/cli/command/flag"
	"code.cloudfoundry.org/cli/command/v7/shared"
	"code.cloudfoundry.org/clock"
)

//go:generate counterfeiter . DeletePrivateDomainActor

type DeletePrivateDomainActor interface {
	DeleteDomain(domain v7action.Domain) (v7action.Warnings, error)
	GetDomainByName(domainName string) (v7action.Domain, v7action.Warnings, error)
}

type DeletePrivateDomainCommand struct {
	RequiredArgs    flag.Domain `positional-args:"yes"`
	Force           bool        `short:"f" description:"Force deletion without confirmation"`
	usage           interface{} `usage:"CF_NAME delete-private-domain DOMAIN [-f]"`
	relatedCommands interface{} `related_commands:"delete-shared-domain, domains, unshare-private-domain"`

	UI          command.UI
	Config      command.Config
	SharedActor command.SharedActor
	Actor       DeletePrivateDomainActor
}

func (cmd *DeletePrivateDomainCommand) Setup(config command.Config, ui command.UI) error {
	cmd.UI = ui
	cmd.Config = config
	cmd.SharedActor = sharedaction.NewActor(config)

	ccClient, _, err := shared.GetNewClientsAndConnectToCF(config, ui, "")
	if err != nil {
		return err
	}
	cmd.Actor = v7action.NewActor(ccClient, config, nil, nil, clock.NewClock())

	return nil
}

func (cmd DeletePrivateDomainCommand) Execute(args []string) error {
	domainName := cmd.RequiredArgs.Domain
	err := cmd.SharedActor.CheckTarget(true, false)
	if err != nil {
		return err
	}

	currentUser, err := cmd.Config.CurrentUser()
	if err != nil {
		return err
	}

	domain, warnings, err := cmd.Actor.GetDomainByName(domainName)
	cmd.UI.DisplayWarningsV7(warnings)

	cmd.UI.DisplayTextWithFlavor("Deleting private domain {{.DomainName}} as {{.Username}}...", map[string]interface{}{
		"DomainName": domainName,
		"Username":   currentUser.Name,
	})

	if err != nil {
		if _, ok := err.(actionerror.DomainNotFoundError); ok {
			cmd.UI.DisplayTextWithFlavor("Deleting private domain {{.DomainName}} as {{.Username}}...", map[string]interface{}{
				"DomainName": domainName,
				"Username":   currentUser.Name,
			})
			cmd.UI.DisplayWarningV7("Domain '{{.DomainName}}' does not exist.", map[string]interface{}{
				"DomainName": cmd.RequiredArgs.Domain,
			})
			cmd.UI.DisplayOK()
			return nil
		}
		return err
	}

	if domain.Shared() {
		return fmt.Errorf("Domain '%s' is a shared domain, not a private domain.", domainName)
	}

	cmd.UI.DisplayText("Deleting the private domain will remove associated routes which will make apps with this domain unreachable.")

	if !cmd.Force {
		response, promptErr := cmd.UI.DisplayBoolPrompt(false, "Really delete the private domain {{.DomainName}}?", map[string]interface{}{
			"DomainName": domainName,
		})

		if promptErr != nil {
			return promptErr
		}

		if !response {
			cmd.UI.DisplayText("'{{.DomainName}}' has not been deleted.", map[string]interface{}{
				"DomainName": domainName,
			})
			return nil
		}
	}
	cmd.UI.DisplayTextWithFlavor("Deleting private domain {{.DomainName}} as {{.Username}}...", map[string]interface{}{
		"DomainName": domainName,
		"Username":   currentUser.Name,
	})

	warnings, err = cmd.Actor.DeleteDomain(domain)
	cmd.UI.DisplayWarningsV7(warnings)

	if err != nil {
		return err
	}

	cmd.UI.DisplayOK()

	cmd.UI.DisplayText("TIP: Run 'cf domains' to view available domains.")

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"os/exec"
	"syscall"
)

func getLogFileSocketPair() (*os.File, int) {
	fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
	if err != nil {
		panic(err)
	}

	localFd := fds[0]
	remoteFd := fds[1]

	localLogFile := os.NewFile(uintptr(localFd), "")
	return localLogFile, remoteFd
}

func sendFD(conn *net.UnixConn, remoteAddr *net.UnixAddr, source string, fd int) error {
	oobs := syscall.UnixRights(fd)
	_, _, err := conn.WriteMsgUnix([]byte(source), oobs, remoteAddr)
	return err
}

func main() {
	var err error
	var ok bool

	var serverSocket string
	var name string

	flag.StringVar(&serverSocket, "socket", "/var/run/linuxkit-external-logging.sock", "socket to pass fd's to memlogd")
	flag.StringVar(&name, "n", "", "name of sender, defaults to first argument if left blank")
	flag.Parse()
	args := flag.Args()

	if len(args) < 1 {
		log.Fatal("no command specified")
	}

	if name == "" {
		name = args[0]
	}

	localStdoutLog, remoteStdoutFd := getLogFileSocketPair()
	localStderrLog, remoteStderrFd := getLogFileSocketPair()

	var outSocket int
	if outSocket, err = syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0); err != nil {
		log.Fatal("Unable to create socket: ", err)
	}

	var outFile net.Conn
	if outFile, err = net.FileConn(os.NewFile(uintptr(outSocket), "")); err != nil {
		log.Fatal(err)
	}

	var conn *net.UnixConn
	if conn, ok = outFile.(*net.UnixConn); !ok {
		log.Fatal("Internal error, invalid cast.")
	}

	raddr := net.UnixAddr{Name: serverSocket, Net: "unixgram"}

	if err = sendFD(conn, &raddr, name+".stdout", remoteStdoutFd); err != nil {
		log.Fatal("fd stdout send failed: ", err)
	}

	if err = sendFD(conn, &raddr, name+".stderr", remoteStderrFd); err != nil {
		log.Fatal("fd stderr send failed: ", err)
	}

	cmd := exec.Command(args[0], args[1:]...)
	outStderr := io.MultiWriter(localStderrLog, os.Stderr)
	outStdout := io.MultiWriter(localStdoutLog, os.Stdout)
	cmd.Stderr = outStderr
	cmd.Stdout = outStdout
	if err = cmd.Run(); err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			// exit with exit code from process
			status := exitError.Sys().(syscall.WaitStatus)
			os.Exit(status.ExitStatus())
		} else {
			// no exit code, report error and exit 1
			fmt.Println(err)
			os.Exit(1)
		}
	}
}
<commit_msg>memlogd/logwrite: use the same naming convention as init<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"os/exec"
	"syscall"
)

func getLogFileSocketPair() (*os.File, int) {
	fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
	if err != nil {
		panic(err)
	}

	localFd := fds[0]
	remoteFd := fds[1]

	localLogFile := os.NewFile(uintptr(localFd), "")
	return localLogFile, remoteFd
}

func sendFD(conn *net.UnixConn, remoteAddr *net.UnixAddr, source string, fd int) error {
	oobs := syscall.UnixRights(fd)
	_, _, err := conn.WriteMsgUnix([]byte(source), oobs, remoteAddr)
	return err
}

func main() {
	var err error
	var ok bool

	var serverSocket string
	var name string

	flag.StringVar(&serverSocket, "socket", "/var/run/linuxkit-external-logging.sock", "socket to pass fd's to memlogd")
	flag.StringVar(&name, "n", "", "name of sender, defaults to first argument if left blank")
	flag.Parse()
	args := flag.Args()

	if len(args) < 1 {
		log.Fatal("no command specified")
	}

	if name == "" {
		name = args[0]
	}

	localStdoutLog, remoteStdoutFd := getLogFileSocketPair()
	localStderrLog, remoteStderrFd := getLogFileSocketPair()

	var outSocket int
	if outSocket, err = syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0); err != nil {
		log.Fatal("Unable to create socket: ", err)
	}

	var outFile net.Conn
	if outFile, err = net.FileConn(os.NewFile(uintptr(outSocket), "")); err != nil {
		log.Fatal(err)
	}

	var conn *net.UnixConn
	if conn, ok = outFile.(*net.UnixConn); !ok {
		log.Fatal("Internal error, invalid cast.")
	}

	raddr := net.UnixAddr{Name: serverSocket, Net: "unixgram"}

	if err = sendFD(conn, &raddr, name+".out", remoteStdoutFd); err != nil {
		log.Fatal("fd stdout send failed: ", err)
	}

	if err = sendFD(conn, &raddr, name, remoteStderrFd); err != nil {
		log.Fatal("fd stderr send failed: ", err)
	}

	cmd := exec.Command(args[0], args[1:]...)
	outStderr := io.MultiWriter(localStderrLog, os.Stderr)
	outStdout := io.MultiWriter(localStdoutLog, os.Stdout)
	cmd.Stderr = outStderr
	cmd.Stdout = outStdout
	if err = cmd.Run(); err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			// exit with exit code from process
			status := exitError.Sys().(syscall.WaitStatus)
			os.Exit(status.ExitStatus())
		} else {
			// no exit code, report error and exit 1
			fmt.Println(err)
			os.Exit(1)
		}
	}
}
<|endoftext|>


<commit_before>package retryutil

import (
	"fmt"
	"time"
)

type RetryError struct {
	n int
}

func (e *RetryError) Error() string {
	return fmt.Sprintf("still failing after %d retries", e.n)
}

func IsRetryFailure(err error) bool {
	_, ok := err.(*RetryError)
	return ok
}

type ConditionFunc func() (bool, error)

// Retry retries f every interval until after maxRetries.
// The interval won't be affected by how long f takes.
// For example, if interval is 3s, f takes 1s, another f will be called 2s later.
// However, if f takes longer than interval, it will be delayed.
func Retry(interval time.Duration, maxRetries int, f ConditionFunc) error {
	if maxRetries <= 0 {
		return fmt.Errorf("maxRetries (%d) should be > 0", maxRetries)
	}
	tick := time.NewTicker(interval)
	defer tick.Stop()

	for i := 0; ; i++ {
		ok, err := f()
		if err != nil {
			return err
		}
		if ok {
			return nil
		}
		if i+1 == maxRetries {
			break
		}
		<-tick.C
	}
	return &RetryError{maxRetries}
}
<commit_msg>retry: fix assumption<commit_after>package retryutil

import (
	"fmt"
	"time"
)

type RetryError struct {
	n int
}

func (e *RetryError) Error() string {
	return fmt.Sprintf("still failing after %d retries", e.n)
}

func IsRetryFailure(err error) bool {
	_, ok := err.(*RetryError)
	return ok
}

type ConditionFunc func() (bool, error)

// Retry retries f every interval until after maxRetries.
// The interval won't be affected by how long f takes.
// For example, if interval is 3s, f takes 1s, another f will be called 2s later.
// However, if f takes longer than interval, it will be delayed.
func Retry(interval time.Duration, maxRetries int, f ConditionFunc) error {
	if maxRetries <= 0 {
		return fmt.Errorf("maxRetries (%d) should be > 0", maxRetries)
	}
	tick := time.NewTicker(interval)
	defer tick.Stop()

	for i := 0; ; i++ {
		ok, err := f()
		if err != nil {
			return err
		}
		if ok {
			return nil
		}
		if i == maxRetries {
			break
		}
		<-tick.C
	}
	return &RetryError{maxRetries}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Prometheus 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 collector

import (
	"os"
	"testing"
)

func TestBuddyInfo(t *testing.T) {
	file, err := os.Open("fixtures/proc/buddyinfo")
	if err != nil {
		t.Fatal(err)
	}
	defer file.Close()

	buddyInfo, err := parseBuddyInfo(file)
	if err != nil {
		t.Fatal(err)
	}

	if want, got := 4381.0, buddyInfo["0"]["Normal"][0]; want != got {
		t.Errorf("want Node 0, Zone Normal %f, got %f", want, got)
	}

	if want, got := 572.0, buddyInfo["0"]["DMA32"][1]; want != got {
		t.Errorf("want Node 0, Zone DMA32 %f, got %f", want, got)
	}
}
<commit_msg>Moving buddyinfo_test.go to procfs library<commit_after><|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.

// [START functions_http_form_data]

// Package http provides a set of HTTP Cloud Functions samples.
package http

import (
	"fmt"
	"log"
	"net/http"
)

// UploadFile processes a 'multipart/form-data' upload request.
func UploadFile(w http.ResponseWriter, r *http.Request) {
	const maxMemory = 2 * 1024 * 1024 // 2 megabytes.

	// ParseMultipartForm parses a request body as multipart/form-data.
	// The whole request body is parsed and up to a total of maxMemory bytes of
	// its file parts are stored in memory, with the remainder stored on
	// disk in temporary files.
	if err := r.ParseMultipartForm(maxMemory); err != nil {
		http.Error(w, "Unable to parse form", http.StatusBadRequest)
		log.Printf("Error parsing form: %v", err)
		return
	}

	// Be sure to remove all temporary files after your function is finished.
	defer func() {
		if err := r.MultipartForm.RemoveAll(); err != nil {
			http.Error(w, "Error cleaning up form files", http.StatusInternalServerError)
			log.Printf("Error cleaning up form files: %v", err)
		}
	}()

	// r.MultipartForm.File contains *multipart.FileHeader values for every
	// file in the form. You can access the file contents using
	// *multipart.FileHeader's Open method.
	for _, headers := range r.MultipartForm.File {
		for _, h := range headers {
			fmt.Fprintf(w, "File uploaded: %q (%v bytes)", h.Filename, h.Size)
			// Use h.Open() to read the contents of the file.
		}
	}

}

// [END functions_http_form_data]
<commit_msg>functions: add "filesystem is not persistent" note (#1359)<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.

// [START functions_http_form_data]

// Package http provides a set of HTTP Cloud Functions samples.
package http

import (
	"fmt"
	"log"
	"net/http"
)

// UploadFile processes a 'multipart/form-data' upload request.
func UploadFile(w http.ResponseWriter, r *http.Request) {
	const maxMemory = 2 * 1024 * 1024 // 2 megabytes.

	// ParseMultipartForm parses a request body as multipart/form-data.
	// The whole request body is parsed and up to a total of maxMemory bytes of
	// its file parts are stored in memory, with the remainder stored on
	// disk in temporary files.

	// Note that any files saved during a particular invocation may not
	// persist after the current invocation completes; persistent files
	// should be stored elsewhere, such as in a Cloud Storage bucket.
	if err := r.ParseMultipartForm(maxMemory); err != nil {
		http.Error(w, "Unable to parse form", http.StatusBadRequest)
		log.Printf("Error parsing form: %v", err)
		return
	}

	// Be sure to remove all temporary files after your function is finished.
	defer func() {
		if err := r.MultipartForm.RemoveAll(); err != nil {
			http.Error(w, "Error cleaning up form files", http.StatusInternalServerError)
			log.Printf("Error cleaning up form files: %v", err)
		}
	}()

	// r.MultipartForm.File contains *multipart.FileHeader values for every
	// file in the form. You can access the file contents using
	// *multipart.FileHeader's Open method.
	for _, headers := range r.MultipartForm.File {
		for _, h := range headers {
			fmt.Fprintf(w, "File uploaded: %q (%v bytes)", h.Filename, h.Size)
			// Use h.Open() to read the contents of the file.
		}
	}

}

// [END functions_http_form_data]
<|endoftext|>


<commit_before>//
// version.go -- contains srnd version strings
//

package srnd

import "fmt"

const major_version = 3
const minor_version = 0
const patch_verson = 0
const program_name = "srnd"

var GitVersion string

func Version() string {
	return fmt.Sprintf("%s-%d.%d.%d%s", program_name, major_version, minor_version, patch_verson, GitVersion)
}
<commit_msg>bump version<commit_after>//
// version.go -- contains srnd version strings
//

package srnd

import "fmt"

const major_version = 3
const minor_version = 1
const patch_verson = 0
const program_name = "srnd"

var GitVersion string

func Version() string {
	return fmt.Sprintf("%s-%d.%d.%d%s", program_name, major_version, minor_version, patch_verson, GitVersion)
}
<|endoftext|>


<commit_before>package generator

import (
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"go/types"
	"os"
	"path/filepath"
	"reflect"
	"strings"

	"github.com/src-d/proteus/source"
)

// BaseModel is the type name of the kallax base model.
const BaseModel = "github.com/src-d/go-kallax.Model"

// Processor is in charge of processing the package in a patch and
// scan models from it.
type Processor struct {
	// Path of the package.
	Path string
	// Ignore is the list of files to ignore when scanning.
	Ignore map[string]struct{}
	// Package is the scanned package.
	Package *types.Package
}

// NewProcessor creates a new Processor for the given path and ignored files.
func NewProcessor(path string, ignore []string) *Processor {
	i := make(map[string]struct{})
	for _, file := range ignore {
		i[file] = struct{}{}
	}

	return &Processor{
		Path:   path,
		Ignore: i,
	}
}

// Do performs all the processing and returns the scanned package.
func (p *Processor) Do() (*Package, error) {
	files, err := p.getSourceFiles()
	if err != nil {
		return nil, err
	}

	p.Package, err = p.parseSourceFiles(files)
	if err != nil {
		return nil, err
	}

	return p.processPackage()
}

func (p *Processor) getSourceFiles() ([]string, error) {
	pkg, err := build.Default.ImportDir(p.Path, 0)
	if err != nil {
		return nil, fmt.Errorf("cannot process directory %s: %s", p.Path, err)
	}

	var files []string
	files = append(files, pkg.GoFiles...)
	files = append(files, pkg.CgoFiles...)

	if len(files) == 0 {
		return nil, fmt.Errorf("%s: no buildable Go files", p.Path)
	}

	return joinDirectory(p.Path, p.removeIgnoredFiles(files)), nil
}

func (p *Processor) removeIgnoredFiles(filenames []string) []string {
	var output []string
	for _, filename := range filenames {
		if _, ok := p.Ignore[filename]; ok {
			continue
		}

		output = append(output, filename)
	}

	return output
}

func (p *Processor) parseSourceFiles(filenames []string) (*types.Package, error) {
	var files []*ast.File
	fs := token.NewFileSet()
	for _, filename := range filenames {
		file, err := parser.ParseFile(fs, filename, nil, 0)
		if err != nil {
			return nil, fmt.Errorf("parsing package: %s: %s", filename, err)
		}

		files = append(files, file)
	}

	config := types.Config{
		FakeImportC: true,
		Error:       func(error) {},
		Importer:    source.NewImporter(),
	}

	return config.Check(p.Path, fs, files, new(types.Info))
}

func (p *Processor) processPackage() (*Package, error) {
	pkg := &Package{pkg: p.Package, Name: p.Package.Name()}
	var ctors []*types.Func

	fmt.Println("Package: ", pkg.Name)

	s := p.Package.Scope()
	for _, name := range s.Names() {
		obj := s.Lookup(name)
		switch t := obj.Type().(type) {
		case *types.Signature:
			if strings.HasPrefix(name, "new") {
				ctors = append(ctors, obj.(*types.Func))
			}
		case *types.Named:
			if str, ok := t.Underlying().(*types.Struct); ok {
				if m := p.processModel(name, str, t); m != nil {
					fmt.Printf("Found: %s\n", m)
					if err := m.Validate(); err != nil {
						return nil, err
					}

					pkg.Models = append(pkg.Models, m)
					m.Node = t
					m.Package = p.Package
				}
			}
		}
	}

	for _, ctor := range ctors {
		p.tryMatchConstructor(pkg.Models, ctor)
	}

	return pkg, nil
}

func (p *Processor) tryMatchConstructor(models []*Model, fun *types.Func) {
	for _, m := range models {
		if fun.Name() != fmt.Sprintf("new%s", m.Name) {
			continue
		}

		sig := fun.Type().(*types.Signature)
		if sig.Recv() != nil {
			continue
		}

		res := sig.Results()
		if res.Len() > 0 {
			for i := 0; i < res.Len(); i++ {
				if isTypeOrPtrTo(res.At(i).Type(), m.Node) {
					m.CtorFunc = fun
					return
				}
			}
		}
		return
	}
}

func (p *Processor) processModel(name string, s *types.Struct, t *types.Named) *Model {
	m := NewModel(name)
	m.Events = p.findEvents(t)

	var base int
	if base, m.Fields = p.processFields(s, nil, true); base == -1 {
		return nil
	}

	p.processBaseField(m, m.Fields[base])
	return m
}

func (p *Processor) findEvents(node *types.Named) []Event {
	var events []Event
	all := []Event{
		BeforeInsert, AfterInsert, BeforeUpdate, AfterUpdate, BeforeSave, AfterSave,
	}

	for _, e := range all {
		if p.isEventPresent(node, e) {
			events = append(events, e)
		}
	}

	return events
}

// isEventPresent checks the given Event is implemented for the given node.
func (p *Processor) isEventPresent(node *types.Named, e Event) bool {
	signature := p.getMethodSignature(types.NewPointer(node), string(e))
	return signatureMatches(signature, nil, typeCheckers{isBuiltinError})
}

// processFields returns which field index is an embedded kallax.Model, or -1 if none.
func (p *Processor) processFields(s *types.Struct, done []*types.Struct, root bool) (base int, fields []*Field) {
	base = -1

	for i := 0; i < s.NumFields(); i++ {
		f := s.Field(i)
		if !f.Exported() {
			continue
		}

		field := NewField(
			f.Name(),
			typeName(f.Type().Underlying()),
			reflect.StructTag(s.Tag(i)),
		)
		field.Node = f
		if typeName(f.Type()) == BaseModel {
			base = i
			field.Type = BaseModel
		}

		p.processField(field, f.Type(), done, root)
		fields = append(fields, field)
	}

	return base, fields
}

// processField processes recursively the field. During the processing several
// field properties might be modified, such as the properties that report if
// the type has to be serialized to json, if it's an alias or if it's a pointer
// and so on. Also, the kind of the field is set here.
// If root is true, models are established as relationships. If not, they are
// just treated as structs.
// The following types are always set as JSON:
//  - Map
//  - Slice or Array with non-basic underlying type
//  - Interface
//  - Struct that is not a model or is not at root level
func (p *Processor) processField(field *Field, typ types.Type, done []*types.Struct, root bool) {
	switch typ := typ.(type) {
	case *types.Basic:
		field.Type = typ.String()
		field.Kind = Basic
	case *types.Pointer:
		field.IsPtr = true
		p.processField(field, typ.Elem(), done, root)
	case *types.Named:
		if field.Type == BaseModel {
			p.processField(field, typ.Underlying(), done, root)
			return
		}

		if isModel(typ, true) && root {
			field.Kind = Relationship
			field.Type = typ.String()
			return
		}

		if p.isSQLType(types.NewPointer(typ)) {
			field.Kind = Interface
			return
		}

		if t, ok := specialTypes[typeName(typ)]; ok {
			field.Type = t
			return
		}

		p.processField(field, typ.Underlying(), done, root)
		field.IsAlias = !field.IsJSON
	case *types.Array:
		var underlying Field
		p.processField(&underlying, typ.Elem(), done, root)
		if underlying.Kind == Relationship {
			field.Kind = Relationship
			return
		}

		if underlying.Kind != Basic {
			field.IsJSON = true
		}
		field.Kind = Array
		field.Fields = underlying.Fields
	case *types.Slice:
		var underlying Field
		p.processField(&underlying, typ.Elem(), done, root)
		if underlying.Kind == Relationship {
			field.Kind = Relationship
			return
		}

		if underlying.Kind != Basic {
			field.IsJSON = true
		}
		field.Kind = Slice
		field.Fields = underlying.Fields
	case *types.Map:
		field.Kind = Map
		field.IsJSON = true
	case *types.Interface:
		field.Kind = Interface
		field.IsJSON = true
	case *types.Struct:
		field.Kind = Struct
		field.IsJSON = true

		d := false
		for _, v := range done {
			if v == typ {
				d = true
				break
			}
		}

		if !d {
			_, subfs := p.processFields(typ, append(done, typ), false)
			field.SetFields(subfs)
		}
	default:
		fmt.Printf("Ignored field %s of type %s\n", field.Name, field.Type)
	}
}

func (p *Processor) isSQLType(typ types.Type) bool {
	scan := p.getMethodSignature(typ, "Scan")
	if !signatureMatches(scan, typeCheckers{isEmptyInterface}, typeCheckers{isBuiltinError}) {
		return false
	}

	value := p.getMethodSignature(typ, "Value")
	if !signatureMatches(value, nil, typeCheckers{isDriverValue, isBuiltinError}) {
		return false
	}

	return true
}

func signatureMatches(s *types.Signature, params typeCheckers, results typeCheckers) bool {
	return s != nil &&
		s.Params().Len() == len(params) &&
		s.Results().Len() == len(results) &&
		params.check(s.Params()) &&
		results.check(s.Results())
}

type typeCheckers []typeChecker

func (c typeCheckers) check(tuple *types.Tuple) bool {
	for i, checker := range c {
		if !checker(tuple.At(i).Type()) {
			return false
		}
	}
	return true
}

type typeChecker func(types.Type) bool

func (p *Processor) getMethodSignature(typ types.Type, name string) *types.Signature {
	ms := types.NewMethodSet(typ)
	method := ms.Lookup(p.Package, name)
	if method == nil {
		return nil
	}

	return method.Obj().(*types.Func).Type().(*types.Signature)
}

func isEmptyInterface(typ types.Type) bool {
	switch typ := typ.(type) {
	case *types.Interface:
		return typ.NumMethods() == 0
	}
	return false
}

func isDriverValue(typ types.Type) bool {
	switch typ := typ.(type) {
	case *types.Named:
		return typ.String() == "database/sql/driver.Value"
	}
	return false
}

// isModel checks if the type is a model. If dive is true, it will check also
// the types of the struct if the type is a struct.
func isModel(typ types.Type, dive bool) bool {
	switch typ := typ.(type) {
	case *types.Named:
		if typeName(typ) == BaseModel {
			return true
		}
		return isModel(typ.Underlying(), true && dive)
	case *types.Pointer:
		return isModel(typ.Elem(), true && dive)
	case *types.Struct:
		if !dive {
			return false
		}

		for i := 0; i < typ.NumFields(); i++ {
			if isModel(typ.Field(i).Type(), false) {
				return true
			}
		}
	}
	return false
}

func (p *Processor) processBaseField(m *Model, f *Field) {
	m.Table = f.Tag.Get("table")
	if m.Table == "" {
		m.Table = toLowerSnakeCase(m.Name)
	}
}

func joinDirectory(directory string, files []string) []string {
	result := make([]string, len(files))
	for i, file := range files {
		result[i] = filepath.Join(directory, file)
	}

	return result
}

var goPath = os.Getenv("GOPATH")

func typeName(typ types.Type) string {
	return strings.Replace(typ.String(), goPath+"/src/", "", -1)
}
<commit_msg>Remove proteus as a dependency and set go-parse-utils<commit_after>package generator

import (
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"go/types"
	"os"
	"path/filepath"
	"reflect"
	"strings"

	parseutil "srcd.works/go-parse-utils.v1"
)

// BaseModel is the type name of the kallax base model.
const BaseModel = "github.com/src-d/go-kallax.Model"

// Processor is in charge of processing the package in a patch and
// scan models from it.
type Processor struct {
	// Path of the package.
	Path string
	// Ignore is the list of files to ignore when scanning.
	Ignore map[string]struct{}
	// Package is the scanned package.
	Package *types.Package
}

// NewProcessor creates a new Processor for the given path and ignored files.
func NewProcessor(path string, ignore []string) *Processor {
	i := make(map[string]struct{})
	for _, file := range ignore {
		i[file] = struct{}{}
	}

	return &Processor{
		Path:   path,
		Ignore: i,
	}
}

// Do performs all the processing and returns the scanned package.
func (p *Processor) Do() (*Package, error) {
	files, err := p.getSourceFiles()
	if err != nil {
		return nil, err
	}

	p.Package, err = p.parseSourceFiles(files)
	if err != nil {
		return nil, err
	}

	return p.processPackage()
}

func (p *Processor) getSourceFiles() ([]string, error) {
	pkg, err := build.Default.ImportDir(p.Path, 0)
	if err != nil {
		return nil, fmt.Errorf("cannot process directory %s: %s", p.Path, err)
	}

	var files []string
	files = append(files, pkg.GoFiles...)
	files = append(files, pkg.CgoFiles...)

	if len(files) == 0 {
		return nil, fmt.Errorf("%s: no buildable Go files", p.Path)
	}

	return joinDirectory(p.Path, p.removeIgnoredFiles(files)), nil
}

func (p *Processor) removeIgnoredFiles(filenames []string) []string {
	var output []string
	for _, filename := range filenames {
		if _, ok := p.Ignore[filename]; ok {
			continue
		}

		output = append(output, filename)
	}

	return output
}

func (p *Processor) parseSourceFiles(filenames []string) (*types.Package, error) {
	var files []*ast.File
	fs := token.NewFileSet()
	for _, filename := range filenames {
		file, err := parser.ParseFile(fs, filename, nil, 0)
		if err != nil {
			return nil, fmt.Errorf("parsing package: %s: %s", filename, err)
		}

		files = append(files, file)
	}

	config := types.Config{
		FakeImportC: true,
		Error:       func(error) {},
		Importer:    parseutil.NewImporter(),
	}

	return config.Check(p.Path, fs, files, new(types.Info))
}

func (p *Processor) processPackage() (*Package, error) {
	pkg := &Package{pkg: p.Package, Name: p.Package.Name()}
	var ctors []*types.Func

	fmt.Println("Package: ", pkg.Name)

	s := p.Package.Scope()
	for _, name := range s.Names() {
		obj := s.Lookup(name)
		switch t := obj.Type().(type) {
		case *types.Signature:
			if strings.HasPrefix(name, "new") {
				ctors = append(ctors, obj.(*types.Func))
			}
		case *types.Named:
			if str, ok := t.Underlying().(*types.Struct); ok {
				if m := p.processModel(name, str, t); m != nil {
					fmt.Printf("Found: %s\n", m)
					if err := m.Validate(); err != nil {
						return nil, err
					}

					pkg.Models = append(pkg.Models, m)
					m.Node = t
					m.Package = p.Package
				}
			}
		}
	}

	for _, ctor := range ctors {
		p.tryMatchConstructor(pkg.Models, ctor)
	}

	return pkg, nil
}

func (p *Processor) tryMatchConstructor(models []*Model, fun *types.Func) {
	for _, m := range models {
		if fun.Name() != fmt.Sprintf("new%s", m.Name) {
			continue
		}

		sig := fun.Type().(*types.Signature)
		if sig.Recv() != nil {
			continue
		}

		res := sig.Results()
		if res.Len() > 0 {
			for i := 0; i < res.Len(); i++ {
				if isTypeOrPtrTo(res.At(i).Type(), m.Node) {
					m.CtorFunc = fun
					return
				}
			}
		}
		return
	}
}

func (p *Processor) processModel(name string, s *types.Struct, t *types.Named) *Model {
	m := NewModel(name)
	m.Events = p.findEvents(t)

	var base int
	if base, m.Fields = p.processFields(s, nil, true); base == -1 {
		return nil
	}

	p.processBaseField(m, m.Fields[base])
	return m
}

func (p *Processor) findEvents(node *types.Named) []Event {
	var events []Event
	all := []Event{
		BeforeInsert, AfterInsert, BeforeUpdate, AfterUpdate, BeforeSave, AfterSave,
	}

	for _, e := range all {
		if p.isEventPresent(node, e) {
			events = append(events, e)
		}
	}

	return events
}

// isEventPresent checks the given Event is implemented for the given node.
func (p *Processor) isEventPresent(node *types.Named, e Event) bool {
	signature := p.getMethodSignature(types.NewPointer(node), string(e))
	return signatureMatches(signature, nil, typeCheckers{isBuiltinError})
}

// processFields returns which field index is an embedded kallax.Model, or -1 if none.
func (p *Processor) processFields(s *types.Struct, done []*types.Struct, root bool) (base int, fields []*Field) {
	base = -1

	for i := 0; i < s.NumFields(); i++ {
		f := s.Field(i)
		if !f.Exported() {
			continue
		}

		field := NewField(
			f.Name(),
			typeName(f.Type().Underlying()),
			reflect.StructTag(s.Tag(i)),
		)
		field.Node = f
		if typeName(f.Type()) == BaseModel {
			base = i
			field.Type = BaseModel
		}

		p.processField(field, f.Type(), done, root)
		fields = append(fields, field)
	}

	return base, fields
}

// processField processes recursively the field. During the processing several
// field properties might be modified, such as the properties that report if
// the type has to be serialized to json, if it's an alias or if it's a pointer
// and so on. Also, the kind of the field is set here.
// If root is true, models are established as relationships. If not, they are
// just treated as structs.
// The following types are always set as JSON:
//  - Map
//  - Slice or Array with non-basic underlying type
//  - Interface
//  - Struct that is not a model or is not at root level
func (p *Processor) processField(field *Field, typ types.Type, done []*types.Struct, root bool) {
	switch typ := typ.(type) {
	case *types.Basic:
		field.Type = typ.String()
		field.Kind = Basic
	case *types.Pointer:
		field.IsPtr = true
		p.processField(field, typ.Elem(), done, root)
	case *types.Named:
		if field.Type == BaseModel {
			p.processField(field, typ.Underlying(), done, root)
			return
		}

		if isModel(typ, true) && root {
			field.Kind = Relationship
			field.Type = typ.String()
			return
		}

		if p.isSQLType(types.NewPointer(typ)) {
			field.Kind = Interface
			return
		}

		if t, ok := specialTypes[typeName(typ)]; ok {
			field.Type = t
			return
		}

		p.processField(field, typ.Underlying(), done, root)
		field.IsAlias = !field.IsJSON
	case *types.Array:
		var underlying Field
		p.processField(&underlying, typ.Elem(), done, root)
		if underlying.Kind == Relationship {
			field.Kind = Relationship
			return
		}

		if underlying.Kind != Basic {
			field.IsJSON = true
		}
		field.Kind = Array
		field.Fields = underlying.Fields
	case *types.Slice:
		var underlying Field
		p.processField(&underlying, typ.Elem(), done, root)
		if underlying.Kind == Relationship {
			field.Kind = Relationship
			return
		}

		if underlying.Kind != Basic {
			field.IsJSON = true
		}
		field.Kind = Slice
		field.Fields = underlying.Fields
	case *types.Map:
		field.Kind = Map
		field.IsJSON = true
	case *types.Interface:
		field.Kind = Interface
		field.IsJSON = true
	case *types.Struct:
		field.Kind = Struct
		field.IsJSON = true

		d := false
		for _, v := range done {
			if v == typ {
				d = true
				break
			}
		}

		if !d {
			_, subfs := p.processFields(typ, append(done, typ), false)
			field.SetFields(subfs)
		}
	default:
		fmt.Printf("Ignored field %s of type %s\n", field.Name, field.Type)
	}
}

func (p *Processor) isSQLType(typ types.Type) bool {
	scan := p.getMethodSignature(typ, "Scan")
	if !signatureMatches(scan, typeCheckers{isEmptyInterface}, typeCheckers{isBuiltinError}) {
		return false
	}

	value := p.getMethodSignature(typ, "Value")
	if !signatureMatches(value, nil, typeCheckers{isDriverValue, isBuiltinError}) {
		return false
	}

	return true
}

func signatureMatches(s *types.Signature, params typeCheckers, results typeCheckers) bool {
	return s != nil &&
		s.Params().Len() == len(params) &&
		s.Results().Len() == len(results) &&
		params.check(s.Params()) &&
		results.check(s.Results())
}

type typeCheckers []typeChecker

func (c typeCheckers) check(tuple *types.Tuple) bool {
	for i, checker := range c {
		if !checker(tuple.At(i).Type()) {
			return false
		}
	}
	return true
}

type typeChecker func(types.Type) bool

func (p *Processor) getMethodSignature(typ types.Type, name string) *types.Signature {
	ms := types.NewMethodSet(typ)
	method := ms.Lookup(p.Package, name)
	if method == nil {
		return nil
	}

	return method.Obj().(*types.Func).Type().(*types.Signature)
}

func isEmptyInterface(typ types.Type) bool {
	switch typ := typ.(type) {
	case *types.Interface:
		return typ.NumMethods() == 0
	}
	return false
}

func isDriverValue(typ types.Type) bool {
	switch typ := typ.(type) {
	case *types.Named:
		return typ.String() == "database/sql/driver.Value"
	}
	return false
}

// isModel checks if the type is a model. If dive is true, it will check also
// the types of the struct if the type is a struct.
func isModel(typ types.Type, dive bool) bool {
	switch typ := typ.(type) {
	case *types.Named:
		if typeName(typ) == BaseModel {
			return true
		}
		return isModel(typ.Underlying(), true && dive)
	case *types.Pointer:
		return isModel(typ.Elem(), true && dive)
	case *types.Struct:
		if !dive {
			return false
		}

		for i := 0; i < typ.NumFields(); i++ {
			if isModel(typ.Field(i).Type(), false) {
				return true
			}
		}
	}
	return false
}

func (p *Processor) processBaseField(m *Model, f *Field) {
	m.Table = f.Tag.Get("table")
	if m.Table == "" {
		m.Table = toLowerSnakeCase(m.Name)
	}
}

func joinDirectory(directory string, files []string) []string {
	result := make([]string, len(files))
	for i, file := range files {
		result[i] = filepath.Join(directory, file)
	}

	return result
}

var goPath = os.Getenv("GOPATH")

func typeName(typ types.Type) string {
	return strings.Replace(typ.String(), goPath+"/src/", "", -1)
}
<|endoftext|>


<commit_before>package geofence_test

import (
	"bytes"
	"fmt"
	"os"
	"strings"
	"testing"

	"github.com/buckhx/diglet/geo"
	"github.com/buckhx/gofence/geofence"
)

var ues *geo.Feature
var s2f geofence.GeoFence
var tracts, result []*geo.Feature
var museums = map[string]geo.Coordinate{
	"guggenheim":      {40.7830, -73.9590},
	"met":             {40.7788, -73.9621},
	"moma":            {40.7615, -73.9777},
	"whitney":         {40.7396, -74.0089},
	"old whitney":     {40.7732, -73.9641},
	"natural history": {40.7806, -73.9747},
	"brooklyn":        {40.6713, -73.9638},
	"louvre":          {48.8611, 2.3364},
}

func TestFences(t *testing.T) {
	tests := []struct {
		museum   string
		contains bool
	}{
		{"guggenheim", true},
		{"met", true},
		{"old whitney", true},
		{"whitney", false},
		{"moma", false},
		{"natural history", false},
		{"brooklyn", false},
		{"louvre", false},
	}
	idx := geofence.NewFenceIndex()
	for _, fn := range geofence.FenceLabels {
		fence, err := geofence.GetFence(fn, 14)
		if err != nil {
			// City fences need NYC_BOROS_PATH and we don't always want to test them
			t.Logf("Skipping %q because - %s", fn, err)
			continue
		}
		idx.Set(fn, fence)
		fence.Add(ues)
		for _, test := range tests {
			// Search test
			c := museums[test.museum]
			if (len(fence.Get(c)) == 0) == test.contains {
				t.Errorf("Invalid search %q %q %s", fn, test.museum, c)
			}
			// Index test
			if matchs, err := idx.Search(fn, c); err != nil {
				t.Errorf("Error index search %q - $s", fn, err)
			} else if (len(matchs) == 0) == test.contains {
				t.Errorf("Invalid index search %q %q %s", fn, test.museum, c)
			}
			// Encoding test
			p := &geofence.PointMessage{
				Type:       "Feature",
				Properties: geofence.Properties{"name": []byte(test.museum)}, //TODO fix this
				Geometry:   geofence.PointGeometry{Type: "Point", Coordinates: []float64{c.Lon, c.Lat}},
			}
			b := bytes.NewBuffer(nil)
			err = geofence.WriteJson(b, p)
			if err != nil {
				t.Errorf("Error writing json %s", err)
			}
			res, err := geofence.GeojsonSearch(idx, fn, b.Bytes())
			if err != nil {
				t.Errorf("Error GeojsonSearch %s", err)
			}
			if (len(res.Fences) == 0) == test.contains {
				t.Errorf("Invalid GeojsonSearch %q %q %s", fn, test.museum, c)
			}
		}
	}
}

func BenchmarkBrute(b *testing.B) {
	fence := geofence.NewBruteFence()
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["met"])
	}
}

func BenchmarkCity(b *testing.B) {
	fence, err := geofence.NewCityFence()
	if err != nil {
		fmt.Printf("Skipping benchmark for 'CityFence' because %s", err)
		return
	}
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["met"])
	}
}

func BenchmarkBbox(b *testing.B) {
	fence := geofence.NewBboxFence()
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["met"])
	}
}

func BenchmarkCityBbox(b *testing.B) {
	fence, err := geofence.NewCityBboxFence()
	if err != nil {
		fmt.Printf("Skipping benchmark for 'CityBboxFence' because %s", err)
		return
	}
	if err != nil {
		return
	}
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["met"])
	}
}

func BenchmarkQfence(b *testing.B) {
	fence := geofence.NewQfence(14)
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["met"])
	}
}

func BenchmarkRfence(b *testing.B) {
	fence := geofence.NewRfence()
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["met"])
	}
}

func BenchmarkS2fence(b *testing.B) {
	for n := 0; n < b.N; n++ {
		result = s2f.Get(museums["old whitney"])
		if len(result) != 1 {
			panic(result)
		}
	}
}

func TestMain(m *testing.M) {
	for _, arg := range os.Args {
		// only load tracts if benching
		if strings.Contains(arg, "bench") {
			path := os.Getenv("NYC_TRACTS_PATH")
			if path == "" {
				panic("Missing NYC_TRACTS_PATH envvar")
			}
			features, err := loadGeojson(path)
			if err != nil {
				panic(err)
			}
			tracts = features
			fmt.Println("Loading s2fence...")
			s2f = geofence.NewS2fence(14)
			for _, tract := range tracts {
				//fmt.Printf("s2fence adding feature %d\n", i)
				s2f.Add(tract)
			}
			fmt.Println("Loaded s2fence!")
			break
		}
	}
	ues = getUpperEastSide()
	os.Exit(m.Run())
}

func loadGeojson(path string) (features []*geo.Feature, err error) {
	source, err := geo.NewGeojsonSource(path, nil).Publish()
	if err != nil {
		return
	}
	for feature := range source {
		features = append(features, feature)
	}
	return
}

func getUpperEastSide() (ues *geo.Feature) {
	shp := geo.NewShape()
	for _, p := range [][]float64{
		{-73.9493, 40.7852}, // w
		{-73.9665, 40.7615}, // s
		{-73.9730, 40.7642}, // e
		{-73.9557, 40.7879}, // n
		{-73.9493, 40.7852}, // w
	} {
		c := geo.Coordinate{p[1], p[0]} //swapped
		shp.Add(c)
	}
	ues = geo.NewPolygonFeature(shp)
	ues.Properties = map[string]interface{}{"BoroName": "Manhattan", "NTAName": "Upper East Side"} // for city
	return
}
<commit_msg>testing<commit_after>package geofence_test

import (
	"bytes"
	"fmt"
	"os"
	"strings"
	"testing"

	"github.com/buckhx/diglet/geo"
	"github.com/buckhx/gofence/geofence"
)

const (
	TEST_ZOOM = 14
)

var (
	ues            *geo.Feature
	s2f            geofence.GeoFence
	tracts, result []*geo.Feature
	museums        = map[string]geo.Coordinate{
		"guggenheim":      {40.7830, -73.9590},
		"met":             {40.7788, -73.9621},
		"moma":            {40.7615, -73.9777},
		"whitney":         {40.7396, -74.0089},
		"old whitney":     {40.7732, -73.9641},
		"natural history": {40.7806, -73.9747},
		"brooklyn":        {40.6713, -73.9638},
		"louvre":          {48.8611, 2.3364},
	}
)

func TestFences(t *testing.T) {
	tests := []struct {
		museum   string
		contains bool
	}{
		{"guggenheim", true},
		{"met", true},
		{"old whitney", true},
		{"whitney", false},
		{"moma", false},
		{"natural history", false},
		{"brooklyn", false},
		{"louvre", false},
	}
	idx := geofence.NewFenceIndex()
	for _, fn := range geofence.FenceLabels {
		fence, err := geofence.GetFence(fn, TEST_ZOOM)
		if err != nil {
			// City fences need NYC_BOROS_PATH and we don't always want to test them
			t.Logf("Skipping %q because - %s", fn, err)
			continue
		}
		idx.Set(fn, fence)
		fence.Add(ues)
		for _, test := range tests {
			// Search test
			c := museums[test.museum]
			if (len(fence.Get(c)) == 0) == test.contains {
				t.Errorf("Invalid search %q %q %s", fn, test.museum, c)
			}
			// Index test
			if matchs, err := idx.Search(fn, c); err != nil {
				t.Errorf("Error index search %q - $s", fn, err)
			} else if (len(matchs) == 0) == test.contains {
				t.Errorf("Invalid index search %q %q %s", fn, test.museum, c)
			}
			// Encoding test
			p := &geofence.PointMessage{
				Type:       "Feature",
				Properties: geofence.Properties{"name": []byte(test.museum)}, //TODO fix this
				Geometry:   geofence.PointGeometry{Type: "Point", Coordinates: []float64{c.Lon, c.Lat}},
			}
			b := bytes.NewBuffer(nil)
			err = geofence.WriteJson(b, p)
			if err != nil {
				t.Errorf("Error writing json %s", err)
			}
			res, err := geofence.GeojsonSearch(idx, fn, b.Bytes())
			if err != nil {
				t.Errorf("Error GeojsonSearch %s", err)
			}
			if (len(res.Fences) == 0) == test.contains {
				t.Errorf("Invalid GeojsonSearch %q %q %s", fn, test.museum, c)
			}
		}
	}
}

func BenchmarkBrute(b *testing.B) {
	fence := geofence.NewBruteFence()
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkCity(b *testing.B) {
	fence, err := geofence.NewCityFence()
	if err != nil {
		fmt.Printf("Skipping benchmark for 'CityFence' because %s", err)
		return
	}
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkBbox(b *testing.B) {
	fence := geofence.NewBboxFence()
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkCityBbox(b *testing.B) {
	fence, err := geofence.NewCityBboxFence()
	if err != nil {
		fmt.Printf("Skipping benchmark for 'CityBboxFence' because %s", err)
		return
	}
	if err != nil {
		return
	}
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkQfence(b *testing.B) {
	fence := geofence.NewQfence(TEST_ZOOM)
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkRfence(b *testing.B) {
	fence := geofence.NewRfence()
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkS2fence(b *testing.B) {
	for n := 0; n < b.N; n++ {
		// interior @ Z18
		result = s2f.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func TestMain(m *testing.M) {
	for _, arg := range os.Args {
		// only load tracts if benching
		if strings.Contains(arg, "bench") {
			path := os.Getenv("NYC_TRACTS_PATH")
			if path == "" {
				panic("Missing NYC_TRACTS_PATH envvar")
			}
			features, err := loadGeojson(path)
			if err != nil {
				panic(err)
			}
			tracts = features
			fmt.Println("Loading s2fence...")
			s2f = geofence.NewS2fence(TEST_ZOOM)
			for _, tract := range tracts {
				//fmt.Printf("s2fence adding feature %d\n", i)
				s2f.Add(tract)
			}
			fmt.Println("Loaded s2fence!")
			break
		}
	}
	ues = getUpperEastSide()
	os.Exit(m.Run())
}

func loadGeojson(path string) (features []*geo.Feature, err error) {
	source, err := geo.NewGeojsonSource(path, nil).Publish()
	if err != nil {
		return
	}
	for feature := range source {
		features = append(features, feature)
	}
	return
}

func getUpperEastSide() (ues *geo.Feature) {
	shp := geo.NewShape()
	for _, p := range [][]float64{
		{-73.9493, 40.7852}, // w
		{-73.9665, 40.7615}, // s
		{-73.9730, 40.7642}, // e
		{-73.9557, 40.7879}, // n
		{-73.9493, 40.7852}, // w
	} {
		c := geo.Coordinate{p[1], p[0]} //swapped
		shp.Add(c)
	}
	ues = geo.NewPolygonFeature(shp)
	ues.Properties = map[string]interface{}{"BoroName": "Manhattan", "NTAName": "Upper East Side"} // for city
	return
}
<|endoftext|>