<commit_before>package assertions

import (
	"fmt"
	"strconv"

	"ci.guzzler.io/guzzler/corcel/core"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

type ATC struct {
	Actual               interface{}
	Instance             interface{}
	ActualStringNumber   bool
	InstanceStringNumber bool
}

func NewATC(actual interface{}, instance interface{}) (newInstance ATC) {
	newInstance.Actual = actual
	newInstance.Instance = instance
	switch actualType := actual.(type) {
	case string:
		_, err := strconv.ParseFloat(actualType, 64)
		if err == nil {
			newInstance.ActualStringNumber = true
		}
	}
	switch instanceType := instance.(type) {
	case string:
		_, err := strconv.ParseFloat(instanceType, 64)
		if err == nil {
			newInstance.InstanceStringNumber = true
		}
	}
	return
}

var _ = FDescribe("Assertions", func() {

	key := "some:key"

	Context("Greater Than Assertion", func() {

		/*
					   Test Required
					                            INSTANCE

			                                 nil      float64    int    string-number   string
					             ACTUAL

					             float64         x          x          x          x           √

					             int             x          x          x          x           √

					             string-number   x          x          x          x           √

					             string          x          x          x          x           x

					             nil             x          x          x          x           x

		*/

		//To set further context I am making the following assumption
		//Something is greater than nil
		//nil is NOT greater than nil
		//nil is NOT greater than Something
		//string which is not a number is NOT greater than any number
		//number is NOT greater than a string which is not a number
		//Attempts will first be made to parse strings into a float64
		Context("Succeeds", func() {

			key := "some:key"

			assertTrueResult := func(actualValue interface{}, instanceValue interface{}) {
				executionResult := core.ExecutionResult{
					key: actualValue,
				}

				assertion := GreaterThanAssertion{
					Key:   key,
					Value: instanceValue,
				}

				result := assertion.Assert(executionResult)
				Expect(result["result"]).To(Equal(true))
				Expect(result["message"]).To(BeNil())
			}

			var nilValue interface{}
			var successfulAssertionTestCases = []ATC{
				NewATC(float64(1.1), nilValue),
				NewATC(int(1), nilValue),
				NewATC("1", nilValue),
				NewATC("a", nilValue),
				NewATC(float64(5), float64(1)),
				NewATC(int(5), float64(1)),
				NewATC("2.2", float64(1)),
				NewATC(int(5), int(1)),
				NewATC("5", int(1)),
				NewATC("abc", "a"),
				NewATC(float64(1.3), "1.2"),
			}

			for _, successCase := range successfulAssertionTestCases {
				actualValue := successCase.Actual
				instanceValue := successCase.Instance
				testName := fmt.Sprintf("ACTUAL > INSTANCE when Actual is of type %T and Instance is of type %T", actualValue, instanceValue)
				if successCase.ActualStringNumber {
					testName = fmt.Sprintf("%s. Actual value is a STRING NUMBER", testName)
				}
				if successCase.InstanceStringNumber {
					testName = fmt.Sprintf("%s. Instance value is a STRING NUMBER", testName)
				}
				FIt(testName, func() {
					assertTrueResult(actualValue, instanceValue)
				})
			}

			PIt("When Actual is float64 and Instance is string-number", func() {

			})

			PIt("When Actual is int and Instance is string-number", func() {

			})

			PIt("When Actual is string-number and Instance is string-number", func() {

			})
		})

		Context("Fails", func() {
			PIt("When Actual is nil and Instance is nil", func() {

			})

			PIt("When Actual is nil and Instance is int", func() {

			})

			PIt("When Actual is nil and Instance is string-number", func() {

			})

			PIt("When Actual is nil and Instance is string", func() {

			})

			PIt("When Actual is nil and Instance is float64", func() {

			})

			PIt("When Actual is float64 and Instance is float64", func() {

			})

			PIt("When Actual is int and Instance is float64", func() {

			})

			PIt("When Actual is string-number and Instance is float64", func() {

			})

			PIt("When Actual is float64 and Instance is int", func() {

			})

			PIt("When Actual is float64 and Instance is int", func() {

			})

			PIt("When Actual is int and Instance is int", func() {

			})

			PIt("When Actual is string-number and Instance is int", func() {

			})

			PIt("When Actual is string and Instance is int", func() {

			})

			PIt("When Actual is string and Instance is float64", func() {

			})

			PIt("When Actual is string and Instance is string-number", func() {

			})

			PIt("When Actual is string and Instance is string", func() {

			})

			PIt("When Actual is float64 and Instance is string", func() {

			})

			PIt("When Actual is int and Instance is string", func() {

			})

			PIt("When Actual string-number int and Instance is string", func() {

			})

		})

	})

	Context("Not Equal Assertion", func() {

		It("Succeeds", func() {
			executionResult := core.ExecutionResult{
				key: 8,
			}

			assertion := NotEqualAssertion{
				Key:   key,
				Value: 7,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(true))
			Expect(result["message"]).To(BeNil())
		})

		It("Fails", func() {
			executionResult := core.ExecutionResult{
				key: 7,
			}

			assertion := NotEqualAssertion{
				Key:   key,
				Value: 7,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(false))
			Expect(result["message"]).To(Equal("FAIL: 7 does match 7"))
		})
	})

	Context("Exact Assertion", func() {
		It("Exact Assertion Succeeds", func() {
			expectedValue := 7

			executionResult := core.ExecutionResult{
				key: expectedValue,
			}

			assertion := ExactAssertion{
				Key:   key,
				Value: expectedValue,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(true))
			Expect(result["message"]).To(BeNil())
		})

		It("Exact Assertion Fails", func() {
			expectedValue := 7

			executionResult := core.ExecutionResult{
				key: 8,
			}

			assertion := ExactAssertion{
				Key:   key,
				Value: expectedValue,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(false))
			Expect(result["message"]).To(Equal("FAIL: 8 does not match 7"))
		})

		//NOTHING is currently using the message when an assertion fails but we will need
		//it for when we put the errors into the report.  One of the edge cases with the message
		//is that say the actual value was a string "7" and the expected is an int 7.  The message
		//will not include the quotes so the message would read 7 does not equal 7 as opposed
		//to "7" does not equal 7.  Notice this is a type mismatch
		PIt("Exact Assertion Fails when actual and expected are different types", func() {
			key := "some:key"
			expectedValue := 7

			executionResult := core.ExecutionResult{
				key: "7",
			}

			assertion := ExactAssertion{
				Key:   key,
				Value: expectedValue,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(false))
			Expect(result["message"]).To(Equal("FAIL: \"7\" does not match 7"))
		})
	})

})
<commit_msg>Succeeds when Actual is int and Instance is string-number<commit_after>package assertions

import (
	"fmt"
	"strconv"

	"ci.guzzler.io/guzzler/corcel/core"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

type ATC struct {
	Actual               interface{}
	Instance             interface{}
	ActualStringNumber   bool
	InstanceStringNumber bool
}

func NewATC(actual interface{}, instance interface{}) (newInstance ATC) {
	newInstance.Actual = actual
	newInstance.Instance = instance
	switch actualType := actual.(type) {
	case string:
		_, err := strconv.ParseFloat(actualType, 64)
		if err == nil {
			newInstance.ActualStringNumber = true
		}
	}
	switch instanceType := instance.(type) {
	case string:
		_, err := strconv.ParseFloat(instanceType, 64)
		if err == nil {
			newInstance.InstanceStringNumber = true
		}
	}
	return
}

var _ = FDescribe("Assertions", func() {

	key := "some:key"

	Context("Greater Than Assertion", func() {

		/*
					   Test Required
					                            INSTANCE

			                                 nil      float64    int    string-number   string
					             ACTUAL

					             float64         x          x          x          x           √

					             int             x          x          x          x           √

					             string-number   x          x          x          x           √

					             string          x          x          x          x           x

					             nil             x          x          x          x           x

		*/

		//To set further context I am making the following assumption
		//Something is greater than nil
		//nil is NOT greater than nil
		//nil is NOT greater than Something
		//string which is not a number is NOT greater than any number
		//number is NOT greater than a string which is not a number
		//Attempts will first be made to parse strings into a float64
		Context("Succeeds", func() {

			key := "some:key"

			assertTrueResult := func(actualValue interface{}, instanceValue interface{}) {
				executionResult := core.ExecutionResult{
					key: actualValue,
				}

				assertion := GreaterThanAssertion{
					Key:   key,
					Value: instanceValue,
				}

				result := assertion.Assert(executionResult)
				Expect(result["result"]).To(Equal(true))
				Expect(result["message"]).To(BeNil())
			}

			var nilValue interface{}
			var successfulAssertionTestCases = []ATC{
				NewATC(float64(1.1), nilValue),
				NewATC(int(1), nilValue),
				NewATC("1", nilValue),
				NewATC("a", nilValue),
				NewATC(float64(5), float64(1)),
				NewATC(int(5), float64(1)),
				NewATC("2.2", float64(1)),
				NewATC(int(5), int(1)),
				NewATC("5", int(1)),
				NewATC("abc", "a"),
				NewATC(float64(1.3), "1.2"),
				NewATC(int(3), "1"),
			}

			for _, successCase := range successfulAssertionTestCases {
				actualValue := successCase.Actual
				instanceValue := successCase.Instance
				testName := fmt.Sprintf("ACTUAL > INSTANCE when Actual is of type %T and Instance is of type %T", actualValue, instanceValue)
				if successCase.ActualStringNumber {
					testName = fmt.Sprintf("%s. Actual value is a STRING NUMBER", testName)
				}
				if successCase.InstanceStringNumber {
					testName = fmt.Sprintf("%s. Instance value is a STRING NUMBER", testName)
				}
				FIt(testName, func() {
					assertTrueResult(actualValue, instanceValue)
				})
			}

			PIt("When Actual is int and Instance is string-number", func() {

			})

			PIt("When Actual is string-number and Instance is string-number", func() {

			})
		})

		Context("Fails", func() {
			PIt("When Actual is nil and Instance is nil", func() {

			})

			PIt("When Actual is nil and Instance is int", func() {

			})

			PIt("When Actual is nil and Instance is string-number", func() {

			})

			PIt("When Actual is nil and Instance is string", func() {

			})

			PIt("When Actual is nil and Instance is float64", func() {

			})

			PIt("When Actual is float64 and Instance is float64", func() {

			})

			PIt("When Actual is int and Instance is float64", func() {

			})

			PIt("When Actual is string-number and Instance is float64", func() {

			})

			PIt("When Actual is float64 and Instance is int", func() {

			})

			PIt("When Actual is float64 and Instance is int", func() {

			})

			PIt("When Actual is int and Instance is int", func() {

			})

			PIt("When Actual is string-number and Instance is int", func() {

			})

			PIt("When Actual is string and Instance is int", func() {

			})

			PIt("When Actual is string and Instance is float64", func() {

			})

			PIt("When Actual is string and Instance is string-number", func() {

			})

			PIt("When Actual is string and Instance is string", func() {

			})

			PIt("When Actual is float64 and Instance is string", func() {

			})

			PIt("When Actual is int and Instance is string", func() {

			})

			PIt("When Actual string-number int and Instance is string", func() {

			})

		})

	})

	Context("Not Equal Assertion", func() {

		It("Succeeds", func() {
			executionResult := core.ExecutionResult{
				key: 8,
			}

			assertion := NotEqualAssertion{
				Key:   key,
				Value: 7,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(true))
			Expect(result["message"]).To(BeNil())
		})

		It("Fails", func() {
			executionResult := core.ExecutionResult{
				key: 7,
			}

			assertion := NotEqualAssertion{
				Key:   key,
				Value: 7,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(false))
			Expect(result["message"]).To(Equal("FAIL: 7 does match 7"))
		})
	})

	Context("Exact Assertion", func() {
		It("Exact Assertion Succeeds", func() {
			expectedValue := 7

			executionResult := core.ExecutionResult{
				key: expectedValue,
			}

			assertion := ExactAssertion{
				Key:   key,
				Value: expectedValue,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(true))
			Expect(result["message"]).To(BeNil())
		})

		It("Exact Assertion Fails", func() {
			expectedValue := 7

			executionResult := core.ExecutionResult{
				key: 8,
			}

			assertion := ExactAssertion{
				Key:   key,
				Value: expectedValue,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(false))
			Expect(result["message"]).To(Equal("FAIL: 8 does not match 7"))
		})

		//NOTHING is currently using the message when an assertion fails but we will need
		//it for when we put the errors into the report.  One of the edge cases with the message
		//is that say the actual value was a string "7" and the expected is an int 7.  The message
		//will not include the quotes so the message would read 7 does not equal 7 as opposed
		//to "7" does not equal 7.  Notice this is a type mismatch
		PIt("Exact Assertion Fails when actual and expected are different types", func() {
			key := "some:key"
			expectedValue := 7

			executionResult := core.ExecutionResult{
				key: "7",
			}

			assertion := ExactAssertion{
				Key:   key,
				Value: expectedValue,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(false))
			Expect(result["message"]).To(Equal("FAIL: \"7\" does not match 7"))
		})
	})

})
<|endoftext|>


<commit_before>package web

// TODO: Clean up the Javascript (wrap bits in separate template consts)

const (
	indexTemplate string = `<!DOCTYPE html>

	<meta charset="utf-8">
	<title> Wallboard Control </title>

	Oops, something went wrong with the Wallboard page!

`

	welcomeTemplate string = `<!DOCTYPE html>

	<meta charset="utf-8">
	<title> Welcome </title>

wbc

		{{ if ne .Client "" }}
Client: {{ .Client }}
{{end}}

IP Addr: {{ .RemoteAddr }}

Add a URL or two and this page will disappear. :)

`

	adminTemplate = `<!DOCTYPE html>

	<meta charset="utf-8">
	<title> Wallboard Control </title>

			<input type='text' id='input'>

`
)
<commit_msg>Fix bugs in input handler for websocket<commit_after>package web

// TODO: Clean up the Javascript (wrap bits in separate template consts)

const (
	indexTemplate string = `<!DOCTYPE html>

	<meta charset="utf-8">
	<title> Wallboard Control </title>

	Oops, something went wrong with the Wallboard page!

`

	welcomeTemplate string = `<!DOCTYPE html>

	<meta charset="utf-8">
	<title> Welcome </title>

wbc

		{{ if ne .Client "" }}
Client: {{ .Client }}
{{end}}

IP Addr: {{ .RemoteAddr }}

Add a URL or two and this page will disappear. :)

`

	adminTemplate = `<!DOCTYPE html>

	<meta charset="utf-8">
	<title> Wallboard Control </title>

			<input type='text' id='input'>

`
)
<|endoftext|>


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

package winapi

import (
	"syscall"
)

//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zwinapi.go jobobj.go psapi.go

const (
	// Job object security and access rights.
	DELETE                             = 0x00010000
	READ_CONTROL                       = 0x00020000
	SYNCHRONIZE                        = 0x00100000
	WRITE_DAC                          = 0x00040000
	WRITE_OWNER                        = 0x00080000
	JOB_OBJECT_ALL_ACCESS              = 0x1F001F
	JOB_OBJECT_ASSIGN_PROCESS          = 0x0001
	JOB_OBJECT_QUERY                   = 0x0004
	JOB_OBJECT_SET_ATTRIBUTES          = 0x0002
	JOB_OBJECT_SET_SECURITY_ATTRIBUTES = 0x0010
	JOB_OBJECT_TERMINATE               = 0x0008

	JobObjectAssociateCompletionPortInformation = 7

	JOB_OBJECT_MSG_END_OF_JOB_TIME       = 1
	JOB_OBJECT_MSG_END_OF_PROCESS_TIME   = 2
	JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT  = 3
	JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO   = 4
	JOB_OBJECT_MSG_NEW_PROCESS           = 6
	JOB_OBJECT_MSG_EXIT_PROCESS          = 7
	JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS = 8
	JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT  = 9
	JOB_OBJECT_MSG_JOB_MEMORY_LIMIT      = 10
)

type JOBOBJECT_ASSOCIATE_COMPLETION_PORT struct {
	CompletionKey  uintptr
	CompletionPort syscall.Handle
}

//sys	CreateJobObject(jobAttrs *syscall.SecurityAttributes, name *uint16) (handle syscall.Handle, err error) = kernel32.CreateJobObjectW
//sys	OpenJobObject(desiredAccess uint32, inheritHandles bool, name *uint16) (handle syscall.Handle, err error) = kernel32.OpenJobObjectW
//sys	AssignProcessToJobObject(job syscall.Handle, process syscall.Handle) (err error) = kernel32.AssignProcessToJobObject
//sys	SetInformationJobObject(job syscall.Handle, infoclass uint32, info uintptr, infolien uint32) (err error) = kernel32.SetInformationJobObject
//sys	TerminateJobObject(job syscall.Handle, exitcode uint32) (err error) = kernel32.TerminateJobObject
<commit_msg>add support for job object management (#2)<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package winapi

import (
	"syscall"
)

//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zwinapi.go jobobj.go psapi.go

const (
	// Job object security and access rights.
	DELETE                             = 0x00010000
	READ_CONTROL                       = 0x00020000
	SYNCHRONIZE                        = 0x00100000
	WRITE_DAC                          = 0x00040000
	WRITE_OWNER                        = 0x00080000
	JOB_OBJECT_ALL_ACCESS              = 0x1F001F
	JOB_OBJECT_ASSIGN_PROCESS          = 0x0001
	JOB_OBJECT_QUERY                   = 0x0004
	JOB_OBJECT_SET_ATTRIBUTES          = 0x0002
	JOB_OBJECT_SET_SECURITY_ATTRIBUTES = 0x0010
	JOB_OBJECT_TERMINATE               = 0x0008

	JobObjectAssociateCompletionPortInformation = 7

	JOB_OBJECT_MSG_END_OF_JOB_TIME       = 1
	JOB_OBJECT_MSG_END_OF_PROCESS_TIME   = 2
	JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT  = 3
	JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO   = 4
	JOB_OBJECT_MSG_NEW_PROCESS           = 6
	JOB_OBJECT_MSG_EXIT_PROCESS          = 7
	JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS = 8
	JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT  = 9
	JOB_OBJECT_MSG_JOB_MEMORY_LIMIT      = 10

	JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE          = 0x2000
	JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x400
	JOB_OBJECT_LIMIT_ACTIVE_PROCESS             = 8
	JOB_OBJECT_LIMIT_JOB_MEMORY                 = 0x200
	JOB_OBJECT_LIMIT_JOB_TIME                   = 4
	JOB_OBJECT_LIMIT_PROCESS_MEMORY             = 0x100
	JOB_OBJECT_LIMIT_PROCESS_TIME               = 2
	JOB_OBJECT_LIMIT_WORKINGSET                 = 1
	JOB_OBJECT_LIMIT_AFFINITY                   = 0x00000010
)

type JOBOBJECT_ASSOCIATE_COMPLETION_PORT struct {
	CompletionKey  uintptr
	CompletionPort syscall.Handle
}

type IO_COUNTERS struct {
	ReadOperationCount  uint64
	WriteOperationCount uint64
	OtherOperationCount uint64
	ReadTransferCount   uint64
	WriteTransferCount  uint64
	OtherTransferCount  uint64
}

type JOBOBJECT_BASIC_LIMIT_INFORMATION struct {
	PerProcessUserTimeLimit int64
	PerJobUserTimeLimit     int64
	LimitFlags              uint32
	MinimumWorkingSetSize   uintptr
	MaximumWorkingSetSize   uintptr
	ActiveProcessLimit      uint32
	Affinity                uintptr
	PriorityClass           uint32
	SchedulingClass         uint32
}

type JOBOBJECT_EXTENDED_LIMIT_INFORMATION struct {
	BasicLimitInformation JOBOBJECT_BASIC_LIMIT_INFORMATION
	IoInfo                IO_COUNTERS
	ProcessMemoryLimit    uintptr
	JobMemoryLimit        uintptr
	PeakProcessMemoryUsed uintptr
	PeakJobMemoryUsed     uintptr
}

//sys	CreateJobObject(jobAttrs *syscall.SecurityAttributes, name *uint16) (handle syscall.Handle, err error) = kernel32.CreateJobObjectW
//sys	OpenJobObject(desiredAccess uint32, inheritHandles bool, name *uint16) (handle syscall.Handle, err error) = kernel32.OpenJobObjectW
//sys	AssignProcessToJobObject(job syscall.Handle, process syscall.Handle) (err error) = kernel32.AssignProcessToJobObject
//sys	SetInformationJobObject(job syscall.Handle, infoclass uint32, info uintptr, infolien uint32) (err error) = kernel32.SetInformationJobObject
//sys	TerminateJobObject(job syscall.Handle, exitcode uint32) (err error) = kernel32.TerminateJobObject
<|endoftext|>


<commit_before>package jsonrpc2_test

import (
	"bytes"
	"context"
	"encoding/json"
	"net"
	"net/http"
	"net/rpc"
	"reflect"
	"testing"

	"github.com/powerman/rpc-codec/jsonrpc2"
)

type contextKey int

var remoteAddrContextKey contextKey = 0

// CtxSvc is an RPC service for testing.
type CtxSvc struct{}

func (*CtxSvc) Sum(vals [2]int, res *int) error {
	*res = vals[0] + vals[1]
	return nil
}

// type NameArg struct{ Fname, Lname string }
// type NameRes struct{ Name string }

func (*CtxSvc) Name(t NameArg, res *NameRes) error {
	*res = NameRes{t.Fname + " " + t.Lname}
	return nil
}

// type NameArgContext struct {
// 	Fname, Lname string
// 	jsonrpc2.Ctx
// }

type NameResCtx struct {
	Name           string
	TCPRemoteAddr  string
	HTTPRemoteAddr string
}

// Method with named params and TCP context.
func (*CtxSvc) NameCtx(t NameArgContext, res *NameResCtx) error {
	*res = NameResCtx{Name: t.Fname + " " + t.Lname}
	if val := t.Context().Value(remoteAddrContextKey); val != nil {
		res.TCPRemoteAddr, _, _ = net.SplitHostPort(val.(*net.TCPAddr).String())
	}
	if val := jsonrpc2.HTTPRequestFromContext(t.Context()); val != nil {
		res.HTTPRemoteAddr, _, _ = net.SplitHostPort(val.RemoteAddr)
	}
	return nil
}

func init() {
	_ = rpc.Register(&CtxSvc{})
}

// - for each of these servers:
//   * TCP server without context
//   * TCP server with context
//   * HTTP server with context
// - call these methods:
//   * Sum()
//   * Name()
//   * NameCtx()
//   * TODO batch call all
func TestContext(t *testing.T) {
	// Server provide a TCP transport without context.
	serverTCPNoCtx, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer serverTCPNoCtx.Close()
	go func() {
		for {
			conn, err := serverTCPNoCtx.Accept()
			if err != nil {
				return
			}
			go jsonrpc2.ServeConn(conn)
		}
	}()

	// Server provide a TCP transport with context.
	serverTCP, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer serverTCP.Close()
	go func() {
		for {
			conn, err := serverTCP.Accept()
			if err != nil {
				return
			}
			ctx := context.WithValue(context.Background(), remoteAddrContextKey, conn.RemoteAddr())
			go jsonrpc2.ServeConnContext(ctx, conn)
		}
	}()

	// Server provide a HTTP transport with context.
	http.Handle("/", jsonrpc2.HTTPHandler(nil))
	serverHTTP, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer serverHTTP.Close()
	go http.Serve(serverHTTP, nil)

	// Client use TCP transport without context.
	clientTCPNoCtx, err := jsonrpc2.Dial("tcp", serverTCPNoCtx.Addr().String())
	if err != nil {
		t.Fatal(err)
	}
	defer clientTCPNoCtx.Close()

	// Client use TCP transport with context.
	clientTCP, err := jsonrpc2.Dial("tcp", serverTCP.Addr().String())
	if err != nil {
		t.Fatal(err)
	}
	defer clientTCP.Close()

	// Client use HTTP transport with context.
	clientHTTP := jsonrpc2.NewHTTPClient("http://" + serverHTTP.Addr().String() + "/")
	defer clientHTTP.Close()

	cases := []struct {
		client     *jsonrpc2.Client
		clientName string
		method     string
		arg        interface{}
		want       interface{}
	}{
		{clientTCPNoCtx, "clientTCPNoCtx",
			"CtxSvc.Sum", [2]int{3, 5}, 8.0},
		{clientTCP, "clientTCP",
			"CtxSvc.Sum", [2]int{3, 5}, 8.0},
		{clientHTTP, "clientHTTP",
			"CtxSvc.Sum", [2]int{3, 5}, 8.0},
		{clientTCPNoCtx, "clientTCPNoCtx",
			"CtxSvc.Name", NameArg{"First", "Last"}, map[string]interface{}{
				"Name": "First Last",
			}},
		{clientTCP, "clientTCP",
			"CtxSvc.Name", NameArg{"First", "Last"}, map[string]interface{}{
				"Name": "First Last",
			}},
		{clientHTTP, "clientHTTP",
			"CtxSvc.Name", NameArg{"First", "Last"}, map[string]interface{}{
				"Name": "First Last",
			}},
		{clientTCPNoCtx, "clientTCPNoCtx",
			"CtxSvc.NameCtx", NameArg{"First", "Last"}, map[string]interface{}{
				"Name":           "First Last",
				"TCPRemoteAddr":  "",
				"HTTPRemoteAddr": "",
			}},
		{clientTCP, "clientTCP",
			"CtxSvc.NameCtx", NameArg{"First", "Last"}, map[string]interface{}{
				"Name":           "First Last",
				"TCPRemoteAddr":  "127.0.0.1",
				"HTTPRemoteAddr": "",
			}},
		{clientHTTP, "clientHTTP",
			"CtxSvc.NameCtx", NameArg{"First", "Last"}, map[string]interface{}{
				"Name":           "First Last",
				"TCPRemoteAddr":  "",
				"HTTPRemoteAddr": "127.0.0.1",
			}},
	}
	for _, v := range cases {
		var res interface{}
		err := v.client.Call(v.method, v.arg, &res)
		if err != nil {
			t.Errorf("%s.Call(%q) = %v", v.clientName, v.method, err)
		}
		if !reflect.DeepEqual(v.want, res) {
			t.Errorf("%s.Call(%q):\n\n\texp: %#v\n\n\tgot: %#v\n\n", v.clientName, v.method, v.want, res)
		}
	}
}

func TestContextBugNoContextWithoutParams(t *testing.T) {
	cases := []struct {
		req  string
		want interface{}
	}{
		{
			`{"jsonrpc":"2.0","id":0,"method":"CtxSvc.NameCtx"}`,
			map[string]interface{}{
				"Name":           " ",
				"TCPRemoteAddr":  "127.0.0.1",
				"HTTPRemoteAddr": "",
			},
		},
		{
			`{"jsonrpc":"2.0","id":0,"method":"CtxSvc.NameCtx","params":{}}`,
			map[string]interface{}{
				"Name":           " ",
				"TCPRemoteAddr":  "127.0.0.1",
				"HTTPRemoteAddr": "",
			},
		},
		{
			`{"jsonrpc":"2.0","id":0,"method":"CtxSvc.NameCtx","params":{"Fname":"First","Lname":"Last"}}`,
			map[string]interface{}{
				"Name":           "First Last",
				"TCPRemoteAddr":  "127.0.0.1",
				"HTTPRemoteAddr": "",
			},
		},
	}
	for _, v := range cases {
		buf := bytes.NewBufferString(v.req)
		rpc.ServeRequest(jsonrpc2.NewServerCodecContext(
			context.WithValue(context.Background(), remoteAddrContextKey, &net.TCPAddr{IP: net.ParseIP("127.0.0.1")}),
			&bufReadWriteCloser{buf},
			nil,
		))
		var res map[string]interface{}
		err := json.Unmarshal(buf.Bytes(), &res)
		if err != nil {
			t.Fatal(err)
		}
		if !reflect.DeepEqual(v.want, res["result"]) {
			t.Errorf("%q:\n\n\texp: %#v\n\n\tgot: %#v\n\n", v.req, v.want, res["result"])
		}
	}
}

type bufReadWriteCloser struct {
	*bytes.Buffer
}

func (b *bufReadWriteCloser) Close() error { return nil }
<commit_msg>add test for batch with context<commit_after>package jsonrpc2_test

import (
	"bytes"
	"context"
	"encoding/json"
	"net"
	"net/http"
	"net/rpc"
	"reflect"
	"testing"

	"github.com/powerman/rpc-codec/jsonrpc2"
)

type contextKey int

var remoteAddrContextKey contextKey = 0

// CtxSvc is an RPC service for testing.
type CtxSvc struct{}

func (*CtxSvc) Sum(vals [2]int, res *int) error {
	*res = vals[0] + vals[1]
	return nil
}

// type NameArg struct{ Fname, Lname string }
// type NameRes struct{ Name string }

func (*CtxSvc) Name(t NameArg, res *NameRes) error {
	*res = NameRes{t.Fname + " " + t.Lname}
	return nil
}

// type NameArgContext struct {
// 	Fname, Lname string
// 	jsonrpc2.Ctx
// }

type NameResCtx struct {
	Name           string
	TCPRemoteAddr  string
	HTTPRemoteAddr string
}

// Method with named params and TCP context.
func (*CtxSvc) NameCtx(t NameArgContext, res *NameResCtx) error {
	*res = NameResCtx{Name: t.Fname + " " + t.Lname}
	if val := t.Context().Value(remoteAddrContextKey); val != nil {
		res.TCPRemoteAddr, _, _ = net.SplitHostPort(val.(*net.TCPAddr).String())
	}
	if val := jsonrpc2.HTTPRequestFromContext(t.Context()); val != nil {
		res.HTTPRemoteAddr, _, _ = net.SplitHostPort(val.RemoteAddr)
	}
	return nil
}

func init() {
	_ = rpc.Register(&CtxSvc{})
}

// - for each of these servers:
//   * TCP server without context
//   * TCP server with context
//   * HTTP server with context
// - call these methods:
//   * Sum()
//   * Name()
//   * NameCtx()
//   * TODO batch call all
func TestContext(t *testing.T) {
	// Server provide a TCP transport without context.
	serverTCPNoCtx, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer serverTCPNoCtx.Close()
	go func() {
		for {
			conn, err := serverTCPNoCtx.Accept()
			if err != nil {
				return
			}
			go jsonrpc2.ServeConn(conn)
		}
	}()

	// Server provide a TCP transport with context.
	serverTCP, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer serverTCP.Close()
	go func() {
		for {
			conn, err := serverTCP.Accept()
			if err != nil {
				return
			}
			ctx := context.WithValue(context.Background(), remoteAddrContextKey, conn.RemoteAddr())
			go jsonrpc2.ServeConnContext(ctx, conn)
		}
	}()

	// Server provide a HTTP transport with context.
	http.Handle("/", jsonrpc2.HTTPHandler(nil))
	serverHTTP, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer serverHTTP.Close()
	go http.Serve(serverHTTP, nil)

	// Client use TCP transport without context.
	clientTCPNoCtx, err := jsonrpc2.Dial("tcp", serverTCPNoCtx.Addr().String())
	if err != nil {
		t.Fatal(err)
	}
	defer clientTCPNoCtx.Close()

	// Client use TCP transport with context.
	clientTCP, err := jsonrpc2.Dial("tcp", serverTCP.Addr().String())
	if err != nil {
		t.Fatal(err)
	}
	defer clientTCP.Close()

	// Client use HTTP transport with context.
	clientHTTP := jsonrpc2.NewHTTPClient("http://" + serverHTTP.Addr().String() + "/")
	defer clientHTTP.Close()

	cases := []struct {
		client     *jsonrpc2.Client
		clientName string
		method     string
		arg        interface{}
		want       interface{}
	}{
		{clientTCPNoCtx, "clientTCPNoCtx",
			"CtxSvc.Sum", [2]int{3, 5}, 8.0},
		{clientTCP, "clientTCP",
			"CtxSvc.Sum", [2]int{3, 5}, 8.0},
		{clientHTTP, "clientHTTP",
			"CtxSvc.Sum", [2]int{3, 5}, 8.0},
		{clientTCPNoCtx, "clientTCPNoCtx",
			"CtxSvc.Name", NameArg{"First", "Last"}, map[string]interface{}{
				"Name": "First Last",
			}},
		{clientTCP, "clientTCP",
			"CtxSvc.Name", NameArg{"First", "Last"}, map[string]interface{}{
				"Name": "First Last",
			}},
		{clientHTTP, "clientHTTP",
			"CtxSvc.Name", NameArg{"First", "Last"}, map[string]interface{}{
				"Name": "First Last",
			}},
		{clientTCPNoCtx, "clientTCPNoCtx",
			"CtxSvc.NameCtx", NameArg{"First", "Last"}, map[string]interface{}{
				"Name":           "First Last",
				"TCPRemoteAddr":  "",
				"HTTPRemoteAddr": "",
			}},
		{clientTCP, "clientTCP",
			"CtxSvc.NameCtx", NameArg{"First", "Last"}, map[string]interface{}{
				"Name":           "First Last",
				"TCPRemoteAddr":  "127.0.0.1",
				"HTTPRemoteAddr": "",
			}},
		{clientHTTP, "clientHTTP",
			"CtxSvc.NameCtx", NameArg{"First", "Last"}, map[string]interface{}{
				"Name":           "First Last",
				"TCPRemoteAddr":  "",
				"HTTPRemoteAddr": "127.0.0.1",
			}},
	}
	for _, v := range cases {
		var res interface{}
		err := v.client.Call(v.method, v.arg, &res)
		if err != nil {
			t.Errorf("%s.Call(%q) = %v", v.clientName, v.method, err)
		}
		if !reflect.DeepEqual(v.want, res) {
			t.Errorf("%s.Call(%q):\n\n\texp: %#v\n\n\tgot: %#v\n\n", v.clientName, v.method, v.want, res)
		}
	}
}

func TestContextBatch(t *testing.T) {
	req := `[
		{"jsonrpc":"2.0","id":0,"method":"CtxSvc.NameCtx","params":{}},
		{"jsonrpc":"2.0","id":1,"method":"CtxSvc.NameCtx","params":{"Fname":"First","Lname":"Last"}}
		]`
	want := []map[string]interface{}{
		{
			"jsonrpc": "2.0",
			"id":      0.0,
			"result": map[string]interface{}{
				"Name":           " ",
				"TCPRemoteAddr":  "127.0.0.1",
				"HTTPRemoteAddr": "",
			},
		},
		{
			"jsonrpc": "2.0",
			"id":      1.0,
			"result": map[string]interface{}{
				"Name":           "First Last",
				"TCPRemoteAddr":  "127.0.0.1",
				"HTTPRemoteAddr": "",
			},
		},
	}
	buf := bytes.NewBufferString(req)
	rpc.ServeRequest(jsonrpc2.NewServerCodecContext(
		context.WithValue(context.Background(), remoteAddrContextKey, &net.TCPAddr{IP: net.ParseIP("127.0.0.1")}),
		&bufReadWriteCloser{buf},
		nil,
	))
	var res []map[string]interface{}
	err := json.Unmarshal(buf.Bytes(), &res)
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(want, res) {
		t.Errorf("%s:\n\n\texp: %#v\n\n\tgot: %#v\n\n", req, want, res)
	}
}

func TestContextBugNoContextWithoutParams(t *testing.T) {
	cases := []struct {
		req  string
		want interface{}
	}{
		{
			`{"jsonrpc":"2.0","id":0,"method":"CtxSvc.NameCtx"}`,
			map[string]interface{}{
				"Name":           " ",
				"TCPRemoteAddr":  "127.0.0.1",
				"HTTPRemoteAddr": "",
			},
		},
		{
			`{"jsonrpc":"2.0","id":0,"method":"CtxSvc.NameCtx","params":{}}`,
			map[string]interface{}{
				"Name":           " ",
				"TCPRemoteAddr":  "127.0.0.1",
				"HTTPRemoteAddr": "",
			},
		},
		{
			`{"jsonrpc":"2.0","id":0,"method":"CtxSvc.NameCtx","params":{"Fname":"First","Lname":"Last"}}`,
			map[string]interface{}{
				"Name":           "First Last",
				"TCPRemoteAddr":  "127.0.0.1",
				"HTTPRemoteAddr": "",
			},
		},
	}
	for _, v := range cases {
		buf := bytes.NewBufferString(v.req)
		rpc.ServeRequest(jsonrpc2.NewServerCodecContext(
			context.WithValue(context.Background(), remoteAddrContextKey, &net.TCPAddr{IP: net.ParseIP("127.0.0.1")}),
			&bufReadWriteCloser{buf},
			nil,
		))
		var res map[string]interface{}
		err := json.Unmarshal(buf.Bytes(), &res)
		if err != nil {
			t.Fatal(err)
		}
		if !reflect.DeepEqual(v.want, res["result"]) {
			t.Errorf("%q:\n\n\texp: %#v\n\n\tgot: %#v\n\n", v.req, v.want, res["result"])
		}
	}
}

type bufReadWriteCloser struct {
	*bytes.Buffer
}

func (b *bufReadWriteCloser) Close() error { return nil }
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Tigera, Inc. 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 main

import (
	"net/http"
	"os/exec"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	log "github.com/sirupsen/logrus"
	"k8s.io/client-go/kubernetes"

	"github.com/projectcalico/libcalico-go/lib/health"
)

var _ = Describe("calculation graph scale test", func() {

	var (
		clientset *kubernetes.Clientset
		nsPrefix  string
	)

	BeforeEach(func() {
		log.Info(">>> BeforeEach <<<")
		clientset = initialize(k8sServerEndpoint)
		nsPrefix = getNamespacePrefix()
	})

	It("should run label rotation test", func() {
		Expect(rotateLabels(clientset, nsPrefix)).To(BeNil())
	})

	It("should process 1000 pods", func() {
		Expect(create1000Pods(clientset, nsPrefix)).To(BeNil())
	})

	It("health endpoint should indicate not ready", func() {
		// Because there is no config for the local node.
		triggerFelixRestart()
		for i := 0; i < 20; i++ {
			Expect(getHealthStatus("readiness")()).To(BeNumerically("==", health.StatusBad))
			time.Sleep(500 * time.Millisecond)
		}
	})

	It("health endpoint should indicate not live", func() {
		// Because there is no config for the local node.
		triggerFelixRestart()
		for i := 0; i < 20; i++ {
			Expect(getHealthStatus("liveness")()).To(BeNumerically("==", health.StatusBad))
			time.Sleep(500 * time.Millisecond)
		}
	})

	Context("with a local host", func() {
		BeforeEach(func() {
			triggerFelixRestart()
			_ = NewDeployment(clientset, 0, true)
		})

		It("should see health readiness endpoint", func() {
			Eventually(getHealthStatus("readiness"), "20s", "0.5s").Should(BeNumerically("==", health.StatusGood))
		})

		It("should see health liveness endpoint", func() {
			Eventually(getHealthStatus("liveness"), "20s", "0.5s").Should(BeNumerically("==", health.StatusGood))
		})
	})

	AfterEach(func() {
		log.Info(">>> AfterEach <<<")
		time.Sleep(10 * time.Second)
		cleanupAll(clientset, nsPrefix)
	})
})

func getHealthStatus(endpoint string) func() int {
	return func() int {
		resp, err := http.Get("http://" + felixIP + ":9099/" + endpoint)
		if err != nil {
			log.WithError(err).Error("HTTP GET failed")
			return health.StatusBad
		}
		log.WithField("resp", resp).Info("Health response")
		defer resp.Body.Close()
		return resp.StatusCode
	}
}

func triggerFelixRestart() {
	exec.Command("pkill", "-TERM", "calico-felix").Run()
	time.Sleep(1 * time.Second)
}
<commit_msg>k8sfv: remove health endpoint tests<commit_after>// Copyright (c) 2016-2017 Tigera, Inc. 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 main

import (
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	log "github.com/sirupsen/logrus"
	"k8s.io/client-go/kubernetes"

	"github.com/projectcalico/libcalico-go/lib/health"
)

var _ = Describe("calculation graph scale test", func() {

	var (
		clientset *kubernetes.Clientset
		nsPrefix  string
	)

	BeforeEach(func() {
		log.Info(">>> BeforeEach <<<")
		clientset = initialize(k8sServerEndpoint)
		nsPrefix = getNamespacePrefix()
	})

	It("should run label rotation test", func() {
		Expect(rotateLabels(clientset, nsPrefix)).To(BeNil())
	})

	It("should process 1000 pods", func() {
		Expect(create1000Pods(clientset, nsPrefix)).To(BeNil())
	})

	AfterEach(func() {
		log.Info(">>> AfterEach <<<")
		time.Sleep(10 * time.Second)
		cleanupAll(clientset, nsPrefix)
	})
})
<|endoftext|>


<commit_before>// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package params

import "math/big"

var (
	TestNetHomesteadBlock = big.NewInt(494000)    // testnet homestead block
	MainNetHomesteadBlock = big.NewInt(2000000)   // mainnet homestead block
	HomesteadBlock        = MainNetHomesteadBlock // homestead block used to check against
)

func IsHomestead(blockNumber *big.Int) bool {
	// for unit tests TODO: flip to true after homestead is live
	if blockNumber == nil {
		return false
	}
	return blockNumber.Cmp(HomesteadBlock) >= 0
}
<commit_msg>params: updated homestead block<commit_after>// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package params

import "math/big"

var (
	TestNetHomesteadBlock = big.NewInt(494000)    // testnet homestead block
	MainNetHomesteadBlock = big.NewInt(1150000)   // mainnet homestead block
	HomesteadBlock        = MainNetHomesteadBlock // homestead block used to check against
)

func IsHomestead(blockNumber *big.Int) bool {
	// for unit tests TODO: flip to true after homestead is live
	if blockNumber == nil {
		return false
	}
	return blockNumber.Cmp(HomesteadBlock) >= 0
}
<|endoftext|>


<commit_before><commit_msg>unexported some stuff<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Matthew Dawson <matthew@mjdsystems.ca>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package main

import (
	"crypto/sha512"

	"io"

	"net/url"

	"sort"

	"time"

	"code.google.com/p/go-charset/charset"
	_ "code.google.com/p/go-charset/data"

	rss "github.com/jteeuwen/go-pkg-rss"
)

type ParsedFeedItemList []ParsedFeedItem

type ParsedFeedData struct {
	Title string

	Items ParsedFeedItemList

	NextCheckTime time.Time
}

type ParsedFeedItem struct {
	GenericKey []byte //This is just the hash of the GUID or Link or Title or w/e makes it unique.  It is not the system's id, as it doesn't include the generated id
	Title      string
	Author     string
	Content    string

	Url url.URL

	PubDate time.Time
}

func makeHash(str string) []byte {
	hasher := sha512.New()

	n, err := io.WriteString(hasher, str)
	if err != nil {
		panic(err)
	} else if n != len(str) {
		panic(n)
	}

	return hasher.Sum(nil)
}

func (l ParsedFeedItemList) Len() int {
	return len(l)
}

func (l ParsedFeedItemList) Less(i, j int) bool {
	return l[i].PubDate.After(l[j].PubDate) //The latest item should be at position 0
}

func (l ParsedFeedItemList) Swap(i, j int) {
	l[i], l[j] = l[j], l[i]
}

func parseRssFeed(feedContents []byte) (*ParsedFeedData, error) {
	feed := rss.New(0, true, nil, nil)

	err := feed.FetchBytes("", feedContents, charset.NewReader)
	if err != nil {
		return nil, err
	}

	channel := feed.Channels[0]

	output := ParsedFeedData{
		Title: channel.Title,
	}

	for _, item := range channel.Items {
		nextItem := ParsedFeedItem{
			Title:  item.Title,
			Author: item.Author.Name,
		}
		if item.Content == nil {
			nextItem.Content = item.Description
		} else {
			nextItem.Content = item.Content.Text
		}

		if len(item.Links) >= 1 {
			if Url, err := url.Parse(item.Links[0].Href); err != nil {
				// Note need to log these failures for the future
				nextItem.Url = url.URL{}
			} else {
				nextItem.Url = *Url
			}
		}

		if item.PubDate != "" {
			if Date, err := parseDate(item.PubDate); err != nil {
				// Also log this for the future ...
				return nil, err
			} else {
				nextItem.PubDate = Date
			}
		}

		// The item id is a SHA512 hash of one of the following, whatever comes first:
		// GUID, Link (as used above), Title, Content, PubDate (from a processed state above).
		// Failing that any of those are useful, just fail the item.
		if item.Guid != "" {
			nextItem.GenericKey = makeHash(item.Guid)
		} else if len(item.Links) >= 1 {
			nextItem.GenericKey = makeHash(item.Links[0].Href)
		} else if item.Title != "" {
			nextItem.GenericKey = makeHash(item.Title)
		} else if item.Content != nil && item.Content.Text != "" {
			nextItem.GenericKey = makeHash(item.Content.Text)
		} else if !nextItem.PubDate.IsZero() {
			nextItem.GenericKey = makeHash(nextItem.PubDate.String())
		} else {
			continue //Seriously, this should be reported.  The item is probably junk ...
		}

		output.Items = append(output.Items, nextItem)
	}

	sort.Sort(output.Items)

	return &output, nil
}

type FeedParserOut struct {
	Data ParsedFeedData
	Url  url.URL
}

func FeedParser(in <-chan RawFeed, out chan<- FeedParserOut, errChan chan<- FeedError) {
	for {
		if next, ok := <-in; ok {

			data, err := parseRssFeed(next.Data)
			if err == nil {
				out <- FeedParserOut{Data: *data, Url: next.Url}
			} else {
				errChan <- FeedError{Err: err, Url: next.Url}
			}
		} else {
			break
		}
	}
}
<commit_msg>Atom feeds set Id instead of Guid, so make sure to use it.<commit_after>/*
 * Copyright (C) 2013 Matthew Dawson <matthew@mjdsystems.ca>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package main

import (
	"crypto/sha512"

	"io"

	"net/url"

	"sort"

	"time"

	"code.google.com/p/go-charset/charset"
	_ "code.google.com/p/go-charset/data"

	rss "github.com/jteeuwen/go-pkg-rss"
)

type ParsedFeedItemList []ParsedFeedItem

type ParsedFeedData struct {
	Title string

	Items ParsedFeedItemList

	NextCheckTime time.Time
}

type ParsedFeedItem struct {
	GenericKey []byte //This is just the hash of the GUID or Link or Title or w/e makes it unique.  It is not the system's id, as it doesn't include the generated id
	Title      string
	Author     string
	Content    string

	Url url.URL

	PubDate time.Time
}

func makeHash(str string) []byte {
	hasher := sha512.New()

	n, err := io.WriteString(hasher, str)
	if err != nil {
		panic(err)
	} else if n != len(str) {
		panic(n)
	}

	return hasher.Sum(nil)
}

func (l ParsedFeedItemList) Len() int {
	return len(l)
}

func (l ParsedFeedItemList) Less(i, j int) bool {
	return l[i].PubDate.After(l[j].PubDate) //The latest item should be at position 0
}

func (l ParsedFeedItemList) Swap(i, j int) {
	l[i], l[j] = l[j], l[i]
}

func parseRssFeed(feedContents []byte) (*ParsedFeedData, error) {
	feed := rss.New(0, true, nil, nil)

	err := feed.FetchBytes("", feedContents, charset.NewReader)
	if err != nil {
		return nil, err
	}

	channel := feed.Channels[0]

	output := ParsedFeedData{
		Title: channel.Title,
	}

	for _, item := range channel.Items {
		nextItem := ParsedFeedItem{
			Title:  item.Title,
			Author: item.Author.Name,
		}
		if item.Content == nil {
			nextItem.Content = item.Description
		} else {
			nextItem.Content = item.Content.Text
		}

		if len(item.Links) >= 1 {
			if Url, err := url.Parse(item.Links[0].Href); err != nil {
				// Note need to log these failures for the future
				nextItem.Url = url.URL{}
			} else {
				nextItem.Url = *Url
			}
		}

		if item.PubDate != "" {
			if Date, err := parseDate(item.PubDate); err != nil {
				// Also log this for the future ...
				return nil, err
			} else {
				nextItem.PubDate = Date
			}
		}

		// The item id is a SHA512 hash of one of the following, whatever comes first:
		// GUID, Link (as used above), Title, Content, PubDate (from a processed state above).
		// Failing that any of those are useful, just fail the item.
		if item.Guid != "" {
			nextItem.GenericKey = makeHash(item.Guid)
		} else if item.Id != "" {
			nextItem.GenericKey = makeHash(item.Id)
		} else if len(item.Links) >= 1 {
			nextItem.GenericKey = makeHash(item.Links[0].Href)
		} else if item.Title != "" {
			nextItem.GenericKey = makeHash(item.Title)
		} else if item.Content != nil && item.Content.Text != "" {
			nextItem.GenericKey = makeHash(item.Content.Text)
		} else if !nextItem.PubDate.IsZero() {
			nextItem.GenericKey = makeHash(nextItem.PubDate.String())
		} else {
			continue //Seriously, this should be reported.  The item is probably junk ...
		}

		output.Items = append(output.Items, nextItem)
	}

	sort.Sort(output.Items)

	return &output, nil
}

type FeedParserOut struct {
	Data ParsedFeedData
	Url  url.URL
}

func FeedParser(in <-chan RawFeed, out chan<- FeedParserOut, errChan chan<- FeedError) {
	for {
		if next, ok := <-in; ok {

			data, err := parseRssFeed(next.Data)
			if err == nil {
				out <- FeedParserOut{Data: *data, Url: next.Url}
			} else {
				errChan <- FeedError{Err: err, Url: next.Url}
			}
		} else {
			break
		}
	}
}
<|endoftext|>


<commit_before>package glfw

//go:generate ../../scripts/glfw_tree_rebuild.sh

// This is a recursive hash of the full contents of the upstream glfw, as
// generated by git (doesn't need to be committed) when you run `go generate` on
// this package. This exists to invalidate the build cache (see [0]), which is
// unaffected by C source inputs.
// [0] https://github.com/go-gl/glfw/issues/269
const upstreamTreeSHA = "4490c2c270a92046291b021c15e33340289b33db"
<commit_msg>Update docstring for nit<commit_after>package glfw

//go:generate ../../scripts/glfw_tree_rebuild.sh

// upstreamTreeSHA is a recursive hash of the full contents of the upstream
// glfw, as generated by git (doesn't need to be committed) when you run `go
// generate` on this package. This exists to invalidate the build cache (see
// https://github.com/go-gl/glfw/issues/269), which is unaffected by C source
// inputs.
const upstreamTreeSHA = "4490c2c270a92046291b021c15e33340289b33db"
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. 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 gcscaching

import (
	"fmt"
	"io"
	"sync"
	"time"

	"golang.org/x/net/context"

	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/gcloud/gcs"
)

// Create a bucket that caches object records returned by the supplied wrapped
// bucket. Records are invalidated when modifications are made through this
// bucket, and after the supplied TTL.
func NewFastStatBucket(
	ttl time.Duration,
	cache StatCache,
	clock timeutil.Clock,
	wrapped gcs.Bucket) (b gcs.Bucket) {
	fsb := &fastStatBucket{
		cache:   cache,
		clock:   clock,
		wrapped: wrapped,
		ttl:     ttl,
	}

	b = fsb
	return
}

type fastStatBucket struct {
	mu sync.Mutex

	/////////////////////////
	// Dependencies
	/////////////////////////

	// GUARDED_BY(mu)
	cache StatCache

	clock   timeutil.Clock
	wrapped gcs.Bucket

	/////////////////////////
	// Constant data
	/////////////////////////

	ttl time.Duration
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) insertMultiple(objs []*gcs.Object) {
	b.mu.Lock()
	defer b.mu.Unlock()

	expiration := b.clock.Now().Add(b.ttl)
	for _, o := range objs {
		b.cache.Insert(o, expiration)
	}
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) insert(o *gcs.Object) {
	b.insertMultiple([]*gcs.Object{o})
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) invalidate(name string) {
	b.mu.Lock()
	defer b.mu.Unlock()

	b.cache.Erase(name)
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) lookUp(name string) (hit bool, o *gcs.Object) {
	b.mu.Lock()
	defer b.mu.Unlock()

	hit, o = b.cache.LookUp(name, b.clock.Now())
	return
}

////////////////////////////////////////////////////////////////////////
// Bucket interface
////////////////////////////////////////////////////////////////////////

func (b *fastStatBucket) Name() string {
	return b.wrapped.Name()
}

func (b *fastStatBucket) NewReader(
	ctx context.Context,
	req *gcs.ReadObjectRequest) (rc io.ReadCloser, err error) {
	rc, err = b.wrapped.NewReader(ctx, req)
	return
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) CreateObject(
	ctx context.Context,
	req *gcs.CreateObjectRequest) (o *gcs.Object, err error) {
	// Throw away any existing record for this object.
	b.invalidate(req.Name)

	// Create the new object.
	o, err = b.wrapped.CreateObject(ctx, req)
	if err != nil {
		return
	}

	// Record the new object.
	b.insert(o)

	return
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) StatObject(
	ctx context.Context,
	req *gcs.StatObjectRequest) (o *gcs.Object, err error) {
	// Do we have an entry in the cache?
	if hit, entry := b.lookUp(req.Name); hit {
		// Negative entries result in NotFoundError.
		if entry == nil {
			err = &gcs.NotFoundError{
				Err: fmt.Errorf("Negative cache entry for %v", req.Name),
			}

			return
		}

		// Otherwise, return the object.
		o = entry
		return
	}

	// Ask the wrapped bucket.
	o, err = b.wrapped.StatObject(ctx, req)
	if err != nil {
		// Special case: NotFoundError -> negative entry.
		if _, ok := err.(*gcs.NotFoundError); ok {
			b.insert(o)
		}

		return
	}

	// Put the object in cache.
	b.insert(o)

	return
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) ListObjects(
	ctx context.Context,
	req *gcs.ListObjectsRequest) (listing *gcs.Listing, err error) {
	// Fetch the listing.
	listing, err = b.wrapped.ListObjects(ctx, req)
	if err != nil {
		return
	}

	// Note anything we found.
	b.insertMultiple(listing.Objects)

	return
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) UpdateObject(
	ctx context.Context,
	req *gcs.UpdateObjectRequest) (o *gcs.Object, err error) {
	// Throw away any existing record for this object.
	b.invalidate(req.Name)

	// Update the object.
	o, err = b.wrapped.UpdateObject(ctx, req)
	if err != nil {
		return
	}

	// Record the new version.
	b.insert(o)

	return
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) DeleteObject(
	ctx context.Context,
	name string) (err error) {
	b.invalidate(name)
	err = b.wrapped.DeleteObject(ctx, name)
	return
}
<commit_msg>Fixed a bug.<commit_after>// Copyright 2015 Google Inc. 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 gcscaching

import (
	"fmt"
	"io"
	"sync"
	"time"

	"golang.org/x/net/context"

	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/gcloud/gcs"
)

// Create a bucket that caches object records returned by the supplied wrapped
// bucket. Records are invalidated when modifications are made through this
// bucket, and after the supplied TTL.
func NewFastStatBucket(
	ttl time.Duration,
	cache StatCache,
	clock timeutil.Clock,
	wrapped gcs.Bucket) (b gcs.Bucket) {
	fsb := &fastStatBucket{
		cache:   cache,
		clock:   clock,
		wrapped: wrapped,
		ttl:     ttl,
	}

	b = fsb
	return
}

type fastStatBucket struct {
	mu sync.Mutex

	/////////////////////////
	// Dependencies
	/////////////////////////

	// GUARDED_BY(mu)
	cache StatCache

	clock   timeutil.Clock
	wrapped gcs.Bucket

	/////////////////////////
	// Constant data
	/////////////////////////

	ttl time.Duration
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) insertMultiple(objs []*gcs.Object) {
	b.mu.Lock()
	defer b.mu.Unlock()

	expiration := b.clock.Now().Add(b.ttl)
	for _, o := range objs {
		b.cache.Insert(o, expiration)
	}
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) insert(o *gcs.Object) {
	b.insertMultiple([]*gcs.Object{o})
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) addNegativeEntry(name string) {
	b.mu.Lock()
	defer b.mu.Unlock()

	expiration := b.clock.Now().Add(b.ttl)
	b.cache.AddNegativeEntry(name, expiration)
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) invalidate(name string) {
	b.mu.Lock()
	defer b.mu.Unlock()

	b.cache.Erase(name)
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) lookUp(name string) (hit bool, o *gcs.Object) {
	b.mu.Lock()
	defer b.mu.Unlock()

	hit, o = b.cache.LookUp(name, b.clock.Now())
	return
}

////////////////////////////////////////////////////////////////////////
// Bucket interface
////////////////////////////////////////////////////////////////////////

func (b *fastStatBucket) Name() string {
	return b.wrapped.Name()
}

func (b *fastStatBucket) NewReader(
	ctx context.Context,
	req *gcs.ReadObjectRequest) (rc io.ReadCloser, err error) {
	rc, err = b.wrapped.NewReader(ctx, req)
	return
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) CreateObject(
	ctx context.Context,
	req *gcs.CreateObjectRequest) (o *gcs.Object, err error) {
	// Throw away any existing record for this object.
	b.invalidate(req.Name)

	// Create the new object.
	o, err = b.wrapped.CreateObject(ctx, req)
	if err != nil {
		return
	}

	// Record the new object.
	b.insert(o)

	return
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) StatObject(
	ctx context.Context,
	req *gcs.StatObjectRequest) (o *gcs.Object, err error) {
	// Do we have an entry in the cache?
	if hit, entry := b.lookUp(req.Name); hit {
		// Negative entries result in NotFoundError.
		if entry == nil {
			err = &gcs.NotFoundError{
				Err: fmt.Errorf("Negative cache entry for %v", req.Name),
			}

			return
		}

		// Otherwise, return the object.
		o = entry
		return
	}

	// Ask the wrapped bucket.
	o, err = b.wrapped.StatObject(ctx, req)
	if err != nil {
		// Special case: NotFoundError -> negative entry.
		if _, ok := err.(*gcs.NotFoundError); ok {
			b.addNegativeEntry(req.Name)
		}

		return
	}

	// Put the object in cache.
	b.insert(o)

	return
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) ListObjects(
	ctx context.Context,
	req *gcs.ListObjectsRequest) (listing *gcs.Listing, err error) {
	// Fetch the listing.
	listing, err = b.wrapped.ListObjects(ctx, req)
	if err != nil {
		return
	}

	// Note anything we found.
	b.insertMultiple(listing.Objects)

	return
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) UpdateObject(
	ctx context.Context,
	req *gcs.UpdateObjectRequest) (o *gcs.Object, err error) {
	// Throw away any existing record for this object.
	b.invalidate(req.Name)

	// Update the object.
	o, err = b.wrapped.UpdateObject(ctx, req)
	if err != nil {
		return
	}

	// Record the new version.
	b.insert(o)

	return
}

// LOCKS_EXCLUDED(b.mu)
func (b *fastStatBucket) DeleteObject(
	ctx context.Context,
	name string) (err error) {
	b.invalidate(name)
	err = b.wrapped.DeleteObject(ctx, name)
	return
}
<|endoftext|>


<commit_before>package tracing

import (
	"context"
	"errors"
	"net/http"
	"runtime"

	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/log"
)

// LogError adds a span log for an error.
// Returns unchanged error, so useful to wrap as in:
//  return 0, tracing.LogError(err)
func LogError(span opentracing.Span, err error) error {
	span.LogFields(log.Error(err))
	return err
}

// InjectToHTTPRequest adds tracing headers to an HTTP request.
// Easier than adding this boilerplate everywhere.
func InjectToHTTPRequest(span opentracing.Span, req *http.Request) {
	err := opentracing.GlobalTracer().Inject(span.Context(), opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header))
	if err != nil {
		span.LogFields(log.String("trace-inject-error", err.Error()))
	}
}

// ExtractFromHTTPRequest gets a child span of the parent referenced in HTTP request headers.
// Easier than adding this boilerplate everywhere.
func ExtractFromHTTPRequest(req *http.Request, handlerName string) (opentracing.Span, *http.Request) {
	spanContext, err := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header))
	if err != nil {
		span, ctx := opentracing.StartSpanFromContext(req.Context(), handlerName+":"+req.URL.Path)
		span.LogFields(log.String("trace-extract-error", err.Error()))
		req = req.WithContext(ctx)
		return span, req
	}

	span := opentracing.StartSpan(handlerName+":"+req.URL.Path, opentracing.ChildOf(spanContext))
	req = req.WithContext(opentracing.ContextWithSpan(req.Context(), span))
	return span, req
}

// StartSpanFromContext is an improved opentracing.StartSpanFromContext.
// Uses the calling function as the operation name, and logs the filename and line number.
//
// Passing nil context triggers new context and root span construction.
// Context without parent span reference triggers root span construction.
// This function never returns nil values.
//
// Performance
//
// This function incurs a small performance penalty, roughly 1000 ns/op, 376 B/op, 6 allocs/op.
// Jaeger timestamp and duration precision is only µs, so this is pretty negligible.
//
// Alternatives
//
// If this performance penalty is too much, try these, which are also demonstrated in benchmark tests:
//  // Create a root span
//  span := opentracing.StartSpan("operation name")
//  ctx := opentracing.ContextWithSpan(context.Background(), span)
//
//  // Create a child span
//  span := opentracing.StartSpan("operation name", opentracing.ChildOf(sc))
//  ctx := opentracing.ContextWithSpan(context.Background(), span)
//
//  // Sugar to create a child span
//  span, ctx := opentracing.StartSpanFromContext(ctx, "operation name")
func StartSpanFromContext(ctx context.Context) (opentracing.Span, context.Context) {
	if ctx == nil {
		panic("StartSpanFromContext called with nil context")
	}

	var frame runtime.Frame
	{
		// Get caller frame.
		pc, _, _, ok := runtime.Caller(1)
		if !ok {
			span, ctx := opentracing.StartSpanFromContext(ctx, "unknown")
			span.LogFields(log.Error(errors.New("runtime.Caller failed")))
			return span, ctx
		}

		frame, _ = runtime.CallersFrames([]uintptr{pc}).Next()
	}

	var span opentracing.Span
	if parentSpan := opentracing.SpanFromContext(ctx); parentSpan != nil {
		// Create a child span.
		span = opentracing.StartSpan(frame.Function, opentracing.ChildOf(parentSpan.Context()))
	} else {
		// Create a root span.
		span = opentracing.StartSpan(frame.Function)
	}
	// New context references this span, not the parent (if there was one).
	ctx = opentracing.ContextWithSpan(ctx, span)

	span.LogFields(log.String("filename", frame.File), log.Int("line", frame.Line))

	return span, ctx
}
<commit_msg>perf(tracing): Use alternate runtime APIs to reduce allocs / cpu<commit_after>package tracing

import (
	"context"
	"errors"
	"net/http"
	"runtime"

	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/log"
)

// LogError adds a span log for an error.
// Returns unchanged error, so useful to wrap as in:
//  return 0, tracing.LogError(err)
func LogError(span opentracing.Span, err error) error {
	span.LogFields(log.Error(err))
	return err
}

// InjectToHTTPRequest adds tracing headers to an HTTP request.
// Easier than adding this boilerplate everywhere.
func InjectToHTTPRequest(span opentracing.Span, req *http.Request) {
	err := opentracing.GlobalTracer().Inject(span.Context(), opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header))
	if err != nil {
		span.LogFields(log.String("trace-inject-error", err.Error()))
	}
}

// ExtractFromHTTPRequest gets a child span of the parent referenced in HTTP request headers.
// Easier than adding this boilerplate everywhere.
func ExtractFromHTTPRequest(req *http.Request, handlerName string) (opentracing.Span, *http.Request) {
	spanContext, err := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header))
	if err != nil {
		span, ctx := opentracing.StartSpanFromContext(req.Context(), handlerName+":"+req.URL.Path)
		span.LogFields(log.String("trace-extract-error", err.Error()))
		req = req.WithContext(ctx)
		return span, req
	}

	span := opentracing.StartSpan(handlerName+":"+req.URL.Path, opentracing.ChildOf(spanContext))
	req = req.WithContext(opentracing.ContextWithSpan(req.Context(), span))
	return span, req
}

// StartSpanFromContext is an improved opentracing.StartSpanFromContext.
// Uses the calling function as the operation name, and logs the filename and line number.
//
// Passing nil context triggers new context and root span construction.
// Context without parent span reference triggers root span construction.
// This function never returns nil values.
//
// Performance
//
// This function incurs a small performance penalty, roughly 1000 ns/op, 376 B/op, 6 allocs/op.
// Jaeger timestamp and duration precision is only µs, so this is pretty negligible.
//
// Alternatives
//
// If this performance penalty is too much, try these, which are also demonstrated in benchmark tests:
//  // Create a root span
//  span := opentracing.StartSpan("operation name")
//  ctx := opentracing.ContextWithSpan(context.Background(), span)
//
//  // Create a child span
//  span := opentracing.StartSpan("operation name", opentracing.ChildOf(sc))
//  ctx := opentracing.ContextWithSpan(context.Background(), span)
//
//  // Sugar to create a child span
//  span, ctx := opentracing.StartSpanFromContext(ctx, "operation name")
func StartSpanFromContext(ctx context.Context) (opentracing.Span, context.Context) {
	if ctx == nil {
		panic("StartSpanFromContext called with nil context")
	}

	// Get caller frame.
	var pcs [1]uintptr
	n := runtime.Callers(2, pcs[:])
	if n < 1 {
		span, ctx := opentracing.StartSpanFromContext(ctx, "unknown")
		span.LogFields(log.Error(errors.New("runtime.Caller failed")))
		return span, ctx
	}
	fn := runtime.FuncForPC(pcs[0])
	name := fn.Name()

	var span opentracing.Span
	if parentSpan := opentracing.SpanFromContext(ctx); parentSpan != nil {
		// Create a child span.
		span = opentracing.StartSpan(name, opentracing.ChildOf(parentSpan.Context()))
	} else {
		// Create a root span.
		span = opentracing.StartSpan(name)
	}
	// New context references this span, not the parent (if there was one).
	ctx = opentracing.ContextWithSpan(ctx, span)

	file, line := fn.FileLine(pcs[0])
	span.LogFields(log.String("filename", file), log.Int("line", line))

	return span, ctx
}
<|endoftext|>


<commit_before>package common

import (
	"strconv"
	"strings"
)

type Status uint8

const (
	ShowAll Status = iota
	FilterRemakes
	Trusted
	APlus
)

func (st *Status) ToString() string {
	switch *st {
	case FilterRemakes:
		return "1"
	case Trusted:
		return "2"
	case APlus:
		return "3"
	}
	return ""
}

func (st *Status) Parse(s string) {
	switch s {
	case "1":
		*st = FilterRemakes
		break
	case "2":
		*st = Trusted
		break
	case "3":
		*st = APlus
		break
	default:
		*st = ShowAll
	}
}

type SortMode uint8

const (
	ID SortMode = iota
	Name
	Date
	Downloads
	Size
	Seeders
	Leechers
	Completed
)

func (s *SortMode) Parse(str string) {
	switch str {
	case "1":
		*s = Name
		break
	case "2":
		*s = Date
		break
	case "3":
		*s = Downloads
		break
	case "4":
		*s = Size
		break
	case "5":
		*s = Seeders
		break
	case "6":
		*s = Leechers
		break
	case "7":
		*s = Completed
		break
	default:
		*s = ID
	}
}

/* INFO Always need to keep in sync with the field that are used in the
 * elasticsearch index.
 * TODO Verify the field in postgres database
 */
func (s *SortMode) ToESField() string {
	switch *s {
	case ID:
		return "id"
	case Name:
		return "name"
	case Date:
		return "date"
	case Downloads:
		return "downloads"
	case Size:
		return "filesize"
	case Seeders:
		return "seeders"
	case Leechers:
		return "leechers"
	case Completed:
		return "completed"
	}
	return "id"
}

type Category struct {
	Main, Sub uint8
}

func (c Category) String() (s string) {
	if c.Main != 0 {
		s += strconv.Itoa(int(c.Main))
	}
	s += "_"
	if c.Sub != 0 {
		s += strconv.Itoa(int(c.Sub))
	}
	return
}

func (c Category) IsSet() bool {
	return c.IsMainSet() && c.IsSubSet()
}

func (c Category) IsMainSet() bool {
	return c.Main != 0
}

func (c Category) IsSubSet() bool {
	return c.Sub != 0
}

// Parse sets category by string
// returns true if string is valid otherwise returns false
func (c *Category) Parse(s string) (ok bool) {
	parts := strings.Split(s, "_")
	if len(parts) == 2 {
		tmp, err := strconv.ParseUint(parts[0], 10, 8)
		if err == nil {
			c.Main = uint8(tmp)
			tmp, err = strconv.ParseUint(parts[1], 10, 8)
			if err == nil {
				c.Sub = uint8(tmp)
				ok = true
			}
		}
	}
	return
}

// deprecated for TorrentParam
type SearchParam struct {
	TorrentID uint
	FromID    uint // Search for torrentID > FromID
	Order     bool // True means acsending
	Status    Status
	Sort      SortMode
	Category  Category
	Page      int
	UserID    uint
	Max       uint
	NotNull   string
	Query     string
}
<commit_msg>Use raw entry for sorting by text<commit_after>package common

import (
	"strconv"
	"strings"
)

type Status uint8

const (
	ShowAll Status = iota
	FilterRemakes
	Trusted
	APlus
)

func (st *Status) ToString() string {
	switch *st {
	case FilterRemakes:
		return "1"
	case Trusted:
		return "2"
	case APlus:
		return "3"
	}
	return ""
}

func (st *Status) Parse(s string) {
	switch s {
	case "1":
		*st = FilterRemakes
		break
	case "2":
		*st = Trusted
		break
	case "3":
		*st = APlus
		break
	default:
		*st = ShowAll
	}
}

type SortMode uint8

const (
	ID SortMode = iota
	Name
	Date
	Downloads
	Size
	Seeders
	Leechers
	Completed
)

func (s *SortMode) Parse(str string) {
	switch str {
	case "1":
		*s = Name
		break
	case "2":
		*s = Date
		break
	case "3":
		*s = Downloads
		break
	case "4":
		*s = Size
		break
	case "5":
		*s = Seeders
		break
	case "6":
		*s = Leechers
		break
	case "7":
		*s = Completed
		break
	default:
		*s = ID
	}
}

/* INFO Always need to keep in sync with the field that are used in the
 * elasticsearch index.
 * TODO Verify the field in postgres database
 */
func (s *SortMode) ToESField() string {
	switch *s {
	case ID:
		return "id"
	case Name:
		return "name.raw"
	case Date:
		return "date"
	case Downloads:
		return "downloads"
	case Size:
		return "filesize"
	case Seeders:
		return "seeders"
	case Leechers:
		return "leechers"
	case Completed:
		return "completed"
	}
	return "id"
}

type Category struct {
	Main, Sub uint8
}

func (c Category) String() (s string) {
	if c.Main != 0 {
		s += strconv.Itoa(int(c.Main))
	}
	s += "_"
	if c.Sub != 0 {
		s += strconv.Itoa(int(c.Sub))
	}
	return
}

func (c Category) IsSet() bool {
	return c.IsMainSet() && c.IsSubSet()
}

func (c Category) IsMainSet() bool {
	return c.Main != 0
}

func (c Category) IsSubSet() bool {
	return c.Sub != 0
}

// Parse sets category by string
// returns true if string is valid otherwise returns false
func (c *Category) Parse(s string) (ok bool) {
	parts := strings.Split(s, "_")
	if len(parts) == 2 {
		tmp, err := strconv.ParseUint(parts[0], 10, 8)
		if err == nil {
			c.Main = uint8(tmp)
			tmp, err = strconv.ParseUint(parts[1], 10, 8)
			if err == nil {
				c.Sub = uint8(tmp)
				ok = true
			}
		}
	}
	return
}

// deprecated for TorrentParam
type SearchParam struct {
	TorrentID uint
	FromID    uint // Search for torrentID > FromID
	Order     bool // True means acsending
	Status    Status
	Sort      SortMode
	Category  Category
	Page      int
	UserID    uint
	Max       uint
	NotNull   string
	Query     string
}
<|endoftext|>


<commit_before>package proxy

import (
	"fmt"
	"log"
	"sort"
	"time"

	"github.com/SoCloz/goprismic"
)

type Config struct {
	// Cache size
	CacheSize int
	// Documents are cached for a maximum time of ttl.
	TTL time.Duration
	// API Master ref refresh frequency
	MasterRefresh time.Duration
	// Base refresh chance after master reference chance
	BaselineRefreshChance float32
	// inherited from api
	debug bool
}

type Proxy struct {
	cache *Cache
	api   *goprismic.Api

	Config Config

	lastRefresh           time.Time
	baselineRefreshChance float32
}

// Creates a proxy
//
// All documents are cached in a LRU cache of cacheSize elements.
func New(u, accessToken string, apiCfg goprismic.Config, cfg Config) (*Proxy, error) {
	a, err := goprismic.Get(u, accessToken, apiCfg)
	if err != nil {
		return nil, err
	}
	if cfg.MasterRefresh == 0 {
		cfg.MasterRefresh = time.Minute
	}
	cfg.debug = apiCfg.Debug
	if cfg.BaselineRefreshChance == 0 {
		cfg.BaselineRefreshChance = 1.0
	}
	c := NewCache(cfg.CacheSize, cfg.TTL, 1.0)
	c.revision = a.GetMasterRef()
	p := &Proxy{
		cache:                 c,
		api:                   a,
		Config:                cfg,
		lastRefresh:           time.Now(),
		baselineRefreshChance: cfg.BaselineRefreshChance,
	}
	go p.loopRefresh()
	return p, nil
}

// Returns the cache stats
func (p *Proxy) GetStats() Stats {
	return p.cache.Stats
}

// Queries the API
//
//   proxy.Direct().Master().Form("everything").Submit()
func (p *Proxy) Direct() *goprismic.Api {
	return p.api
}

// Fetches a document by id
func (p *Proxy) GetDocument(id string) (*goprismic.Document, error) {
	sr, err := p.Search().Form("everything").Query("[[:d = at(document.id, \"" + id + "\")]]").Submit()
	if err != nil || sr.TotalResults == 0 {
		return nil, err
	}
	return &sr.Results[0], nil

}

// Fetches a document of a specific type by a field value
func (p *Proxy) GetDocumentBy(docType, field string, value interface{}) (*goprismic.Document, error) {
	query := fmt.Sprintf("[[:d = at(my.%s.%s, \"%v\")][:d = any(document.type, [\"%s\"])]]", docType, field, value, docType)
	sr, err := p.Search().Form("everything").Query(query).Submit()
	if err != nil || sr.TotalResults == 0 {
		return nil, err
	}
	return &sr.Results[0], nil
}

// Search documents
func (p *Proxy) Search() *SearchForm {
	f := &SearchForm{sf: p.api.Master(), p: p}
	f.sig = sort.StringSlice{}
	return f
}

// Refreshes the master ref, returns true if master ref has changed
func (p *Proxy) Refresh() bool {
	p.api.Refresh()
	oldRev := p.cache.revision
	p.cache.revision = p.api.GetMasterRef()
	if oldRev != p.cache.revision {
		p.lastRefresh = time.Now()
		// refresh : 100% cache miss expected => we switch to baseline
		p.cache.refreshChance = p.baselineRefreshChance
		if p.Config.debug {
			log.Printf("Prismic - refreshing master ref and lowering refresh chance to %.1f%%", p.cache.refreshChance*100)
		}
		return true
	}
	return false
}

// Refreshes the master ref, returns true if master ref has changed
func (p *Proxy) loopRefresh() {
	prevRefreshError, prevRefresh := 0, 0
	tick := time.Tick(p.Config.MasterRefresh)
	for {
		select {
		case <-tick:
			refreshed := p.Refresh()
			deltaRefreshError := p.cache.Stats.RefreshError - prevRefreshError
			deltaRefresh := p.cache.Stats.Refresh - prevRefresh
			// ensure that chance is always > 0 and valid
			refreshChance := float32(deltaRefresh+1) / float32(deltaRefresh+deltaRefreshError+1)
			if refreshChance < p.baselineRefreshChance {
				p.baselineRefreshChance = refreshChance
				if p.Config.debug {
					log.Printf("Prismic - lowering baseline refresh chance to %.2f%%", p.baselineRefreshChance*100.0)
				}
			}
			if !refreshed {
				if refreshChance < p.cache.refreshChance {
					p.cache.refreshChance = refreshChance
					if p.Config.debug {
						log.Printf("Prismic - lowering refresh chance to %.2f%%", p.cache.refreshChance*100.0)
					}
				}
				if refreshChance > p.cache.refreshChance {
					if refreshChance < p.cache.refreshChance*1.1 {
						p.cache.refreshChance = refreshChance
					} else {
						p.cache.refreshChance = p.cache.refreshChance * 1.1
					}
					if p.cache.refreshChance >= 1.0 {
						p.cache.refreshChance = 1.0
					}
					if p.Config.debug {
						log.Printf("Prismic - raising refresh chance to %.2f%%", p.cache.refreshChance*100.0)
					}
				}
			}
		}
	}
}

// Get something from the proxy
func (p *Proxy) Get(key string, refresh RefreshFn) (interface{}, error) {
	return p.cache.Get(key, refresh)
}

// Clears the cache
func (p *Proxy) Clear() {
	p.cache.Clear()
}
<commit_msg>proxy: never change baseline, updated refreshChance computation<commit_after>package proxy

import (
	"fmt"
	"log"
	"sort"
	"time"

	"github.com/SoCloz/goprismic"
)

type Config struct {
	// Cache size
	CacheSize int
	// Documents are cached for a maximum time of ttl.
	TTL time.Duration
	// API Master ref refresh frequency
	MasterRefresh time.Duration
	// Base refresh chance after master reference chance
	BaselineRefreshChance float32
	// inherited from api
	debug bool
}

type Proxy struct {
	cache *Cache
	api   *goprismic.Api

	Config Config

	lastRefresh           time.Time
}

// Creates a proxy
//
// All documents are cached in a LRU cache of cacheSize elements.
func New(u, accessToken string, apiCfg goprismic.Config, cfg Config) (*Proxy, error) {
	a, err := goprismic.Get(u, accessToken, apiCfg)
	if err != nil {
		return nil, err
	}
	if cfg.MasterRefresh == 0 {
		cfg.MasterRefresh = time.Minute
	}
	cfg.debug = apiCfg.Debug
	if cfg.BaselineRefreshChance == 0 {
		cfg.BaselineRefreshChance = 1.0
	}
	c := NewCache(cfg.CacheSize, cfg.TTL, 1.0)
	c.revision = a.GetMasterRef()
	p := &Proxy{
		cache:                 c,
		api:                   a,
		Config:                cfg,
		lastRefresh:           time.Now(),
	}
	go p.loopRefresh()
	return p, nil
}

// Returns the cache stats
func (p *Proxy) GetStats() Stats {
	return p.cache.Stats
}

// Queries the API
//
//   proxy.Direct().Master().Form("everything").Submit()
func (p *Proxy) Direct() *goprismic.Api {
	return p.api
}

// Fetches a document by id
func (p *Proxy) GetDocument(id string) (*goprismic.Document, error) {
	sr, err := p.Search().Form("everything").Query("[[:d = at(document.id, \"" + id + "\")]]").Submit()
	if err != nil || sr.TotalResults == 0 {
		return nil, err
	}
	return &sr.Results[0], nil

}

// Fetches a document of a specific type by a field value
func (p *Proxy) GetDocumentBy(docType, field string, value interface{}) (*goprismic.Document, error) {
	query := fmt.Sprintf("[[:d = at(my.%s.%s, \"%v\")][:d = any(document.type, [\"%s\"])]]", docType, field, value, docType)
	sr, err := p.Search().Form("everything").Query(query).Submit()
	if err != nil || sr.TotalResults == 0 {
		return nil, err
	}
	return &sr.Results[0], nil
}

// Search documents
func (p *Proxy) Search() *SearchForm {
	f := &SearchForm{sf: p.api.Master(), p: p}
	f.sig = sort.StringSlice{}
	return f
}

// Refreshes the master ref, returns true if master ref has changed
func (p *Proxy) Refresh() bool {
	p.api.Refresh()
	oldRev := p.cache.revision
	p.cache.revision = p.api.GetMasterRef()
	if oldRev != p.cache.revision {
		p.lastRefresh = time.Now()
		// refresh : 100% cache miss expected => we switch to baseline
		p.cache.refreshChance = p.Config.BaselineRefreshChance
		if p.Config.debug {
			log.Printf("Prismic - refreshing master ref and lowering refresh chance to %.1f%%", p.cache.refreshChance*100)
		}
		return true
	}
	return false
}

// Refreshes the master ref, returns true if master ref has changed
func (p *Proxy) loopRefresh() {
	prevRefreshError, prevRefresh := 0, 0
	tick := time.Tick(p.Config.MasterRefresh)
	for {
		select {
		case <-tick:
			refreshed := p.Refresh()
			deltaRefreshError := p.cache.Stats.RefreshError - prevRefreshError
			deltaRefresh := p.cache.Stats.Refresh - prevRefresh
			prevRefreshError, prevRefresh = p.cache.Stats.RefreshError, p.cache.Stats.Refresh
			if !refreshed && deltaRefresh+deltaRefreshError > 0 {
				refreshChance := float32(deltaRefresh) / float32(deltaRefresh+deltaRefreshError) * p.cache.refreshChance
				if refreshChance < p.cache.refreshChance {
					p.cache.refreshChance = refreshChance
					if p.Config.debug {
						log.Printf("Prismic - lowering refresh chance to %.2f%%", p.cache.refreshChance*100.0)
					}
				}
				if refreshChance > p.cache.refreshChance {
					if refreshChance < p.cache.refreshChance*1.1 {
						p.cache.refreshChance = refreshChance
					} else {
						p.cache.refreshChance = p.cache.refreshChance * 1.1
					}
					if p.cache.refreshChance >= 1.0 {
						p.cache.refreshChance = 1.0
					}
					if p.Config.debug {
						log.Printf("Prismic - raising refresh chance to %.2f%%", p.cache.refreshChance*100.0)
					}
				}
			}
		}
	}
}

// Get something from the proxy
func (p *Proxy) Get(key string, refresh RefreshFn) (interface{}, error) {
	return p.cache.Get(key, refresh)
}

// Clears the cache
func (p *Proxy) Clear() {
	p.cache.Clear()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"

	kingpin "gopkg.in/alecthomas/kingpin.v2"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/prometheus/common/promlog"
	"github.com/prometheus/common/promlog/flag"

	"github.com/robustperception/pushprox/util"
)

const (
	namespace = "pushprox_proxy" // For Prometheus metrics.
)

var (
	listenAddress        = kingpin.Flag("web.listen-address", "Address to listen on for proxy and client requests.").Default(":8080").String()
	maxScrapeTimeout     = kingpin.Flag("scrape.max-timeout", "Any scrape with a timeout higher than this will have to be clamped to this.").Default("5m").Duration()
	defaultScrapeTimeout = kingpin.Flag("scrape.default-timeout", "If a scrape lacks a timeout, use this value.").Default("15s").Duration()
)

var (
	httpAPICounter = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "pushprox_http_requests_total",
			Help: "Number of http api requests.",
		},
		[]string{"code", "path"},
	)

	httpProxyCounter = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "pushproxy_proxied_requests_total",
			Help: "Number of http proxy requests.",
		},
		[]string{"code"},
	)
)

func init() {
	prometheus.MustRegister(httpAPICounter, httpProxyCounter)
}

func copyHTTPResponse(resp *http.Response, w http.ResponseWriter) {
	for k, v := range resp.Header {
		w.Header()[k] = v
	}
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}

type targetGroup struct {
	Targets []string          `json:"targets"`
	Labels  map[string]string `json:"labels"`
}

type httpHandler struct {
	logger      log.Logger
	coordinator *Coordinator
	mux         http.Handler
	proxy       http.Handler
}

func newHTTPHandler(logger log.Logger, coordinator *Coordinator, mux *http.ServeMux) *httpHandler {
	h := &httpHandler{logger: logger, coordinator: coordinator, mux: mux}

	// api handlers
	handlers := map[string]http.HandlerFunc{
		"/push":    h.handlePush,
		"/poll":    h.handlePoll,
		"/clients": h.handleListClients,
	}
	for path, handlerFunc := range handlers {
		counter := httpAPICounter.MustCurryWith(prometheus.Labels{"path": path})
		mux.Handle(path, promhttp.InstrumentHandlerCounter(counter, http.HandlerFunc(handlerFunc)))
		counter.WithLabelValues("200")
		if path == "/push" {
			counter.WithLabelValues("500")
		}
		if path == "/poll" {
			counter.WithLabelValues("408")
		}
	}

	// proxy handler
	h.proxy = promhttp.InstrumentHandlerCounter(httpProxyCounter, http.HandlerFunc(h.handleProxy))

	return h
}

// handlePush handles scrape responses from client.
func (h *httpHandler) handlePush(w http.ResponseWriter, r *http.Request) {
	buf := &bytes.Buffer{}
	io.Copy(buf, r.Body)
	scrapeResult, err := http.ReadResponse(bufio.NewReader(buf), nil)
	if err != nil {
		level.Error(h.logger).Log("msg", "Error reading pushed response:", "err", err)
		http.Error(w, fmt.Sprintf("Error pushing: %s", err.Error()), 500)
		return
	}
	level.Info(h.logger).Log("msg", "Got /push", "scrape_id", scrapeResult.Header.Get("Id"))
	err = h.coordinator.ScrapeResult(scrapeResult)
	if err != nil {
		level.Error(h.logger).Log("msg", "Error pushing:", "err", err, "scrape_id", scrapeResult.Header.Get("Id"))
		http.Error(w, fmt.Sprintf("Error pushing: %s", err.Error()), 500)
	}
}

// handlePoll handles clients registering and asking for scrapes.
func (h *httpHandler) handlePoll(w http.ResponseWriter, r *http.Request) {
	fqdn, _ := ioutil.ReadAll(r.Body)
	request, err := h.coordinator.WaitForScrapeInstruction(strings.TrimSpace(string(fqdn)))
	if err != nil {
		level.Info(h.logger).Log("msg", "Error WaitForScrapeInstruction:", "err", err)
		http.Error(w, fmt.Sprintf("Error WaitForScrapeInstruction: %s", err.Error()), 408)
		return
	}
	request.WriteProxy(w) // Send full request as the body of the response.
	level.Info(h.logger).Log("msg", "Responded to /poll", "url", request.URL.String(), "scrape_id", request.Header.Get("Id"))
}

// handleListClients handles requests to list available clients as a JSON array.
func (h *httpHandler) handleListClients(w http.ResponseWriter, r *http.Request) {
	known := h.coordinator.KnownClients()
	targets := make([]*targetGroup, 0, len(known))
	for _, k := range known {
		targets = append(targets, &targetGroup{Targets: []string{k}})
	}
	json.NewEncoder(w).Encode(targets)
	level.Info(h.logger).Log("msg", "Responded to /clients", "client_count", len(known))
}

// handleProxy handles proxied scrapes from Prometheus.
func (h *httpHandler) handleProxy(w http.ResponseWriter, r *http.Request) {
	ctx, _ := context.WithTimeout(r.Context(), util.GetScrapeTimeout(maxScrapeTimeout, defaultScrapeTimeout, r.Header))
	request := r.WithContext(ctx)
	request.RequestURI = ""

	resp, err := h.coordinator.DoScrape(ctx, request)
	if err != nil {
		level.Error(h.logger).Log("msg", "Error scraping:", "err", err, "url", request.URL.String())
		http.Error(w, fmt.Sprintf("Error scraping %q: %s", request.URL.String(), err.Error()), 500)
		return
	}
	defer resp.Body.Close()
	copyHTTPResponse(resp, w)
}

// ServeHTTP discriminates between proxy requests (e.g. from Prometheus) and other requests (e.g. from the Client).
func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Host != "" { // Proxy request
		h.proxy.ServeHTTP(w, r)
	} else { // Non-proxy requests
		h.mux.ServeHTTP(w, r)
	}
}

func main() {
	promlogConfig := promlog.Config{}
	flag.AddFlags(kingpin.CommandLine, &promlogConfig)
	kingpin.HelpFlag.Short('h')
	kingpin.Parse()
	logger := promlog.New(&promlogConfig)
	coordinator := NewCoordinator(logger)

	mux := http.NewServeMux()
	mux.Handle("/metrics", promhttp.Handler())
	handler := newHTTPHandler(logger, coordinator, mux)

	level.Info(logger).Log("msg", "Listening", "address", *listenAddress)
	if err := http.ListenAndServe(*listenAddress, handler); err != nil {
		level.Error(logger).Log("msg", "Listening failed", "err", err)
		os.Exit(1)
	}
}
<commit_msg>duration metric for http paths (#62)<commit_after>package main

import (
	"bufio"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"

	kingpin "gopkg.in/alecthomas/kingpin.v2"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/prometheus/common/promlog"
	"github.com/prometheus/common/promlog/flag"

	"github.com/robustperception/pushprox/util"
)

const (
	namespace = "pushprox_proxy" // For Prometheus metrics.
)

var (
	listenAddress        = kingpin.Flag("web.listen-address", "Address to listen on for proxy and client requests.").Default(":8080").String()
	maxScrapeTimeout     = kingpin.Flag("scrape.max-timeout", "Any scrape with a timeout higher than this will have to be clamped to this.").Default("5m").Duration()
	defaultScrapeTimeout = kingpin.Flag("scrape.default-timeout", "If a scrape lacks a timeout, use this value.").Default("15s").Duration()
)

var (
	httpAPICounter = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "pushprox_http_requests_total",
			Help: "Number of http api requests.",
		}, []string{"code", "path"},
	)

	httpProxyCounter = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "pushproxy_proxied_requests_total",
			Help: "Number of http proxy requests.",
		}, []string{"code"},
	)
	httpPathHistogram = prometheus.NewHistogramVec(
		prometheus.HistogramOpts{
			Name: "pushprox_http_duration_seconds",
			Help: "Time taken by path",
		}, []string{"path"})
)

func init() {
	prometheus.MustRegister(httpAPICounter, httpProxyCounter, httpPathHistogram)
}

func copyHTTPResponse(resp *http.Response, w http.ResponseWriter) {
	for k, v := range resp.Header {
		w.Header()[k] = v
	}
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}

type targetGroup struct {
	Targets []string          `json:"targets"`
	Labels  map[string]string `json:"labels"`
}

type httpHandler struct {
	logger      log.Logger
	coordinator *Coordinator
	mux         http.Handler
	proxy       http.Handler
}

func newHTTPHandler(logger log.Logger, coordinator *Coordinator, mux *http.ServeMux) *httpHandler {
	h := &httpHandler{logger: logger, coordinator: coordinator, mux: mux}

	// api handlers
	handlers := map[string]http.HandlerFunc{
		"/push":    h.handlePush,
		"/poll":    h.handlePoll,
		"/clients": h.handleListClients,
		"/metrics": promhttp.Handler().ServeHTTP,
	}
	for path, handlerFunc := range handlers {
		counter := httpAPICounter.MustCurryWith(prometheus.Labels{"path": path})
		handler := promhttp.InstrumentHandlerCounter(counter, http.HandlerFunc(handlerFunc))
		histogram := httpPathHistogram.MustCurryWith(prometheus.Labels{"path": path})
		handler = promhttp.InstrumentHandlerDuration(histogram, handler)
		mux.Handle(path, handler)
		counter.WithLabelValues("200")
		if path == "/push" {
			counter.WithLabelValues("500")
		}
		if path == "/poll" {
			counter.WithLabelValues("408")
		}
	}

	// proxy handler
	h.proxy = promhttp.InstrumentHandlerCounter(httpProxyCounter, http.HandlerFunc(h.handleProxy))

	return h
}

// handlePush handles scrape responses from client.
func (h *httpHandler) handlePush(w http.ResponseWriter, r *http.Request) {
	buf := &bytes.Buffer{}
	io.Copy(buf, r.Body)
	scrapeResult, err := http.ReadResponse(bufio.NewReader(buf), nil)
	if err != nil {
		level.Error(h.logger).Log("msg", "Error reading pushed response:", "err", err)
		http.Error(w, fmt.Sprintf("Error pushing: %s", err.Error()), 500)
		return
	}
	level.Info(h.logger).Log("msg", "Got /push", "scrape_id", scrapeResult.Header.Get("Id"))
	err = h.coordinator.ScrapeResult(scrapeResult)
	if err != nil {
		level.Error(h.logger).Log("msg", "Error pushing:", "err", err, "scrape_id", scrapeResult.Header.Get("Id"))
		http.Error(w, fmt.Sprintf("Error pushing: %s", err.Error()), 500)
	}
}

// handlePoll handles clients registering and asking for scrapes.
func (h *httpHandler) handlePoll(w http.ResponseWriter, r *http.Request) {
	fqdn, _ := ioutil.ReadAll(r.Body)
	request, err := h.coordinator.WaitForScrapeInstruction(strings.TrimSpace(string(fqdn)))
	if err != nil {
		level.Info(h.logger).Log("msg", "Error WaitForScrapeInstruction:", "err", err)
		http.Error(w, fmt.Sprintf("Error WaitForScrapeInstruction: %s", err.Error()), 408)
		return
	}
	request.WriteProxy(w) // Send full request as the body of the response.
	level.Info(h.logger).Log("msg", "Responded to /poll", "url", request.URL.String(), "scrape_id", request.Header.Get("Id"))
}

// handleListClients handles requests to list available clients as a JSON array.
func (h *httpHandler) handleListClients(w http.ResponseWriter, r *http.Request) {
	known := h.coordinator.KnownClients()
	targets := make([]*targetGroup, 0, len(known))
	for _, k := range known {
		targets = append(targets, &targetGroup{Targets: []string{k}})
	}
	json.NewEncoder(w).Encode(targets)
	level.Info(h.logger).Log("msg", "Responded to /clients", "client_count", len(known))
}

// handleProxy handles proxied scrapes from Prometheus.
func (h *httpHandler) handleProxy(w http.ResponseWriter, r *http.Request) {
	ctx, _ := context.WithTimeout(r.Context(), util.GetScrapeTimeout(maxScrapeTimeout, defaultScrapeTimeout, r.Header))
	request := r.WithContext(ctx)
	request.RequestURI = ""

	resp, err := h.coordinator.DoScrape(ctx, request)
	if err != nil {
		level.Error(h.logger).Log("msg", "Error scraping:", "err", err, "url", request.URL.String())
		http.Error(w, fmt.Sprintf("Error scraping %q: %s", request.URL.String(), err.Error()), 500)
		return
	}
	defer resp.Body.Close()
	copyHTTPResponse(resp, w)
}

// ServeHTTP discriminates between proxy requests (e.g. from Prometheus) and other requests (e.g. from the Client).
func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Host != "" { // Proxy request
		h.proxy.ServeHTTP(w, r)
	} else { // Non-proxy requests
		h.mux.ServeHTTP(w, r)
	}
}

func main() {
	promlogConfig := promlog.Config{}
	flag.AddFlags(kingpin.CommandLine, &promlogConfig)
	kingpin.HelpFlag.Short('h')
	kingpin.Parse()
	logger := promlog.New(&promlogConfig)
	coordinator := NewCoordinator(logger)

	mux := http.NewServeMux()
	handler := newHTTPHandler(logger, coordinator, mux)

	level.Info(logger).Log("msg", "Listening", "address", *listenAddress)
	if err := http.ListenAndServe(*listenAddress, handler); err != nil {
		level.Error(logger).Log("msg", "Listening failed", "err", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package keys

import (
	"testing"
)

func TestKeyPressFix(t *testing.T) {
	k := KeyPress{'A', false, false, false, false}
	k.fix()
	if k.Key != 'a' {
		t.Errorf("Expected the key to be %q, but it was %q", 'a', k.Key)
	}
	if !k.Shift {
		t.Error("Expected the shift modifier to be active, but it wasn't")
	}
}
<commit_msg>Add some more KeyPress tests.<commit_after>// Copyright 2014 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package keys

import (
	"testing"
)

func TestKeyPressIndex(t *testing.T) {
	tests := []struct {
		kp  KeyPress
		exp int
	}{
		{
			KeyPress{Key: 'a', Shift: false, Super: false, Alt: false, Ctrl: false},
			int('a'),
		},
		{
			KeyPress{Key: 'a', Shift: true, Super: false, Alt: false, Ctrl: false},
			int('a') + shift,
		},
		{
			KeyPress{Key: 'a', Shift: true, Super: true, Alt: false, Ctrl: false},
			int('a') + shift + super,
		},
		{
			KeyPress{Key: 'a', Shift: true, Super: true, Alt: true, Ctrl: false},
			int('a') + shift + super + alt,
		},
		{
			KeyPress{Key: 'a', Shift: true, Super: true, Alt: true, Ctrl: true},
			int('a') + shift + super + alt + ctrl,
		},
	}

	for i, test := range tests {
		if test.kp.Index() != test.exp {
			t.Errorf("Test %d: Expected %d, but got %d", i, test.exp, test.kp.Index())
		}
	}
}

func TestKeyPressIsCharacter(t *testing.T) {
	tests := []struct {
		kp  KeyPress
		exp bool
	}{
		{
			KeyPress{Key: 'a', Shift: false, Super: false, Alt: false, Ctrl: false},
			true,
		},
		{
			KeyPress{Key: 'a', Shift: true, Super: false, Alt: false, Ctrl: false},
			true,
		},
		{
			KeyPress{Key: 'a', Shift: false, Super: true, Alt: false, Ctrl: false},
			false,
		},
		{
			KeyPress{Key: 'a', Shift: false, Super: false, Alt: false, Ctrl: true},
			false,
		},
		// {
		// 	KeyPress{Key: F1, Shift: false, Super: false, Alt: false, Ctrl: false},
		// 	false,
		// },
	}

	for i, test := range tests {
		if test.kp.IsCharacter() != test.exp {
			t.Errorf("Test %d: Expected %v, but got %v", i, test.exp, test.kp.IsCharacter())
		}
	}
}

func TestKeyPressFix(t *testing.T) {
	k := KeyPress{'A', false, false, false, false}
	k.fix()
	if k.Key != 'a' {
		t.Errorf("Expected the key to be %q, but it was %q", 'a', k.Key)
	}
	if !k.Shift {
		t.Error("Expected the shift modifier to be active, but it wasn't")
	}
}

func TestKeyPressString(t *testing.T) {
	k := KeyPress{'a', true, true, false, false}
	if k.String() != "super+shift+a" {
		t.Errorf("Expected %q, but got %q", "super+shift+a", k.String())
	}
}
<|endoftext|>