<commit_before>package oraclegen

import (
	"errors"
	"fmt"
	"strings"

	"github.com/rbastic/dyndao/object"
	"github.com/rbastic/dyndao/schema"
)

// BindingUpdate generates the SQL for a given UPDATE statement for oracle with binding parameter values
func (g Generator) BindingUpdate(sch *schema.Schema, obj *object.Object) (string, []interface{}, []interface{}, error) {
	schTable, ok := sch.Tables[obj.Type]
	if !ok {
		return "", nil, nil, errors.New("BindingUpdate: Table map unavailable for table " + obj.Type)
	}

	fieldsMap := schTable.Fields
	if fieldsMap == nil {
		return "", nil, nil, errors.New("BindingUpdate: Field map unavailable for table " + obj.Type)
	}

	whereClause, bindWhere, err := renderUpdateWhereClause(schTable, fieldsMap, obj)
	if err != nil {
		return "", nil, nil, err
	}

	bindArgs := make([]interface{}, len(obj.KV)-1)
	// TODO: - 1 for Oracle because we expect an identity field
	newValuesAry := make([]string, len(obj.KV)-1)
	i := 0

	if len(obj.ChangedFields) > 0 {
		for k := range obj.ChangedFields {
			f := fieldsMap[k]
			if f.IsIdentity {
				continue
			}
			newValuesAry[i] = fmt.Sprintf("%s = %s%d", f.Name, renderBindingUpdateValue(f), i)
			bindArgs[i] = obj.KV[k]

			i++
		}
	} else {
		for k, v := range obj.KV {
			f := fieldsMap[k]
			if f.IsIdentity {
				continue
			}
			newValuesAry[i] = fmt.Sprintf("%s = %s%d", f.Name, renderBindingUpdateValue(f), i)
			bindArgs[i] = v

			i++
		}
	}

	tableName := schema.GetTableName(schTable.Name, obj.Type)
	sqlStr := fmt.Sprintf("UPDATE %s SET %s WHERE %s", tableName, strings.Join(newValuesAry, ","), whereClause)
	return sqlStr, bindArgs, bindWhere, nil
}

func renderBindingUpdateValue(f *schema.Field) string {
	return ":" + f.Name
}
<commit_msg>fix BindingUpdate: use potentially aliased table name<commit_after>package oraclegen

import (
	"errors"
	"fmt"
	"strings"

	"github.com/rbastic/dyndao/object"
	"github.com/rbastic/dyndao/schema"
)

// BindingUpdate generates the SQL for a given UPDATE statement for oracle with binding parameter values
func (g Generator) BindingUpdate(sch *schema.Schema, obj *object.Object) (string, []interface{}, []interface{}, error) {
	schTable := sch.GetTable(obj.Type)
	if schTable == nil {
		return "", nil, nil, errors.New("BindingUpdate: Table map unavailable for table " + obj.Type)
	}

	fieldsMap := schTable.Fields
	if fieldsMap == nil {
		return "", nil, nil, errors.New("BindingUpdate: Field map unavailable for table " + obj.Type)
	}

	whereClause, bindWhere, err := renderUpdateWhereClause(schTable, fieldsMap, obj)
	if err != nil {
		return "", nil, nil, err
	}

	bindArgs := make([]interface{}, len(obj.KV)-1)
	// TODO: - 1 for Oracle because we expect an identity field
	newValuesAry := make([]string, len(obj.KV)-1)
	i := 0

	if len(obj.ChangedFields) > 0 {
		for k := range obj.ChangedFields {
			f := fieldsMap[k]
			if f.IsIdentity {
				continue
			}
			newValuesAry[i] = fmt.Sprintf("%s = %s%d", f.Name, renderBindingUpdateValue(f), i)
			bindArgs[i] = obj.KV[k]

			i++
		}
	} else {
		for k, v := range obj.KV {
			f := fieldsMap[k]
			if f.IsIdentity {
				continue
			}
			newValuesAry[i] = fmt.Sprintf("%s = %s%d", f.Name, renderBindingUpdateValue(f), i)
			bindArgs[i] = v

			i++
		}
	}

	tableName := schema.GetTableName(schTable.Name, obj.Type)
	sqlStr := fmt.Sprintf("UPDATE %s SET %s WHERE %s", tableName, strings.Join(newValuesAry, ","), whereClause)
	return sqlStr, bindArgs, bindWhere, nil
}

func renderBindingUpdateValue(f *schema.Field) string {
	return ":" + f.Name
}
<|endoftext|>


<commit_before>// Copyright 2010-2012 The W32 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 w32

import (
	"syscall"
	"unsafe"
)

var (
	modkernel32 = syscall.NewLazyDLL("kernel32.dll")

	procGetModuleHandle            = modkernel32.NewProc("GetModuleHandleW")
	procMulDiv                     = modkernel32.NewProc("MulDiv")
	procGetCurrentThread           = modkernel32.NewProc("GetCurrentThread")
	procGetUserDefaultLCID         = modkernel32.NewProc("GetUserDefaultLCID")
	procLstrlen                    = modkernel32.NewProc("lstrlenW")
	procLstrcpy                    = modkernel32.NewProc("lstrcpyW")
	procGlobalAlloc                = modkernel32.NewProc("GlobalAlloc")
	procGlobalFree                 = modkernel32.NewProc("GlobalFree")
	procGlobalLock                 = modkernel32.NewProc("GlobalLock")
	procGlobalUnlock               = modkernel32.NewProc("GlobalUnlock")
	procMoveMemory                 = modkernel32.NewProc("RtlMoveMemory")
	procFindResource               = modkernel32.NewProc("FindResourceW")
	procSizeofResource             = modkernel32.NewProc("SizeofResource")
	procLockResource               = modkernel32.NewProc("LockResource")
	procLoadResource               = modkernel32.NewProc("LoadResource")
	procGetLastError               = modkernel32.NewProc("GetLastError")
	procOpenProcess                = modkernel32.NewProc("OpenProcess")
	procCloseHandle                = modkernel32.NewProc("CloseHandle")
	procCreateToolhelp32Snapshot   = modkernel32.NewProc("CreateToolhelp32Snapshot")
	procModule32First              = modkernel32.NewProc("Module32FirstW")
	procModule32Next               = modkernel32.NewProc("Module32NextW")
	procGetSystemTimes             = modkernel32.NewProc("GetSystemTimes")
	procGetConsoleScreenBufferInfo = modkernel32.NewProc("GetConsoleScreenBufferInfo")
	procSetConsoleTextAttribute    = modkernel32.NewProc("SetConsoleTextAttribute")
)

func GetModuleHandle(modulename string) HINSTANCE {
	var mn uintptr
	if modulename == "" {
		mn = 0
	} else {
		mn = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(modulename)))
	}
	ret, _, _ := procGetModuleHandle.Call(mn)
	return HINSTANCE(ret)
}

func MulDiv(number, numerator, denominator int) int {
	ret, _, _ := procMulDiv.Call(
		uintptr(number),
		uintptr(numerator),
		uintptr(denominator))

	return int(ret)
}

func GetCurrentThread() HANDLE {
	ret, _, _ := procGetCurrentThread.Call()

	return HANDLE(ret)
}

func GetUserDefaultLCID() uint32 {
	ret, _, _ := procGetUserDefaultLCID.Call()

	return uint32(ret)
}

func Lstrlen(lpString *uint16) int {
	ret, _, _ := procLstrlen.Call(uintptr(unsafe.Pointer(lpString)))

	return int(ret)
}

func Lstrcpy(buf []uint16, lpString *uint16) {
	procLstrcpy.Call(
		uintptr(unsafe.Pointer(&buf[0])),
		uintptr(unsafe.Pointer(lpString)))
}

func GlobalAlloc(uFlags uint, dwBytes uint32) HGLOBAL {
	ret, _, _ := procGlobalAlloc.Call(
		uintptr(uFlags),
		uintptr(dwBytes))

	if ret == 0 {
		panic("GlobalAlloc failed")
	}

	return HGLOBAL(ret)
}

func GlobalFree(hMem HGLOBAL) {
	ret, _, _ := procGlobalFree.Call(uintptr(hMem))

	if ret != 0 {
		panic("GlobalFree failed")
	}
}

func GlobalLock(hMem HGLOBAL) unsafe.Pointer {
	ret, _, _ := procGlobalLock.Call(uintptr(hMem))

	if ret == 0 {
		panic("GlobalLock failed")
	}

	return unsafe.Pointer(ret)
}

func GlobalUnlock(hMem HGLOBAL) bool {
	ret, _, _ := procGlobalUnlock.Call(uintptr(hMem))

	return ret != 0
}

func MoveMemory(destination, source unsafe.Pointer, length uint32) {
	procMoveMemory.Call(
		uintptr(unsafe.Pointer(destination)),
		uintptr(source),
		uintptr(length))
}

func FindResource(hModule HMODULE, lpName, lpType *uint16) (HRSRC, error) {
	ret, _, _ := procFindResource.Call(
		uintptr(hModule),
		uintptr(unsafe.Pointer(lpName)),
		uintptr(unsafe.Pointer(lpType)))

	if ret == 0 {
		return 0, syscall.GetLastError()
	}

	return HRSRC(ret), nil
}

func SizeofResource(hModule HMODULE, hResInfo HRSRC) uint32 {
	ret, _, _ := procSizeofResource.Call(
		uintptr(hModule),
		uintptr(hResInfo))

	if ret == 0 {
		panic("SizeofResource failed")
	}

	return uint32(ret)
}

func LockResource(hResData HGLOBAL) unsafe.Pointer {
	ret, _, _ := procLockResource.Call(uintptr(hResData))

	if ret == 0 {
		panic("LockResource failed")
	}

	return unsafe.Pointer(ret)
}

func LoadResource(hModule HMODULE, hResInfo HRSRC) HGLOBAL {
	ret, _, _ := procLoadResource.Call(
		uintptr(hModule),
		uintptr(hResInfo))

	if ret == 0 {
		panic("LoadResource failed")
	}

	return HGLOBAL(ret)
}

func GetLastError() uint32 {
	ret, _, _ := procGetLastError.Call()
	return uint32(ret)
}

func OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) HANDLE {
	inherit := 0
	if inheritHandle {
		inherit = 1
	}

	ret, _, _ := procOpenProcess.Call(
		uintptr(desiredAccess),
		uintptr(inherit),
		uintptr(processId))
	return HANDLE(ret)
}

func CloseHandle(object HANDLE) bool {
	ret, _, _ := procCloseHandle.Call(
		uintptr(object))
	return ret != 0
}

func CreateToolhelp32Snapshot(flags, processId uint32) HANDLE {
	ret, _, _ := procCreateToolhelp32Snapshot.Call(
		uintptr(flags),
		uintptr(processId))

	if ret <= 0 {
		return HANDLE(0)
	}

	return HANDLE(ret)
}

func Module32First(snapshot HANDLE, me *MODULEENTRY32) bool {
	ret, _, _ := procModule32First.Call(
		uintptr(snapshot),
		uintptr(unsafe.Pointer(me)))

	return ret != 0
}

func Module32Next(snapshot HANDLE, me *MODULEENTRY32) bool {
	ret, _, _ := procModule32Next.Call(
		uintptr(snapshot),
		uintptr(unsafe.Pointer(me)))

	return ret != 0
}

func GetSystemTimes(lpIdleTime, lpKernelTime, lpUserTime *FILETIME) bool {
	ret, _, _ := procGetSystemTimes.Call(
		uintptr(unsafe.Pointer(lpIdleTime)),
		uintptr(unsafe.Pointer(lpKernelTime)),
		uintptr(unsafe.Pointer(lpUserTime)))

	return ret != 0
}

func GetConsoleScreenBufferInfo(hConsoleOutput HANDLE) *CONSOLE_SCREEN_BUFFER_INFO {
	var csbi CONSOLE_SCREEN_BUFFER_INFO
	ret, _, _ := procGetConsoleScreenBufferInfo.Call(
		uintptr(hConsoleOutput),
		uintptr(unsafe.Pointer(&csbi)))
	if ret == 0 {
		return nil
	}
	return &csbi
}

func SetConsoleTextAttribute(hConsoleOutput HANDLE, wAttributes uint16) bool {
	ret, _, _ := procSetConsoleTextAttribute.Call(
		uintptr(hConsoleOutput),
		uintptr(wAttributes))
	return ret != 0
}
<commit_msg>Added GetLogicalDrives to kernel32.go<commit_after>// Copyright 2010-2012 The W32 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 w32

import (
	"syscall"
	"unsafe"
)

var (
	modkernel32 = syscall.NewLazyDLL("kernel32.dll")

	procGetModuleHandle            = modkernel32.NewProc("GetModuleHandleW")
	procMulDiv                     = modkernel32.NewProc("MulDiv")
	procGetCurrentThread           = modkernel32.NewProc("GetCurrentThread")
	procGetLogicalDrives           = modkernel32.NewProc("GetLogicalDrives")
	procGetUserDefaultLCID         = modkernel32.NewProc("GetUserDefaultLCID")
	procLstrlen                    = modkernel32.NewProc("lstrlenW")
	procLstrcpy                    = modkernel32.NewProc("lstrcpyW")
	procGlobalAlloc                = modkernel32.NewProc("GlobalAlloc")
	procGlobalFree                 = modkernel32.NewProc("GlobalFree")
	procGlobalLock                 = modkernel32.NewProc("GlobalLock")
	procGlobalUnlock               = modkernel32.NewProc("GlobalUnlock")
	procMoveMemory                 = modkernel32.NewProc("RtlMoveMemory")
	procFindResource               = modkernel32.NewProc("FindResourceW")
	procSizeofResource             = modkernel32.NewProc("SizeofResource")
	procLockResource               = modkernel32.NewProc("LockResource")
	procLoadResource               = modkernel32.NewProc("LoadResource")
	procGetLastError               = modkernel32.NewProc("GetLastError")
	procOpenProcess                = modkernel32.NewProc("OpenProcess")
	procCloseHandle                = modkernel32.NewProc("CloseHandle")
	procCreateToolhelp32Snapshot   = modkernel32.NewProc("CreateToolhelp32Snapshot")
	procModule32First              = modkernel32.NewProc("Module32FirstW")
	procModule32Next               = modkernel32.NewProc("Module32NextW")
	procGetSystemTimes             = modkernel32.NewProc("GetSystemTimes")
	procGetConsoleScreenBufferInfo = modkernel32.NewProc("GetConsoleScreenBufferInfo")
	procSetConsoleTextAttribute    = modkernel32.NewProc("SetConsoleTextAttribute")
)

func GetModuleHandle(modulename string) HINSTANCE {
	var mn uintptr
	if modulename == "" {
		mn = 0
	} else {
		mn = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(modulename)))
	}
	ret, _, _ := procGetModuleHandle.Call(mn)
	return HINSTANCE(ret)
}

func MulDiv(number, numerator, denominator int) int {
	ret, _, _ := procMulDiv.Call(
		uintptr(number),
		uintptr(numerator),
		uintptr(denominator))

	return int(ret)
}

func GetCurrentThread() HANDLE {
	ret, _, _ := procGetCurrentThread.Call()

	return HANDLE(ret)
}

func GetLogicalDrives() uint32 {
	ret, _, _ := procGetLogicalDrives.Call()

	return uint32(ret)
}

func GetUserDefaultLCID() uint32 {
	ret, _, _ := procGetUserDefaultLCID.Call()

	return uint32(ret)
}

func Lstrlen(lpString *uint16) int {
	ret, _, _ := procLstrlen.Call(uintptr(unsafe.Pointer(lpString)))

	return int(ret)
}

func Lstrcpy(buf []uint16, lpString *uint16) {
	procLstrcpy.Call(
		uintptr(unsafe.Pointer(&buf[0])),
		uintptr(unsafe.Pointer(lpString)))
}

func GlobalAlloc(uFlags uint, dwBytes uint32) HGLOBAL {
	ret, _, _ := procGlobalAlloc.Call(
		uintptr(uFlags),
		uintptr(dwBytes))

	if ret == 0 {
		panic("GlobalAlloc failed")
	}

	return HGLOBAL(ret)
}

func GlobalFree(hMem HGLOBAL) {
	ret, _, _ := procGlobalFree.Call(uintptr(hMem))

	if ret != 0 {
		panic("GlobalFree failed")
	}
}

func GlobalLock(hMem HGLOBAL) unsafe.Pointer {
	ret, _, _ := procGlobalLock.Call(uintptr(hMem))

	if ret == 0 {
		panic("GlobalLock failed")
	}

	return unsafe.Pointer(ret)
}

func GlobalUnlock(hMem HGLOBAL) bool {
	ret, _, _ := procGlobalUnlock.Call(uintptr(hMem))

	return ret != 0
}

func MoveMemory(destination, source unsafe.Pointer, length uint32) {
	procMoveMemory.Call(
		uintptr(unsafe.Pointer(destination)),
		uintptr(source),
		uintptr(length))
}

func FindResource(hModule HMODULE, lpName, lpType *uint16) (HRSRC, error) {
	ret, _, _ := procFindResource.Call(
		uintptr(hModule),
		uintptr(unsafe.Pointer(lpName)),
		uintptr(unsafe.Pointer(lpType)))

	if ret == 0 {
		return 0, syscall.GetLastError()
	}

	return HRSRC(ret), nil
}

func SizeofResource(hModule HMODULE, hResInfo HRSRC) uint32 {
	ret, _, _ := procSizeofResource.Call(
		uintptr(hModule),
		uintptr(hResInfo))

	if ret == 0 {
		panic("SizeofResource failed")
	}

	return uint32(ret)
}

func LockResource(hResData HGLOBAL) unsafe.Pointer {
	ret, _, _ := procLockResource.Call(uintptr(hResData))

	if ret == 0 {
		panic("LockResource failed")
	}

	return unsafe.Pointer(ret)
}

func LoadResource(hModule HMODULE, hResInfo HRSRC) HGLOBAL {
	ret, _, _ := procLoadResource.Call(
		uintptr(hModule),
		uintptr(hResInfo))

	if ret == 0 {
		panic("LoadResource failed")
	}

	return HGLOBAL(ret)
}

func GetLastError() uint32 {
	ret, _, _ := procGetLastError.Call()
	return uint32(ret)
}

func OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) HANDLE {
	inherit := 0
	if inheritHandle {
		inherit = 1
	}

	ret, _, _ := procOpenProcess.Call(
		uintptr(desiredAccess),
		uintptr(inherit),
		uintptr(processId))
	return HANDLE(ret)
}

func CloseHandle(object HANDLE) bool {
	ret, _, _ := procCloseHandle.Call(
		uintptr(object))
	return ret != 0
}

func CreateToolhelp32Snapshot(flags, processId uint32) HANDLE {
	ret, _, _ := procCreateToolhelp32Snapshot.Call(
		uintptr(flags),
		uintptr(processId))

	if ret <= 0 {
		return HANDLE(0)
	}

	return HANDLE(ret)
}

func Module32First(snapshot HANDLE, me *MODULEENTRY32) bool {
	ret, _, _ := procModule32First.Call(
		uintptr(snapshot),
		uintptr(unsafe.Pointer(me)))

	return ret != 0
}

func Module32Next(snapshot HANDLE, me *MODULEENTRY32) bool {
	ret, _, _ := procModule32Next.Call(
		uintptr(snapshot),
		uintptr(unsafe.Pointer(me)))

	return ret != 0
}

func GetSystemTimes(lpIdleTime, lpKernelTime, lpUserTime *FILETIME) bool {
	ret, _, _ := procGetSystemTimes.Call(
		uintptr(unsafe.Pointer(lpIdleTime)),
		uintptr(unsafe.Pointer(lpKernelTime)),
		uintptr(unsafe.Pointer(lpUserTime)))

	return ret != 0
}

func GetConsoleScreenBufferInfo(hConsoleOutput HANDLE) *CONSOLE_SCREEN_BUFFER_INFO {
	var csbi CONSOLE_SCREEN_BUFFER_INFO
	ret, _, _ := procGetConsoleScreenBufferInfo.Call(
		uintptr(hConsoleOutput),
		uintptr(unsafe.Pointer(&csbi)))
	if ret == 0 {
		return nil
	}
	return &csbi
}

func SetConsoleTextAttribute(hConsoleOutput HANDLE, wAttributes uint16) bool {
	ret, _, _ := procSetConsoleTextAttribute.Call(
		uintptr(hConsoleOutput),
		uintptr(wAttributes))
	return ret != 0
}
<|endoftext|>


<commit_before>/*
 * This file is part of remco.
 * © 2016 The Remco Authors
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

package template

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	"github.com/HeavyHorst/easyKV/mock"
	"github.com/HeavyHorst/remco/executor"

	. "gopkg.in/check.v1"
)

const tmplString string = "{{ getallkvs() | toPrettyJSON }}"

type ResourceSuite struct {
	templateFile string
	backend      Backend
	renderer     *Renderer
	resource     *Resource
}

var _ = Suite(&ResourceSuite{})

func (s *ResourceSuite) SetUpSuite(t *C) {
	// create simple template file
	f, err := ioutil.TempFile("", "template")
	t.Assert(err, IsNil)
	defer f.Close()
	_, err = f.WriteString(tmplString)
	t.Assert(err, IsNil)
	s.templateFile = f.Name()

	// create a backend
	s.backend = Backend{
		Name:     "mock",
		Onetime:  false,
		Watch:    true,
		Prefix:   "/",
		Interval: 1,
		Keys:     []string{"/"},
	}
	s.backend.ReadWatcher, _ = mock.New(nil, map[string]string{"/some/path/data": "someData"})

	// create a renderer
	s.renderer = &Renderer{
		Src:       s.templateFile,
		Dst:       "/tmp/remco-basic-test.conf",
		CheckCmd:  "exit 0",
		ReloadCmd: "exit 0",
	}

	exec := executor.New("", "", "", 0, 0, nil)
	res, err := NewResource([]Backend{s.backend}, []*Renderer{s.renderer}, "test", exec)
	t.Assert(err, IsNil)
	s.resource = res
}

func (s *ResourceSuite) TearDownSuite(t *C) {
	err := os.Remove(s.templateFile)
	t.Check(err, IsNil)
}

func (s *ResourceSuite) TestNewResource(t *C) {
	t.Check(s.resource.backends, HasLen, 1)
	t.Check(s.resource.backends[0].store, NotNil)
	t.Check(s.resource.store, NotNil)
	t.Check(s.resource.logger, NotNil)

	fm := newFuncMap()
	addFuncs(fm, s.resource.store.FuncMap)
	t.Check(s.resource.funcMap, HasLen, len(fm))
	t.Check(s.resource.sources, DeepEquals, []*Renderer{s.renderer})
	t.Check(s.resource.SignalChan, NotNil)
}

func (s *ResourceSuite) TestClose(t *C) {
	s.resource.Close()
}

func (s *ResourceSuite) TestSetVars(t *C) {
	err := s.resource.setVars(s.resource.backends[0])
	t.Check(err, IsNil)
	// the backend trie and the global tree should hold the same values
	t.Check(s.resource.store.GetAllKVs(), DeepEquals, s.resource.backends[0].store.GetAllKVs())
}

func (s *ResourceSuite) TestCreateStageFileAndSync(t *C) {
	_, err := s.resource.createStageFileAndSync()
	t.Check(err, IsNil)
}

func (s *ResourceSuite) TestProcess(t *C) {
	_, err := s.resource.process(s.resource.backends)
	t.Check(err, IsNil)
}

func (s *ResourceSuite) TestMonitor(t *C) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go func() {
		time.Sleep(5 * time.Second)
		cancel()
	}()

	s.resource.Monitor(ctx)
	t.Check(s.resource.Failed, Equals, false)
}

func (s *ResourceSuite) TestMonitorWithBackendError(t *C) {
	s.resource.backends[0].ReadWatcher.(*mock.Client).Err = fmt.Errorf("some error")
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go func() {
		time.Sleep(5 * time.Second)
		cancel()
	}()

	s.resource.Monitor(ctx)
	t.Check(s.resource.Failed, Equals, false)
	s.resource.backends[0].ReadWatcher.(*mock.Client).Err = nil
}
<commit_msg>one more test<commit_after>/*
 * This file is part of remco.
 * © 2016 The Remco Authors
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

package template

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	"github.com/HeavyHorst/easyKV/mock"
	"github.com/HeavyHorst/remco/executor"

	. "gopkg.in/check.v1"
)

const (
	tmplString string = "{{ getallkvs() | toPrettyJSON }}"
	tmplFile   string = `[
    {
        "Key": "/some/path/data",
        "Value": "someData"
    }
]`
)

type ResourceSuite struct {
	templateFile string
	backend      Backend
	renderer     *Renderer
	resource     *Resource
}

var _ = Suite(&ResourceSuite{})

func (s *ResourceSuite) SetUpSuite(t *C) {
	// create simple template file
	f, err := ioutil.TempFile("", "template")
	t.Assert(err, IsNil)
	defer f.Close()
	_, err = f.WriteString(tmplString)
	t.Assert(err, IsNil)
	s.templateFile = f.Name()

	// create a backend
	s.backend = Backend{
		Name:     "mock",
		Onetime:  false,
		Watch:    true,
		Prefix:   "/",
		Interval: 1,
		Keys:     []string{"/"},
	}
	s.backend.ReadWatcher, _ = mock.New(nil, map[string]string{"/some/path/data": "someData"})

	// create a renderer
	s.renderer = &Renderer{
		Src:       s.templateFile,
		Dst:       "/tmp/remco-basic-test.conf",
		CheckCmd:  "exit 0",
		ReloadCmd: "exit 0",
	}

	exec := executor.New("", "", "", 0, 0, nil)
	res, err := NewResource([]Backend{s.backend}, []*Renderer{s.renderer}, "test", exec)
	t.Assert(err, IsNil)
	s.resource = res
}

func (s *ResourceSuite) TearDownSuite(t *C) {
	err := os.Remove(s.templateFile)
	t.Check(err, IsNil)
}

func (s *ResourceSuite) TestNewResource(t *C) {
	t.Check(s.resource.backends, HasLen, 1)
	t.Check(s.resource.backends[0].store, NotNil)
	t.Check(s.resource.store, NotNil)
	t.Check(s.resource.logger, NotNil)

	fm := newFuncMap()
	addFuncs(fm, s.resource.store.FuncMap)
	t.Check(s.resource.funcMap, HasLen, len(fm))
	t.Check(s.resource.sources, DeepEquals, []*Renderer{s.renderer})
	t.Check(s.resource.SignalChan, NotNil)
}

func (s *ResourceSuite) TestClose(t *C) {
	s.resource.Close()
}

func (s *ResourceSuite) TestSetVars(t *C) {
	err := s.resource.setVars(s.resource.backends[0])
	t.Check(err, IsNil)
	// the backend trie and the global tree should hold the same values
	t.Check(s.resource.store.GetAllKVs(), DeepEquals, s.resource.backends[0].store.GetAllKVs())
}

func (s *ResourceSuite) TestCreateStageFileAndSync(t *C) {
	_, err := s.resource.createStageFileAndSync()
	t.Check(err, IsNil)
}

func (s *ResourceSuite) TestProcess(t *C) {
	_, err := s.resource.process(s.resource.backends)
	t.Check(err, IsNil)

	data, err := ioutil.ReadFile("/tmp/remco-basic-test.conf")
	t.Assert(err, IsNil)
	t.Check(string(data), Equals, tmplFile)
}

func (s *ResourceSuite) TestMonitor(t *C) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go func() {
		time.Sleep(5 * time.Second)
		cancel()
	}()

	s.resource.Monitor(ctx)
	t.Check(s.resource.Failed, Equals, false)
}

func (s *ResourceSuite) TestMonitorWithBackendError(t *C) {
	s.resource.backends[0].ReadWatcher.(*mock.Client).Err = fmt.Errorf("some error")
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go func() {
		time.Sleep(5 * time.Second)
		cancel()
	}()

	s.resource.Monitor(ctx)
	t.Check(s.resource.Failed, Equals, false)
	s.resource.backends[0].ReadWatcher.(*mock.Client).Err = nil
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Elliot Peele <elliot@bentlogic.net>
 *
 * 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 molecule

import (
	"compress/gzip"
	"io"
	"io/ioutil"
	"os"
	"time"

	"github.com/elliotpeele/deepfreeze/atom"
	"github.com/elliotpeele/deepfreeze/log"
	"github.com/elliotpeele/deepfreeze/utils"
	"github.com/satori/go.uuid"
)

type Molecule struct {
	Id             string       `json:"id"`
	Path           string       `json:"path"`
	Hash           string       `json:"hash"`
	Atoms          []*atom.Atom `json:"-"`
	CreatedAt      time.Time    `json:"created_at"`
	OriginalSize   int64        `json:"size"`
	CompressedSize int64        `json:"compressed_size"`
	EncryptedSize  int64        `json:"encrypted_size"`

	finfo           os.FileInfo
	compressed_info os.FileInfo
	encrypted_info  os.FileInfo
	fobj            *os.File
	read_size       int64
}

func New(path string, hash string) (*Molecule, error) {
	info, err := os.Stat(path)
	if err != nil {
		return nil, err
	}
	return &Molecule{
		Id:           uuid.NewV4().String(),
		Path:         path,
		Hash:         hash,
		CreatedAt:    time.Now(),
		OriginalSize: info.Size(),
		finfo:        info,
	}, nil
}

func (m *Molecule) Open() error {
	log.Debugf("opening %s", m.Path)
	f, err := os.Open(m.Path)
	if err != nil {
		return err
	}
	m.fobj = f
	return nil
}

func (m *Molecule) Read(p []byte) (n int, err error) {
	n, err = m.fobj.Read(p)
	m.read_size += int64(n)
	return
}

func (m *Molecule) Seek(offset int64, whence int) (int64, error) {
	return m.fobj.Seek(offset, whence)
}

func (m *Molecule) Close() error {
	return m.fobj.Close()
}

func (m *Molecule) Size() int64 {
	switch {
	case m.EncryptedSize != 0:
		return m.EncryptedSize - m.read_size
	case m.CompressedSize != 0:
		return m.CompressedSize - m.read_size
	case m.OriginalSize != 0:
		return m.OriginalSize - m.read_size
	default:
		return -1
	}
}

func (m *Molecule) Info() os.FileInfo {
	switch {
	case m.encrypted_info != nil:
		log.Debug("using encrypted info")
		return m.encrypted_info
	case m.compressed_info != nil:
		log.Debug("using compressed info")
		return m.compressed_info
	default:
		log.Debug("using orignal info")
		return m.finfo
	}
}

func (m *Molecule) OrigInfo() os.FileInfo {
	return m.finfo
}

func (m *Molecule) Header() ([]byte, error) {
	return utils.ToJSON(m)
}

func (m *Molecule) NewAtom(cubeId string, size int64) *atom.Atom {
	a := atom.New(m.Id, cubeId, size)
	m.Atoms = append(m.Atoms, a)
	return a
}

func (m *Molecule) Encrypt() error {
	log.Debugf("encrypting %s", m.Path)
	log.Warn("encrytion not supported")
	return nil
}

func (m *Molecule) Compress() error {
	log.Debugf("compressing %s", m.Path)
	// Get a tmp file to compress into.
	tmpf, err := ioutil.TempFile("", "deepfreeze")
	if err != nil {
		return err
	}
	// Compress orignal file.
	w, err := gzip.NewWriterLevel(tmpf, gzip.BestSpeed)
	if err != nil {
		return err
	}
	if _, err := io.Copy(w, m.fobj); err != nil {
		return err
	}
	// Flush the compressor once complete.
	if err := w.Close(); err != nil {
		return err
	}
	// Rewind tmp file.
	if _, err := tmpf.Seek(0, 0); err != nil {
		return err
	}
	// Check and store size.
	info, err := tmpf.Stat()
	if err != nil {
		return err
	}
	m.CompressedSize = info.Size()
	m.compressed_info = info
	// Close underlying file object.
	m.fobj.Close()
	// Replace with tmp file.
	m.fobj = tmpf
	return nil
}
<commit_msg>Cleanup tmp files on close.<commit_after>/*
 * Copyright (c) Elliot Peele <elliot@bentlogic.net>
 *
 * 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 molecule

import (
	"compress/gzip"
	"io"
	"io/ioutil"
	"os"
	"time"

	"github.com/elliotpeele/deepfreeze/atom"
	"github.com/elliotpeele/deepfreeze/log"
	"github.com/elliotpeele/deepfreeze/utils"
	"github.com/satori/go.uuid"
)

type Molecule struct {
	Id           string       `json:"id"`
	Path         string       `json:"path"`
	Hash         string       `json:"hash"`
	Atoms        []*atom.Atom `json:"-"`
	CreatedAt    time.Time    `json:"created_at"`
	OriginalSize int64        `json:"size"`

	cur_size        int64
	orig_info       os.FileInfo
	cur_info        os.FileInfo
	fobj            *os.File
	read_size       int64
	delete_on_close bool
}

func New(path string, hash string) (*Molecule, error) {
	info, err := os.Stat(path)
	if err != nil {
		return nil, err
	}
	return &Molecule{
		Id:              uuid.NewV4().String(),
		Path:            path,
		Hash:            hash,
		CreatedAt:       time.Now(),
		OriginalSize:    info.Size(),
		orig_info:       info,
		cur_info:        info,
		delete_on_close: false,
	}, nil
}

func (m *Molecule) Open() error {
	log.Debugf("opening %s", m.Path)
	f, err := os.Open(m.Path)
	if err != nil {
		return err
	}
	m.fobj = f
	return nil
}

func (m *Molecule) Read(p []byte) (n int, err error) {
	n, err = m.fobj.Read(p)
	m.read_size += int64(n)
	return
}

func (m *Molecule) Seek(offset int64, whence int) (int64, error) {
	return m.fobj.Seek(offset, whence)
}

func (m *Molecule) Close() error {
	if err := m.fobj.Close(); err != nil {
		return err
	}
	if m.delete_on_close {
		log.Debugf("deleting %s", m.fobj.Name())
		if err := os.Remove(m.fobj.Name()); err != nil {
			return err
		}
	}
	return nil
}

func (m *Molecule) Size() int64 {
	return m.cur_size - m.read_size
}

func (m *Molecule) Info() os.FileInfo {
	return m.cur_info
}

func (m *Molecule) OrigInfo() os.FileInfo {
	return m.orig_info
}

func (m *Molecule) Header() ([]byte, error) {
	return utils.ToJSON(m)
}

func (m *Molecule) NewAtom(cubeId string, size int64) *atom.Atom {
	a := atom.New(m.Id, cubeId, size)
	m.Atoms = append(m.Atoms, a)
	return a
}

func (m *Molecule) Encrypt() error {
	log.Debugf("encrypting %s", m.Path)
	log.Warn("encrytion not supported")
	return nil
}

func (m *Molecule) Compress() error {
	log.Debugf("compressing %s", m.Path)
	// Get a tmp file to compress into.
	tmpf, err := ioutil.TempFile("", "deepfreeze")
	if err != nil {
		return err
	}
	// Compress orignal file.
	w, err := gzip.NewWriterLevel(tmpf, gzip.BestSpeed)
	if err != nil {
		return err
	}
	if _, err := io.Copy(w, m.fobj); err != nil {
		return err
	}
	// Flush the compressor once complete.
	if err := w.Close(); err != nil {
		return err
	}
	// Rewind tmp file.
	if _, err := tmpf.Seek(0, 0); err != nil {
		return err
	}
	// Check and store size.
	info, err := tmpf.Stat()
	if err != nil {
		return err
	}
	m.cur_size = info.Size()
	m.cur_info = info
	// Close underlying file object.
	m.fobj.Close()
	// Replace with tmp file.
	m.fobj = tmpf
	// Mark tmp file for deletion.
	m.delete_on_close = true
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package ingress

import (
	"context"
	"testing"

	"k8s.io/apimachinery/pkg/util/intstr"
	"knative.dev/networking/pkg/apis/networking"
	"knative.dev/networking/pkg/apis/networking/v1alpha1"
	"knative.dev/networking/test"
)

// TestRule verifies that an Ingress properly dispatches to backends based on different rules.
func TestRule(t *testing.T) {
	t.Parallel()
	ctx, clients := context.Background(), test.Setup(t)

	fooName, fooPort, _ := CreateRuntimeService(ctx, t, clients, networking.ServicePortNameHTTP1)
	barName, barPort, _ := CreateRuntimeService(ctx, t, clients, networking.ServicePortNameHTTP1)

	_, client, _ := CreateIngressReady(ctx, t, clients, v1alpha1.IngressSpec{
		Rules: []v1alpha1.IngressRule{{
			Hosts:      []string{fooName + ".example.com"},
			Visibility: v1alpha1.IngressVisibilityExternalIP,
			HTTP: &v1alpha1.HTTPIngressRuleValue{
				Paths: []v1alpha1.HTTPIngressPath{{
					Splits: []v1alpha1.IngressBackendSplit{{
						IngressBackend: v1alpha1.IngressBackend{
							ServiceName:      fooName,
							ServiceNamespace: test.ServingNamespace,
							ServicePort:      intstr.FromInt(fooPort),
						},
					}},
				}},
			},
		}, {
			Hosts:      []string{barName + ".example.com"},
			Visibility: v1alpha1.IngressVisibilityExternalIP,
			HTTP: &v1alpha1.HTTPIngressRuleValue{
				Paths: []v1alpha1.HTTPIngressPath{{
					Splits: []v1alpha1.IngressBackendSplit{{
						IngressBackend: v1alpha1.IngressBackend{
							ServiceName:      barName,
							ServiceNamespace: test.ServingNamespace,
							ServicePort:      intstr.FromInt(barPort),
						},
					}},
				}},
			},
		}},
	})

	RuntimeRequest(ctx, t, client, "http://"+fooName+".example.com")
	RuntimeRequest(ctx, t, client, "http://"+barName+".example.com")
}
<commit_msg>Append headers to TestRule to verify we hit expected backend (#385)<commit_after>/*
Copyright 2020 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package ingress

import (
	"context"
	"testing"

	"k8s.io/apimachinery/pkg/util/intstr"
	"knative.dev/networking/pkg/apis/networking"
	"knative.dev/networking/pkg/apis/networking/v1alpha1"
	"knative.dev/networking/test"
)

// TestRule verifies that an Ingress properly dispatches to backends based on different rules.
func TestRule(t *testing.T) {
	t.Parallel()
	ctx, clients := context.Background(), test.Setup(t)

	// Use a pre-split injected header to establish which rule we are sending traffic to.
	const headerName = "Foo-Bar-Baz"

	fooName, fooPort, _ := CreateRuntimeService(ctx, t, clients, networking.ServicePortNameHTTP1)
	barName, barPort, _ := CreateRuntimeService(ctx, t, clients, networking.ServicePortNameHTTP1)

	_, client, _ := CreateIngressReady(ctx, t, clients, v1alpha1.IngressSpec{
		Rules: []v1alpha1.IngressRule{{
			Hosts:      []string{fooName + ".example.com"},
			Visibility: v1alpha1.IngressVisibilityExternalIP,
			HTTP: &v1alpha1.HTTPIngressRuleValue{
				Paths: []v1alpha1.HTTPIngressPath{{
					Splits: []v1alpha1.IngressBackendSplit{{
						IngressBackend: v1alpha1.IngressBackend{
							ServiceName:      fooName,
							ServiceNamespace: test.ServingNamespace,
							ServicePort:      intstr.FromInt(fooPort),
						},
					}},
					// Append different headers to each rule, which lets us identify
					// which backend we hit.
					AppendHeaders: map[string]string{
						headerName: fooName,
					},
				}},
			},
		}, {
			Hosts:      []string{barName + ".example.com"},
			Visibility: v1alpha1.IngressVisibilityExternalIP,
			HTTP: &v1alpha1.HTTPIngressRuleValue{
				Paths: []v1alpha1.HTTPIngressPath{{
					Splits: []v1alpha1.IngressBackendSplit{{
						IngressBackend: v1alpha1.IngressBackend{
							ServiceName:      barName,
							ServiceNamespace: test.ServingNamespace,
							ServicePort:      intstr.FromInt(barPort),
						},
					}},
					AppendHeaders: map[string]string{
						headerName: barName,
					},
				}},
			},
		}},
	})

	ri := RuntimeRequest(ctx, t, client, "http://"+fooName+".example.com")
	if got := ri.Request.Headers.Get(headerName); got != fooName {
		t.Errorf("Header[Host] = %q, wanted %q", got, fooName)
	}

	ri = RuntimeRequest(ctx, t, client, "http://"+barName+".example.com")
	if got := ri.Request.Headers.Get(headerName); got != barName {
		t.Errorf("Header[Host] = %q, wanted %q", got, barName)
	}
}
<|endoftext|>


<commit_before>package conf

import (
	"fmt"
	"io/ioutil"
	"runtime"
	"strings"

	"github.com/StackExchange/tsaf/conf/parse"
	"github.com/StackExchange/tsaf/expr"
)

type Conf struct {
	Vars
	Name        string // Config file name
	WebDir      string // Static content web directory: web
	TsdbHost    string // OpenTSDB relay and query destination: ny-devtsdb04:4242
	RelayListen string // OpenTSDB relay listen address: :4242
	HttpListen  string // Web server listen address: :80
	Templates   map[string]*Template
	Alerts      map[string]*Alert

	tree *parse.Tree
	node parse.Node
}

// at marks the state to be on node n, for error reporting.
func (c *Conf) at(node parse.Node) {
	c.node = node
}

func (c *Conf) error(err error) {
	c.errorf(err.Error())
}

// errorf formats the error and terminates processing.
func (c *Conf) errorf(format string, args ...interface{}) {
	if c.node == nil {
		format = fmt.Sprintf("conf: %s: %s", c.Name, format)
	} else {
		location, context := c.tree.ErrorContext(c.node)
		format = fmt.Sprintf("conf: %s: at <%s>: %s", location, context, format)
	}
	panic(fmt.Errorf(format, args...))
}

// errRecover is the handler that turns panics into returns from the top
// level of Parse.
func errRecover(errp *error) {
	e := recover()
	if e != nil {
		switch err := e.(type) {
		case runtime.Error:
			panic(e)
		case error:
			*errp = err
		default:
			panic(e)
		}
	}
}

type Alert struct {
	Vars
	Template
	Name       string
	Owner      string
	Crit, Warn *expr.Expr
	Overriders []*Alert
	Overrides  *Alert

	crit, warn string
	template   string
	override   string
}

type Template struct {
	Vars
	Name    string
	Body    string
	Subject string
}

type Vars map[string]string

func ParseFile(fname string) (*Conf, error) {
	f, err := ioutil.ReadFile(fname)
	if err != nil {
		return nil, err
	}
	return New(fname, string(f))
}

func New(name, text string) (c *Conf, err error) {
	defer errRecover(&err)
	t, e := parse.Parse(name, text)
	if e != nil {
		c.error(err)
	}
	c = &Conf{
		tree:        t,
		Name:        name,
		HttpListen:  ":8070",
		RelayListen: ":4242",
		WebDir:      "web",
		Vars:        make(map[string]string),
		Templates:   make(map[string]*Template),
		Alerts:      make(map[string]*Alert),
	}
	for _, n := range t.Root.Nodes {
		c.at(n)
		switch n := n.(type) {
		case *parse.PairNode:
			c.loadGlobal(n)
		case *parse.SectionNode:
			c.loadSection(n)
		default:
			c.errorf("unexpected parse node %s", n)
		}
	}
	if c.TsdbHost == "" {
		c.at(nil)
		c.errorf("tsdbHost required")
	}
	return
}

func (c *Conf) loadGlobal(p *parse.PairNode) {
	v := p.Val.Text
	switch k := p.Key.Text; k {
	case "tsdbHost":
		c.TsdbHost = v
	case "httpListen":
		c.HttpListen = v
	case "relayListen":
		c.RelayListen = v
	case "c.webDir":
		c.WebDir = v
	default:
		if !strings.HasPrefix(k, "$") {
			c.errorf("unknown key %s", k)
		}
		c.Vars[k] = v
	}
}

func (c *Conf) loadSection(s *parse.SectionNode) {
	sp := strings.SplitN(s.Name.Text, ".", 2)
	if len(sp) != 2 {
		c.errorf("expected . in section name")
	} else if sp[0] == "template" {
		c.loadTemplate(sp[1], s.Nodes)
	} else if sp[0] == "alert" {
		c.loadAlert(sp[1], s.Nodes)
	} else {
		c.errorf("unknown section type: %s", sp[0])
	}
}

func (c *Conf) loadTemplate(name string, nodes []*parse.PairNode) {
	if _, ok := c.Templates[name]; ok {
		c.errorf("duplicate template name: %s", name)
	}
	t := Template{
		Vars: make(map[string]string),
	}
	for _, p := range nodes {
		c.at(p)
		v := p.Val.Text
		switch k := p.Key.Text; k {
		case "body":
			t.Body = k
		case "subject":
			t.Subject = k
		default:
			if !strings.HasPrefix(k, "$") {
				c.errorf("unknown key %s", k)
			}
			t.Vars[k] = v
		}
	}
	c.Templates[name] = &t
}

func (c *Conf) loadAlert(name string, nodes []*parse.PairNode) {
	if _, ok := c.Alerts[name]; ok {
		c.errorf("duplicate template name: %s", name)
	}
	a := Alert{
		Vars: make(map[string]string),
	}
	for _, p := range nodes {
		c.at(p)
		v := p.Val.Text
		switch k := p.Key.Text; k {
		case "owner":
			a.Owner = v
		case "template":
			a.template = v
		case "override":
			a.override = v
		case "crit":
			a.crit = v
		case "warn":
			a.warn = v
		default:
			if !strings.HasPrefix(k, "$") {
				c.errorf("unknown key %s", k)
			}
			a.Vars[k] = v
		}
	}
	c.Alerts[name] = &a
}
<commit_msg>Variable expansion<commit_after>package conf

import (
	"fmt"
	"io/ioutil"
	"regexp"
	"runtime"
	"strings"

	"github.com/StackExchange/tsaf/conf/parse"
	"github.com/StackExchange/tsaf/expr"
)

type Conf struct {
	Vars
	Name        string // Config file name
	WebDir      string // Static content web directory: web
	TsdbHost    string // OpenTSDB relay and query destination: ny-devtsdb04:4242
	RelayListen string // OpenTSDB relay listen address: :4242
	HttpListen  string // Web server listen address: :80
	Templates   map[string]*Template
	Alerts      map[string]*Alert

	tree *parse.Tree
	node parse.Node
}

// at marks the state to be on node n, for error reporting.
func (c *Conf) at(node parse.Node) {
	c.node = node
}

func (c *Conf) error(err error) {
	c.errorf(err.Error())
}

// errorf formats the error and terminates processing.
func (c *Conf) errorf(format string, args ...interface{}) {
	if c.node == nil {
		format = fmt.Sprintf("conf: %s: %s", c.Name, format)
	} else {
		location, context := c.tree.ErrorContext(c.node)
		format = fmt.Sprintf("conf: %s: at <%s>: %s", location, context, format)
	}
	panic(fmt.Errorf(format, args...))
}

// errRecover is the handler that turns panics into returns from the top
// level of Parse.
func errRecover(errp *error) {
	e := recover()
	if e != nil {
		switch err := e.(type) {
		case runtime.Error:
			panic(e)
		case error:
			*errp = err
		default:
			panic(e)
		}
	}
}

type Alert struct {
	Vars
	Template
	Name       string
	Owner      string
	Crit, Warn *expr.Expr
	Overriders []*Alert
	Overrides  *Alert

	crit, warn string
	template   string
	override   string
}

type Template struct {
	Vars
	Name    string
	Body    string
	Subject string
}

type Vars map[string]string

func ParseFile(fname string) (*Conf, error) {
	f, err := ioutil.ReadFile(fname)
	if err != nil {
		return nil, err
	}
	return New(fname, string(f))
}

func New(name, text string) (c *Conf, err error) {
	defer errRecover(&err)
	t, e := parse.Parse(name, text)
	if e != nil {
		c.error(err)
	}
	c = &Conf{
		tree:        t,
		Name:        name,
		HttpListen:  ":8070",
		RelayListen: ":4242",
		WebDir:      "web",
		Vars:        make(map[string]string),
		Templates:   make(map[string]*Template),
		Alerts:      make(map[string]*Alert),
	}
	for _, n := range t.Root.Nodes {
		c.at(n)
		switch n := n.(type) {
		case *parse.PairNode:
			c.loadGlobal(n)
		case *parse.SectionNode:
			c.loadSection(n)
		default:
			c.errorf("unexpected parse node %s", n)
		}
	}
	if c.TsdbHost == "" {
		c.at(nil)
		c.errorf("tsdbHost required")
	}
	return
}

func (c *Conf) loadGlobal(p *parse.PairNode) {
	v := p.Val.Text
	switch k := p.Key.Text; k {
	case "tsdbHost":
		c.TsdbHost = c.expand(v, nil)
	case "httpListen":
		c.HttpListen = c.expand(v, nil)
	case "relayListen":
		c.RelayListen = c.expand(v, nil)
	case "c.webDir":
		c.WebDir = c.expand(v, nil)
	default:
		if !strings.HasPrefix(k, "$") {
			c.errorf("unknown key %s", k)
		}
		c.Vars[k] = c.expand(v, nil)
	}
}

func (c *Conf) loadSection(s *parse.SectionNode) {
	sp := strings.SplitN(s.Name.Text, ".", 2)
	if len(sp) != 2 {
		c.errorf("expected . in section name")
	} else if sp[0] == "template" {
		c.loadTemplate(sp[1], s.Nodes)
	} else if sp[0] == "alert" {
		c.loadAlert(sp[1], s.Nodes)
	} else {
		c.errorf("unknown section type: %s", sp[0])
	}
}

func (c *Conf) loadTemplate(name string, nodes []*parse.PairNode) {
	if _, ok := c.Templates[name]; ok {
		c.errorf("duplicate template name: %s", name)
	}
	t := Template{
		Vars: make(map[string]string),
	}
	for _, p := range nodes {
		c.at(p)
		v := p.Val.Text
		switch k := p.Key.Text; k {
		case "body":
			t.Body = c.expand(v, t.Vars)
		case "subject":
			t.Subject = c.expand(v, t.Vars)
		default:
			if !strings.HasPrefix(k, "$") {
				c.errorf("unknown key %s", k)
			}
			t.Vars[k] = c.expand(v, t.Vars)
		}
	}
	c.Templates[name] = &t
}

func (c *Conf) loadAlert(name string, nodes []*parse.PairNode) {
	if _, ok := c.Alerts[name]; ok {
		c.errorf("duplicate template name: %s", name)
	}
	a := Alert{
		Vars: make(map[string]string),
	}
	for _, p := range nodes {
		c.at(p)
		v := p.Val.Text
		switch k := p.Key.Text; k {
		case "owner":
			a.Owner = c.expand(v, a.Vars)
		case "template":
			a.template = c.expand(v, a.Vars)
		case "override":
			a.override = c.expand(v, a.Vars)
		case "crit":
			a.crit = c.expand(v, a.Vars)
		case "warn":
			a.warn = c.expand(v, a.Vars)
		default:
			if !strings.HasPrefix(k, "$") {
				c.errorf("unknown key %s", k)
			}
			a.Vars[k] = c.expand(v, a.Vars)
		}
	}
	c.Alerts[name] = &a
}

var exRE = regexp.MustCompile(`\$\w+`)

func (c *Conf) expand(v string, vars map[string]string) string {
	v = exRE.ReplaceAllStringFunc(v, func(s string) string {
		if vars != nil {
			if n, ok := vars[s]; ok {
				return n
			}
		}
		n, ok := c.Vars[s]
		if !ok {
			c.errorf("unknown variable %s", s)
		}
		return n
	})
	return v
}<|endoftext|>


<commit_before>package middleware

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

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

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

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

		// Process request
		c.Next()

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

		// abort if theres no ib
		if ib == "" {
			c.Abort()
			return
		}

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

		// set our data
		request := RequestType{
			Ib:        ib,
			Ip:        c.ClientIP(),
			Path:      path,
			Status:    c.Writer.Status(),
			Latency:   latency,
			Useragent: req.UserAgent(),
			Referer:   req.Referer(),
		}

		out := bufio.NewWriter(os.Stdout)

		// print headers
		fmt.Fprintf(out, "%s\n%s\n", request, req.Header)

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

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

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

var testout = bufio.NewWriter(os.Stdout)

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

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

		// Process request
		c.Next()

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

		// abort if theres no ib
		if ib == "" {
			c.Abort()
			return
		}

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

		// set our data
		request := RequestType{
			Ib:        ib,
			Ip:        c.ClientIP(),
			Path:      path,
			Status:    c.Writer.Status(),
			Latency:   latency,
			Useragent: req.UserAgent(),
			Referer:   req.Referer(),
		}

		// print headers
		fmt.Fprintf(testout, "%s\n%s\n", request, req.Header)

	}
}
<|endoftext|>


<commit_before>package client

import (
	"context"
	"fmt"
	"io/ioutil"
	"net/http"

	"github.com/google/go-github/v31/github"
	"github.com/kyma-project/test-infra/development/types"
	"golang.org/x/oauth2"
	"gopkg.in/yaml.v2"
)

const (
	SapToolsGithubURL  = "https://github.tools.sap/"
	ProwGithubProxyURL = "http://ghproxy"
)

// SapToolsClient wraps kyma implementation github Client and provides additional methods.
type SapToolsClient struct {
	*Client
}

// Client wraps google github Client and provides additional methods.
type Client struct {
	*github.Client
}

// newOauthHttpClient creates HTTP client with oauth authentication.
// It authenticates with Bearer token.
func newOauthHttpClient(ctx context.Context, accessToken string) *http.Client {
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{
			AccessToken: accessToken,
			TokenType:   "token",
		},
	)

	return oauth2.NewClient(ctx, ts)
}

// TODO: create client with support for github cache or ghproxy.
// NeClient creates kyma implementation of github client with oauth authentication.
func NewClient(ctx context.Context, accessToken string) (*Client, error) {
	tc := newOauthHttpClient(ctx, accessToken)
	c := github.NewClient(tc)

	return &Client{Client: c}, nil
}

// NewSapToolsClient creates kyma implementation github Client with SapToolsGithubURL as an endpoint.
// Client uses oauth authentication with bearer token.
func NewSapToolsClient(ctx context.Context, accessToken string) (*SapToolsClient, error) {
	tc := newOauthHttpClient(ctx, accessToken)
	c, err := github.NewEnterpriseClient(SapToolsGithubURL, SapToolsGithubURL, tc)
	if err != nil {
		return nil, fmt.Errorf("got error when creating sap tools github enterprise client: %w", err)
	}

	return &SapToolsClient{Client: &Client{Client: c}}, nil
}

// IsStatusOK will check if http response code is 200.
// On not OK status it will read response body to expose details about error.
func (c *Client) IsStatusOK(resp *github.Response) (bool, error) {
	if resp.StatusCode != http.StatusOK {
		bodyBytes, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return false, fmt.Errorf("got error when reading response body for non 200 HTTP reponse code, error: %w", err)
		}
		bodyString := string(bodyBytes)
		return false, fmt.Errorf("got non 200 response code in HTTP response, body: %s", bodyString)
	}
	return true, nil
}

// GetUserMap will get users-map.yaml file from github.tools.sap instance.
func (c *SapToolsClient) GetUsersMap(ctx context.Context) ([]types.User, error) {
	var usersMap []types.User
	// Get file from github.
	usersMapFile, _, resp, err := c.Client.Repositories.GetContents(ctx, "kyma", "test-infra", "/users-map.yaml", &github.RepositoryContentGetOptions{Ref: "main"})
	if err != nil {
		return nil, fmt.Errorf("got error when getting users-map.yaml file from github.tools.sap, error: %w", err)
	}
	// Check HTTP response code
	if ok, err := c.IsStatusOK(resp); !ok {
		return nil, err
	}
	// Read file content.
	usersMapString, err := usersMapFile.GetContent()
	if err != nil {
		return nil, fmt.Errorf("got error when getting content of users-map.yaml file, error: %w", err)
	}
	err = yaml.Unmarshal([]byte(usersMapString), &usersMap)
	if err != nil {
		return nil, fmt.Errorf("got error when unmarshaling usres-map.yaml file content, error: %w", err)
	}
	return usersMap, nil
}

// GetAuthorLoginForSHA will provide commit author github Login for given SHA.
func (c *Client) GetAuthorLoginForSHA(ctx context.Context, sha, owner, repo string) (*string, error) {
	// Get commit for SHA.
	commit, resp, err := c.Repositories.GetCommit(ctx, owner, repo, sha)
	if err != nil {
		return nil, fmt.Errorf("got error when getting users-map.yaml file from github.tools.sap, error: %w", err)
	}
	// Check HTTP response code.
	if ok, err := c.IsStatusOK(resp); !ok {
		return nil, err
	}
	// Read commit author Login.
	l := commit.GetAuthor().GetLogin()
	return &l, nil
}
<commit_msg>cleaner composition and methods calls (#4082)<commit_after>package client

import (
	"context"
	"fmt"
	"io/ioutil"
	"net/http"

	"github.com/google/go-github/v31/github"
	"github.com/kyma-project/test-infra/development/types"
	"golang.org/x/oauth2"
	"gopkg.in/yaml.v2"
)

const (
	SapToolsGithubURL  = "https://github.tools.sap/"
	ProwGithubProxyURL = "http://ghproxy"
)

// SapToolsClient wraps kyma implementation github Client and provides additional methods.
type SapToolsClient struct {
	*Client
}

// Client wraps google github Client and provides additional methods.
type Client struct {
	*github.Client
}

// newOauthHttpClient creates HTTP client with oauth authentication.
// It authenticates with Bearer token.
func newOauthHttpClient(ctx context.Context, accessToken string) *http.Client {
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{
			AccessToken: accessToken,
			TokenType:   "token",
		},
	)

	return oauth2.NewClient(ctx, ts)
}

// TODO: create client with support for github cache or ghproxy.
// NeClient creates kyma implementation of github client with oauth authentication.
func NewClient(ctx context.Context, accessToken string) (*Client, error) {
	tc := newOauthHttpClient(ctx, accessToken)
	c := github.NewClient(tc)

	return &Client{c}, nil
}

// NewSapToolsClient creates kyma implementation github Client with SapToolsGithubURL as an endpoint.
// Client uses oauth authentication with bearer token.
func NewSapToolsClient(ctx context.Context, accessToken string) (*SapToolsClient, error) {
	tc := newOauthHttpClient(ctx, accessToken)
	c, err := github.NewEnterpriseClient(SapToolsGithubURL, SapToolsGithubURL, tc)
	if err != nil {
		return nil, fmt.Errorf("got error when creating sap tools github enterprise client: %w", err)
	}

	return &SapToolsClient{&Client{c}}, nil
}

// IsStatusOK will check if http response code is 200.
// On not OK status it will read response body to expose details about error.
func (c *Client) IsStatusOK(resp *github.Response) (bool, error) {
	if resp.StatusCode != http.StatusOK {
		bodyBytes, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return false, fmt.Errorf("got error when reading response body for non 200 HTTP reponse code, error: %w", err)
		}
		bodyString := string(bodyBytes)
		return false, fmt.Errorf("got non 200 response code in HTTP response, body: %s", bodyString)
	}
	return true, nil
}

// GetUserMap will get users-map.yaml file from github.tools.sap instance.
func (c *SapToolsClient) GetUsersMap(ctx context.Context) ([]types.User, error) {
	var usersMap []types.User
	// Get file from github.
	usersMapFile, _, resp, err := c.Repositories.GetContents(ctx, "kyma", "test-infra", "/users-map.yaml", &github.RepositoryContentGetOptions{Ref: "main"})
	if err != nil {
		return nil, fmt.Errorf("got error when getting users-map.yaml file from github.tools.sap, error: %w", err)
	}
	// Check HTTP response code
	if ok, err := c.IsStatusOK(resp); !ok {
		return nil, err
	}
	// Read file content.
	usersMapString, err := usersMapFile.GetContent()
	if err != nil {
		return nil, fmt.Errorf("got error when getting content of users-map.yaml file, error: %w", err)
	}
	err = yaml.Unmarshal([]byte(usersMapString), &usersMap)
	if err != nil {
		return nil, fmt.Errorf("got error when unmarshaling usres-map.yaml file content, error: %w", err)
	}
	return usersMap, nil
}

// GetAuthorLoginForSHA will provide commit author github Login for given SHA.
func (c *Client) GetAuthorLoginForSHA(ctx context.Context, sha, owner, repo string) (*string, error) {
	// Get commit for SHA.
	commit, resp, err := c.Repositories.GetCommit(ctx, owner, repo, sha)
	if err != nil {
		return nil, fmt.Errorf("got error when getting users-map.yaml file from github.tools.sap, error: %w", err)
	}
	// Check HTTP response code.
	if ok, err := c.IsStatusOK(resp); !ok {
		return nil, err
	}
	// Read commit author Login.
	l := commit.GetAuthor().GetLogin()
	return &l, nil
}
<|endoftext|>


<commit_before>package event_convert

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"strconv"

	"github.com/karimra/gnmic/formatters"
)

const (
	processorType = "event-convert"
	loggingPrefix = "[" + processorType + "] "
)

// Convert converts the value with key matching one of regexes, to the specified Type
type Convert struct {
	Values []string `mapstructure:"value-names,omitempty" json:"value-names,omitempty"`
	Type   string   `mapstructure:"type,omitempty" json:"type,omitempty"`
	Debug  bool     `mapstructure:"debug,omitempty" json:"debug,omitempty"`

	values []*regexp.Regexp
	logger *log.Logger
}

func init() {
	formatters.Register(processorType, func() formatters.EventProcessor {
		return &Convert{
			logger: log.New(ioutil.Discard, "", 0),
		}
	})
}

func (c *Convert) Init(cfg interface{}, opts ...formatters.Option) error {
	err := formatters.DecodeConfig(cfg, c)
	if err != nil {
		return err
	}
	for _, opt := range opts {
		opt(c)
	}
	c.values = make([]*regexp.Regexp, 0, len(c.Values))
	for _, reg := range c.Values {
		re, err := regexp.Compile(reg)
		if err != nil {
			return err
		}
		c.values = append(c.values, re)
	}
	if c.logger.Writer() != ioutil.Discard {
		b, err := json.Marshal(c)
		if err != nil {
			c.logger.Printf("initialized processor '%s': %+v", processorType, c)
			return nil
		}
		c.logger.Printf("initialized processor '%s': %s", processorType, string(b))
	}
	return nil
}

func (c *Convert) Apply(es ...*formatters.EventMsg) []*formatters.EventMsg {
	for _, e := range es {
		if e == nil {
			continue
		}
		for k, v := range e.Values {
			for _, re := range c.values {
				if re.MatchString(k) {
					c.logger.Printf("key '%s' matched regex '%s'", k, re.String())
					switch c.Type {
					case "int":
						iv, err := convertToInt(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %d", k, v, c.Type, iv)
						e.Values[k] = iv
					case "uint":
						iv, err := convertToUint(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %d", k, v, c.Type, iv)
						e.Values[k] = iv
					case "string":
						iv, err := convertToString(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %s", k, v, c.Type, iv)
						e.Values[k] = iv
					case "float":
						iv, err := convertToFloat(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %f", k, v, c.Type, iv)
						e.Values[k] = iv
					}
					break
				}
			}
		}
	}
	return es
}

func (c *Convert) WithLogger(l *log.Logger) {
	if c.Debug && l != nil {
		c.logger = log.New(l.Writer(), loggingPrefix, l.Flags())
	} else if c.Debug {
		c.logger = log.New(os.Stderr, loggingPrefix, log.LstdFlags|log.Lmicroseconds)
	}
}

func (c *Convert) WithTargets(tcs map[string]interface{}) {}

func convertToInt(i interface{}) (int, error) {
	switch i := i.(type) {
	case string:
		iv, err := strconv.Atoi(i)
		if err != nil {
			return 0, err
		}
		return iv, nil
	case int:
		return i, nil
	case uint:
		return int(i), nil
	case float64:
		return int(i), nil
	default:
		return 0, errors.New("cannot convert to int")
	}
}

func convertToUint(i interface{}) (uint, error) {
	switch i := i.(type) {
	case string:
		iv, err := strconv.Atoi(i)
		if err != nil {
			return 0, err
		}
		return uint(iv), nil
	case int:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case uint:
		return i, nil
	case float64:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	default:
		return 0, errors.New("cannot convert to uint")
	}
}

func convertToFloat(i interface{}) (float64, error) {
	switch i := i.(type) {
	case string:
		iv, err := strconv.ParseFloat(i, 64)
		if err != nil {
			return 0, err
		}
		return iv, nil
	case int:
		return float64(i), nil
	case uint:
		return float64(i), nil
	case float64:
		return i, nil
	default:
		return 0, errors.New("cannot convert to float64")
	}
}

func convertToString(i interface{}) (string, error) {
	switch i := i.(type) {
	case string:
		return i, nil
	case int:
		return strconv.Itoa(i), nil
	case uint:
		return strconv.Itoa(int(i)), nil
	case float64:
		return strconv.FormatFloat(i, 'f', 64, 64), nil
	default:
		return "", errors.New("cannot convert to float64")
	}
}
<commit_msg>add per (u)int type conversion<commit_after>package event_convert

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"strconv"

	"github.com/karimra/gnmic/formatters"
)

const (
	processorType = "event-convert"
	loggingPrefix = "[" + processorType + "] "
)

// Convert converts the value with key matching one of regexes, to the specified Type
type Convert struct {
	Values []string `mapstructure:"value-names,omitempty" json:"value-names,omitempty"`
	Type   string   `mapstructure:"type,omitempty" json:"type,omitempty"`
	Debug  bool     `mapstructure:"debug,omitempty" json:"debug,omitempty"`

	values []*regexp.Regexp
	logger *log.Logger
}

func init() {
	formatters.Register(processorType, func() formatters.EventProcessor {
		return &Convert{
			logger: log.New(ioutil.Discard, "", 0),
		}
	})
}

func (c *Convert) Init(cfg interface{}, opts ...formatters.Option) error {
	err := formatters.DecodeConfig(cfg, c)
	if err != nil {
		return err
	}
	for _, opt := range opts {
		opt(c)
	}
	c.values = make([]*regexp.Regexp, 0, len(c.Values))
	for _, reg := range c.Values {
		re, err := regexp.Compile(reg)
		if err != nil {
			return err
		}
		c.values = append(c.values, re)
	}
	if c.logger.Writer() != ioutil.Discard {
		b, err := json.Marshal(c)
		if err != nil {
			c.logger.Printf("initialized processor '%s': %+v", processorType, c)
			return nil
		}
		c.logger.Printf("initialized processor '%s': %s", processorType, string(b))
	}
	return nil
}

func (c *Convert) Apply(es ...*formatters.EventMsg) []*formatters.EventMsg {
	for _, e := range es {
		if e == nil {
			continue
		}
		for k, v := range e.Values {
			for _, re := range c.values {
				if re.MatchString(k) {
					c.logger.Printf("key '%s' matched regex '%s'", k, re.String())
					switch c.Type {
					case "int":
						iv, err := convertToInt(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %d", k, v, c.Type, iv)
						e.Values[k] = iv
					case "uint":
						iv, err := convertToUint(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %d", k, v, c.Type, iv)
						e.Values[k] = iv
					case "string":
						iv, err := convertToString(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %s", k, v, c.Type, iv)
						e.Values[k] = iv
					case "float":
						iv, err := convertToFloat(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %f", k, v, c.Type, iv)
						e.Values[k] = iv
					}
					break
				}
			}
		}
	}
	return es
}

func (c *Convert) WithLogger(l *log.Logger) {
	if c.Debug && l != nil {
		c.logger = log.New(l.Writer(), loggingPrefix, l.Flags())
	} else if c.Debug {
		c.logger = log.New(os.Stderr, loggingPrefix, log.LstdFlags|log.Lmicroseconds)
	}
}

func (c *Convert) WithTargets(tcs map[string]interface{}) {}

func convertToInt(i interface{}) (int, error) {
	switch i := i.(type) {
	case string:
		iv, err := strconv.Atoi(i)
		if err != nil {
			return 0, err
		}
		return iv, nil
	case int:
		return i, nil
	case int8:
		return int(i), nil
	case int16:
		return int(i), nil
	case int32:
		return int(i), nil
	case int64:
		return int(i), nil
	case uint:
		return int(i), nil
	case uint8:
		return int(i), nil
	case uint16:
		return int(i), nil
	case uint32:
		return int(i), nil
	case uint64:
		return int(i), nil
	case float64:
		return int(i), nil
	case float32:
		return int(i), nil
	default:
		return 0, errors.New("cannot convert to int")
	}
}

func convertToUint(i interface{}) (uint, error) {
	switch i := i.(type) {
	case string:
		iv, err := strconv.Atoi(i)
		if err != nil {
			return 0, err
		}
		return uint(iv), nil
	case int:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case int8:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case int16:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case int32:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case int64:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case uint:
		return i, nil
	case uint8:
		return uint(i), nil
	case uint16:
		return uint(i), nil
	case uint32:
		return uint(i), nil
	case uint64:
		return uint(i), nil
	case float32:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case float64:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	default:
		return 0, errors.New("cannot convert to uint")
	}
}

func convertToFloat(i interface{}) (float64, error) {
	switch i := i.(type) {
	case string:
		iv, err := strconv.ParseFloat(i, 64)
		if err != nil {
			return 0, err
		}
		return iv, nil
	case int:
		return float64(i), nil
	case int8:
		return float64(i), nil
	case int16:
		return float64(i), nil
	case int32:
		return float64(i), nil
	case int64:
		return float64(i), nil
	case uint:
		return float64(i), nil
	case uint8:
		return float64(i), nil
	case uint16:
		return float64(i), nil
	case uint32:
		return float64(i), nil
	case uint64:
		return float64(i), nil
	case float64:
		return i, nil
	default:
		return 0, errors.New("cannot convert to float64")
	}
}

func convertToString(i interface{}) (string, error) {
	switch i := i.(type) {
	case string:
		return i, nil
	case int:
		return strconv.Itoa(i), nil
	case uint:
		return strconv.Itoa(int(i)), nil
	case float64:
		return strconv.FormatFloat(i, 'f', 64, 64), nil
	default:
		return "", errors.New("cannot convert to float64")
	}
}
<|endoftext|>


<commit_before>package relay_test

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"testing"
	"time"

	. "github.com/libp2p/go-libp2p-circuit"
	pb "github.com/libp2p/go-libp2p-circuit/pb"

	bhost "github.com/libp2p/go-libp2p-blankhost"
	"github.com/libp2p/go-libp2p-core/host"

	swarm "github.com/libp2p/go-libp2p-swarm"
	swarmt "github.com/libp2p/go-libp2p-swarm/testing"
	ma "github.com/multiformats/go-multiaddr"
)

/* TODO: add tests
- simple A -[R]-> B
- A tries to relay through R, R doesnt support relay
- A tries to relay through R to B, B doesnt support relay
- A sends too long multiaddr
- R drops stream mid-message
- A relays through R, R has no connection to B
*/

func getNetHosts(t *testing.T, ctx context.Context, n int) []host.Host {
	var out []host.Host

	for i := 0; i < n; i++ {
		netw := swarmt.GenSwarm(t, ctx)
		h := bhost.NewBlankHost(netw)
		out = append(out, h)
	}

	return out
}

func newTestRelay(t *testing.T, ctx context.Context, host host.Host, opts ...RelayOpt) *Relay {
	r, err := NewRelay(ctx, host, swarmt.GenUpgrader(host.Network().(*swarm.Swarm)), opts...)
	if err != nil {
		t.Fatal(err)
	}
	return r
}

func connect(t *testing.T, a, b host.Host) {
	pinfo := a.Peerstore().PeerInfo(a.ID())
	err := b.Connect(context.Background(), pinfo)
	if err != nil {
		t.Fatal(err)
	}
}

func TestBasicRelay(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	hosts := getNetHosts(t, ctx, 3)

	connect(t, hosts[0], hosts[1])
	connect(t, hosts[1], hosts[2])

	time.Sleep(10 * time.Millisecond)

	r1 := newTestRelay(t, ctx, hosts[0])

	newTestRelay(t, ctx, hosts[1], OptHop)

	r3 := newTestRelay(t, ctx, hosts[2])

	var (
		conn1, conn2 net.Conn
		done         = make(chan struct{})
	)

	defer func() {
		<-done
		if conn1 != nil {
			conn1.Close()
		}
		if conn2 != nil {
			conn2.Close()
		}
	}()

	msg := []byte("relay works!")
	go func() {
		defer close(done)
		list := r3.Listener()

		var err error
		conn1, err = list.Accept()
		if err != nil {
			t.Error(err)
			return
		}

		_, err = conn1.Write(msg)
		if err != nil {
			t.Error(err)
			return
		}
	}()

	rinfo := hosts[1].Peerstore().PeerInfo(hosts[1].ID())
	dinfo := hosts[2].Peerstore().PeerInfo(hosts[2].ID())

	rctx, rcancel := context.WithTimeout(ctx, time.Second)
	defer rcancel()

	var err error
	conn2, err = r1.DialPeer(rctx, rinfo, dinfo)
	if err != nil {
		t.Fatal(err)
	}

	result := make([]byte, len(msg))
	_, err = io.ReadFull(conn2, result)
	if err != nil {
		t.Fatal(err)
	}

	if !bytes.Equal(result, msg) {
		t.Fatal("message was incorrect:", string(result))
	}
}

func TestRelayReset(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	hosts := getNetHosts(t, ctx, 3)

	connect(t, hosts[0], hosts[1])
	connect(t, hosts[1], hosts[2])

	time.Sleep(10 * time.Millisecond)

	r1 := newTestRelay(t, ctx, hosts[0])

	newTestRelay(t, ctx, hosts[1], OptHop)

	r3 := newTestRelay(t, ctx, hosts[2])

	ready := make(chan struct{})

	msg := []byte("relay works!")
	go func() {
		list := r3.Listener()

		con, err := list.Accept()
		if err != nil {
			t.Error(err)
			return
		}

		<-ready

		_, err = con.Write(msg)
		if err != nil {
			t.Error(err)
			return
		}

		hosts[2].Network().ClosePeer(hosts[1].ID())
	}()

	rinfo := hosts[1].Peerstore().PeerInfo(hosts[1].ID())
	dinfo := hosts[2].Peerstore().PeerInfo(hosts[2].ID())

	rctx, rcancel := context.WithTimeout(ctx, time.Second)
	defer rcancel()

	con, err := r1.DialPeer(rctx, rinfo, dinfo)
	if err != nil {
		t.Fatal(err)
	}

	close(ready)

	_, err = ioutil.ReadAll(con)
	if err == nil {
		t.Fatal("expected error for reset relayed connection")
	}
}

func TestBasicRelayDial(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())

	hosts := getNetHosts(t, ctx, 3)

	connect(t, hosts[0], hosts[1])
	connect(t, hosts[1], hosts[2])

	time.Sleep(10 * time.Millisecond)

	r1 := newTestRelay(t, ctx, hosts[0])

	_ = newTestRelay(t, ctx, hosts[1], OptHop)
	r3 := newTestRelay(t, ctx, hosts[2])

	var (
		conn1, conn2 net.Conn
		done         = make(chan struct{})
	)

	defer func() {
		cancel()
		<-done
		if conn1 != nil {
			conn1.Close()
		}
		if conn2 != nil {
			conn2.Close()
		}
	}()

	msg := []byte("relay works!")
	go func() {
		defer close(done)
		list := r3.Listener()

		var err error
		conn1, err = list.Accept()
		if err != nil {
			t.Error(err)
			return
		}

		_, err = conn1.Write(msg)
		if err != nil {
			t.Error(err)
			return
		}
	}()

	addr := ma.StringCast(fmt.Sprintf("/ipfs/%s/p2p-circuit", hosts[1].ID().Pretty()))

	rctx, rcancel := context.WithTimeout(ctx, time.Second)
	defer rcancel()

	var err error
	conn2, err = r1.Dial(rctx, addr, hosts[2].ID())
	if err != nil {
		t.Fatal(err)
	}

	data := make([]byte, len(msg))
	_, err = io.ReadFull(conn2, data)
	if err != nil {
		t.Fatal(err)
	}

	if !bytes.Equal(data, msg) {
		t.Fatal("message was incorrect:", string(data))
	}
}

func TestUnspecificRelayDialFails(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())

	hosts := getNetHosts(t, ctx, 3)

	r1 := newTestRelay(t, ctx, hosts[0])

	newTestRelay(t, ctx, hosts[1], OptHop)

	r3 := newTestRelay(t, ctx, hosts[2])

	connect(t, hosts[0], hosts[1])
	connect(t, hosts[1], hosts[2])

	time.Sleep(100 * time.Millisecond)

	var (
		done = make(chan struct{})
	)

	defer func() {
		cancel()
		<-done
	}()

	go func() {
		defer close(done)
		list := r3.Listener()

		var err error
		_, err = list.Accept()
		if err == nil {
			t.Error("should not have received relay connection")
		}
	}()

	addr := ma.StringCast("/p2p-circuit")

	rctx, rcancel := context.WithTimeout(ctx, time.Second)
	defer rcancel()

	var err error
	_, err = r1.Dial(rctx, addr, hosts[2].ID())
	if err == nil {
		t.Fatal("expected dial with unspecified relay address to fail, even if we're connected to a relay")
	}
}

func TestRelayThroughNonHop(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	hosts := getNetHosts(t, ctx, 3)

	connect(t, hosts[0], hosts[1])
	connect(t, hosts[1], hosts[2])

	time.Sleep(10 * time.Millisecond)

	r1 := newTestRelay(t, ctx, hosts[0])

	newTestRelay(t, ctx, hosts[1])

	newTestRelay(t, ctx, hosts[2])

	rinfo := hosts[1].Peerstore().PeerInfo(hosts[1].ID())
	dinfo := hosts[2].Peerstore().PeerInfo(hosts[2].ID())

	rctx, rcancel := context.WithTimeout(ctx, time.Second)
	defer rcancel()

	_, err := r1.DialPeer(rctx, rinfo, dinfo)
	if err == nil {
		t.Fatal("expected error")
	}

	rerr, ok := err.(RelayError)
	if !ok {
		t.Fatalf("expected RelayError: %#v", err)
	}

	if rerr.Code != pb.CircuitRelay_HOP_CANT_SPEAK_RELAY {
		t.Fatal("expected 'HOP_CANT_SPEAK_RELAY' error")
	}
}

func TestRelayNoDestConnection(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	hosts := getNetHosts(t, ctx, 3)

	connect(t, hosts[0], hosts[1])

	time.Sleep(10 * time.Millisecond)

	r1 := newTestRelay(t, ctx, hosts[0])

	newTestRelay(t, ctx, hosts[1], OptHop)

	rinfo := hosts[1].Peerstore().PeerInfo(hosts[1].ID())
	dinfo := hosts[2].Peerstore().PeerInfo(hosts[2].ID())

	rctx, rcancel := context.WithTimeout(ctx, time.Second)
	defer rcancel()

	_, err := r1.DialPeer(rctx, rinfo, dinfo)
	if err == nil {
		t.Fatal("expected error")
	}

	rerr, ok := err.(RelayError)
	if !ok {
		t.Fatalf("expected RelayError: %#v", err)
	}

	if rerr.Code != pb.CircuitRelay_HOP_NO_CONN_TO_DST {
		t.Fatal("expected 'HOP_NO_CONN_TO_DST' error")
	}
}

func TestActiveRelay(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	hosts := getNetHosts(t, ctx, 3)

	connect(t, hosts[0], hosts[1])

	time.Sleep(10 * time.Millisecond)

	r1 := newTestRelay(t, ctx, hosts[0])

	newTestRelay(t, ctx, hosts[1], OptHop, OptActive)

	r3 := newTestRelay(t, ctx, hosts[2])

	var (
		conn1, conn2 net.Conn
		done         = make(chan struct{})
	)

	defer func() {
		<-done
		if conn1 != nil {
			conn1.Close()
		}
		if conn2 != nil {
			conn2.Close()
		}
	}()

	msg := []byte("relay works!")
	go func() {
		defer close(done)
		list := r3.Listener()

		var err error
		conn2, err = list.Accept()
		if err != nil {
			t.Error(err)
			return
		}

		_, err = conn2.Write(msg)
		if err != nil {
			t.Error(err)
			return
		}
	}()

	rinfo := hosts[1].Peerstore().PeerInfo(hosts[1].ID())
	dinfo := hosts[2].Peerstore().PeerInfo(hosts[2].ID())

	rctx, rcancel := context.WithTimeout(ctx, time.Second)
	defer rcancel()

	var err error
	conn2, err = r1.DialPeer(rctx, rinfo, dinfo)
	if err != nil {
		t.Fatal(err)
	}

	data := make([]byte, len(msg))
	_, err = io.ReadFull(conn2, data)
	if err != nil {
		t.Fatal(err)
	}

	if !bytes.Equal(data, msg) {
		t.Fatal("message was incorrect:", string(data))
	}
}

func TestRelayCanHop(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	hosts := getNetHosts(t, ctx, 2)

	connect(t, hosts[0], hosts[1])

	time.Sleep(10 * time.Millisecond)

	r1 := newTestRelay(t, ctx, hosts[0])

	newTestRelay(t, ctx, hosts[1], OptHop)

	canhop, err := r1.CanHop(ctx, hosts[1].ID())
	if err != nil {
		t.Fatal(err)
	}

	if !canhop {
		t.Fatal("Relay can't hop")
	}
}
<commit_msg>fix race condition in TestActiveRelay<commit_after>package relay_test

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"testing"
	"time"

	. "github.com/libp2p/go-libp2p-circuit"
	pb "github.com/libp2p/go-libp2p-circuit/pb"

	bhost "github.com/libp2p/go-libp2p-blankhost"
	"github.com/libp2p/go-libp2p-core/host"

	swarm "github.com/libp2p/go-libp2p-swarm"
	swarmt "github.com/libp2p/go-libp2p-swarm/testing"
	ma "github.com/multiformats/go-multiaddr"
	manet "github.com/multiformats/go-multiaddr/net"
)

/* TODO: add tests
- simple A -[R]-> B
- A tries to relay through R, R doesnt support relay
- A tries to relay through R to B, B doesnt support relay
- A sends too long multiaddr
- R drops stream mid-message
- A relays through R, R has no connection to B
*/

func getNetHosts(t *testing.T, ctx context.Context, n int) []host.Host {
	var out []host.Host

	for i := 0; i < n; i++ {
		netw := swarmt.GenSwarm(t, ctx)
		h := bhost.NewBlankHost(netw)
		out = append(out, h)
	}

	return out
}

func newTestRelay(t *testing.T, ctx context.Context, host host.Host, opts ...RelayOpt) *Relay {
	r, err := NewRelay(ctx, host, swarmt.GenUpgrader(host.Network().(*swarm.Swarm)), opts...)
	if err != nil {
		t.Fatal(err)
	}
	return r
}

func connect(t *testing.T, a, b host.Host) {
	pinfo := a.Peerstore().PeerInfo(a.ID())
	err := b.Connect(context.Background(), pinfo)
	if err != nil {
		t.Fatal(err)
	}
}

func TestBasicRelay(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	hosts := getNetHosts(t, ctx, 3)

	connect(t, hosts[0], hosts[1])
	connect(t, hosts[1], hosts[2])

	time.Sleep(10 * time.Millisecond)

	r1 := newTestRelay(t, ctx, hosts[0])

	newTestRelay(t, ctx, hosts[1], OptHop)

	r3 := newTestRelay(t, ctx, hosts[2])

	var (
		conn1, conn2 net.Conn
		done         = make(chan struct{})
	)

	defer func() {
		<-done
		if conn1 != nil {
			conn1.Close()
		}
		if conn2 != nil {
			conn2.Close()
		}
	}()

	msg := []byte("relay works!")
	go func() {
		defer close(done)
		list := r3.Listener()

		var err error
		conn1, err = list.Accept()
		if err != nil {
			t.Error(err)
			return
		}

		_, err = conn1.Write(msg)
		if err != nil {
			t.Error(err)
			return
		}
	}()

	rinfo := hosts[1].Peerstore().PeerInfo(hosts[1].ID())
	dinfo := hosts[2].Peerstore().PeerInfo(hosts[2].ID())

	rctx, rcancel := context.WithTimeout(ctx, time.Second)
	defer rcancel()

	var err error
	conn2, err = r1.DialPeer(rctx, rinfo, dinfo)
	if err != nil {
		t.Fatal(err)
	}

	result := make([]byte, len(msg))
	_, err = io.ReadFull(conn2, result)
	if err != nil {
		t.Fatal(err)
	}

	if !bytes.Equal(result, msg) {
		t.Fatal("message was incorrect:", string(result))
	}
}

func TestRelayReset(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	hosts := getNetHosts(t, ctx, 3)

	connect(t, hosts[0], hosts[1])
	connect(t, hosts[1], hosts[2])

	time.Sleep(10 * time.Millisecond)

	r1 := newTestRelay(t, ctx, hosts[0])

	newTestRelay(t, ctx, hosts[1], OptHop)

	r3 := newTestRelay(t, ctx, hosts[2])

	ready := make(chan struct{})

	msg := []byte("relay works!")
	go func() {
		list := r3.Listener()

		con, err := list.Accept()
		if err != nil {
			t.Error(err)
			return
		}

		<-ready

		_, err = con.Write(msg)
		if err != nil {
			t.Error(err)
			return
		}

		hosts[2].Network().ClosePeer(hosts[1].ID())
	}()

	rinfo := hosts[1].Peerstore().PeerInfo(hosts[1].ID())
	dinfo := hosts[2].Peerstore().PeerInfo(hosts[2].ID())

	rctx, rcancel := context.WithTimeout(ctx, time.Second)
	defer rcancel()

	con, err := r1.DialPeer(rctx, rinfo, dinfo)
	if err != nil {
		t.Fatal(err)
	}

	close(ready)

	_, err = ioutil.ReadAll(con)
	if err == nil {
		t.Fatal("expected error for reset relayed connection")
	}
}

func TestBasicRelayDial(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())

	hosts := getNetHosts(t, ctx, 3)

	connect(t, hosts[0], hosts[1])
	connect(t, hosts[1], hosts[2])

	time.Sleep(10 * time.Millisecond)

	r1 := newTestRelay(t, ctx, hosts[0])

	_ = newTestRelay(t, ctx, hosts[1], OptHop)
	r3 := newTestRelay(t, ctx, hosts[2])

	var (
		conn1, conn2 net.Conn
		done         = make(chan struct{})
	)

	defer func() {
		cancel()
		<-done
		if conn1 != nil {
			conn1.Close()
		}
		if conn2 != nil {
			conn2.Close()
		}
	}()

	msg := []byte("relay works!")
	go func() {
		defer close(done)
		list := r3.Listener()

		var err error
		conn1, err = list.Accept()
		if err != nil {
			t.Error(err)
			return
		}

		_, err = conn1.Write(msg)
		if err != nil {
			t.Error(err)
			return
		}
	}()

	addr := ma.StringCast(fmt.Sprintf("/ipfs/%s/p2p-circuit", hosts[1].ID().Pretty()))

	rctx, rcancel := context.WithTimeout(ctx, time.Second)
	defer rcancel()

	var err error
	conn2, err = r1.Dial(rctx, addr, hosts[2].ID())
	if err != nil {
		t.Fatal(err)
	}

	data := make([]byte, len(msg))
	_, err = io.ReadFull(conn2, data)
	if err != nil {
		t.Fatal(err)
	}

	if !bytes.Equal(data, msg) {
		t.Fatal("message was incorrect:", string(data))
	}
}

func TestUnspecificRelayDialFails(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())

	hosts := getNetHosts(t, ctx, 3)

	r1 := newTestRelay(t, ctx, hosts[0])

	newTestRelay(t, ctx, hosts[1], OptHop)

	r3 := newTestRelay(t, ctx, hosts[2])

	connect(t, hosts[0], hosts[1])
	connect(t, hosts[1], hosts[2])

	time.Sleep(100 * time.Millisecond)

	var (
		done = make(chan struct{})
	)

	defer func() {
		cancel()
		<-done
	}()

	go func() {
		defer close(done)
		list := r3.Listener()

		var err error
		_, err = list.Accept()
		if err == nil {
			t.Error("should not have received relay connection")
		}
	}()

	addr := ma.StringCast("/p2p-circuit")

	rctx, rcancel := context.WithTimeout(ctx, time.Second)
	defer rcancel()

	var err error
	_, err = r1.Dial(rctx, addr, hosts[2].ID())
	if err == nil {
		t.Fatal("expected dial with unspecified relay address to fail, even if we're connected to a relay")
	}
}

func TestRelayThroughNonHop(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	hosts := getNetHosts(t, ctx, 3)

	connect(t, hosts[0], hosts[1])
	connect(t, hosts[1], hosts[2])

	time.Sleep(10 * time.Millisecond)

	r1 := newTestRelay(t, ctx, hosts[0])

	newTestRelay(t, ctx, hosts[1])

	newTestRelay(t, ctx, hosts[2])

	rinfo := hosts[1].Peerstore().PeerInfo(hosts[1].ID())
	dinfo := hosts[2].Peerstore().PeerInfo(hosts[2].ID())

	rctx, rcancel := context.WithTimeout(ctx, time.Second)
	defer rcancel()

	_, err := r1.DialPeer(rctx, rinfo, dinfo)
	if err == nil {
		t.Fatal("expected error")
	}

	rerr, ok := err.(RelayError)
	if !ok {
		t.Fatalf("expected RelayError: %#v", err)
	}

	if rerr.Code != pb.CircuitRelay_HOP_CANT_SPEAK_RELAY {
		t.Fatal("expected 'HOP_CANT_SPEAK_RELAY' error")
	}
}

func TestRelayNoDestConnection(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	hosts := getNetHosts(t, ctx, 3)

	connect(t, hosts[0], hosts[1])

	time.Sleep(10 * time.Millisecond)

	r1 := newTestRelay(t, ctx, hosts[0])

	newTestRelay(t, ctx, hosts[1], OptHop)

	rinfo := hosts[1].Peerstore().PeerInfo(hosts[1].ID())
	dinfo := hosts[2].Peerstore().PeerInfo(hosts[2].ID())

	rctx, rcancel := context.WithTimeout(ctx, time.Second)
	defer rcancel()

	_, err := r1.DialPeer(rctx, rinfo, dinfo)
	if err == nil {
		t.Fatal("expected error")
	}

	rerr, ok := err.(RelayError)
	if !ok {
		t.Fatalf("expected RelayError: %#v", err)
	}

	if rerr.Code != pb.CircuitRelay_HOP_NO_CONN_TO_DST {
		t.Fatal("expected 'HOP_NO_CONN_TO_DST' error")
	}
}

func TestActiveRelay(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	hosts := getNetHosts(t, ctx, 3)

	connect(t, hosts[0], hosts[1])

	time.Sleep(10 * time.Millisecond)

	r1 := newTestRelay(t, ctx, hosts[0])
	newTestRelay(t, ctx, hosts[1], OptHop, OptActive)
	r3 := newTestRelay(t, ctx, hosts[2])

	connChan := make(chan manet.Conn)

	msg := []byte("relay works!")
	go func() {
		defer close(connChan)
		list := r3.Listener()

		conn1, err := list.Accept()
		if err != nil {
			t.Error(err)
			return
		}

		if _, err := conn1.Write(msg); err != nil {
			t.Error(err)
			return
		}
		connChan <- conn1
	}()

	rinfo := hosts[1].Peerstore().PeerInfo(hosts[1].ID())
	dinfo := hosts[2].Peerstore().PeerInfo(hosts[2].ID())

	rctx, rcancel := context.WithTimeout(ctx, time.Second)
	defer rcancel()

	conn2, err := r1.DialPeer(rctx, rinfo, dinfo)
	if err != nil {
		t.Fatal(err)
	}
	defer conn2.Close()

	data := make([]byte, len(msg))
	_, err = io.ReadFull(conn2, data)
	if err != nil {
		t.Fatal(err)
	}

	if !bytes.Equal(data, msg) {
		t.Fatal("message was incorrect:", string(data))
	}
	conn1, ok := <-connChan
	if !ok {
		t.Fatal("listener didn't accept a connection")
	}
	conn1.Close()
}

func TestRelayCanHop(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	hosts := getNetHosts(t, ctx, 2)

	connect(t, hosts[0], hosts[1])

	time.Sleep(10 * time.Millisecond)

	r1 := newTestRelay(t, ctx, hosts[0])

	newTestRelay(t, ctx, hosts[1], OptHop)

	canhop, err := r1.CanHop(ctx, hosts[1].ID())
	if err != nil {
		t.Fatal(err)
	}

	if !canhop {
		t.Fatal("Relay can't hop")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"flag"
	"html/template"
	"log"
	"math/rand"
	"net"
	"os"
	"os/exec"
	"runtime"
	"sort"

	_ "github.com/go-sql-driver/mysql"
	"github.com/valyala/fasthttp"
	"github.com/valyala/fasthttp/reuseport"
)

type Message struct {
	Message string `json:"message"`
}

type World struct {
	Id           uint16 `json:"id"`
	RandomNumber uint16 `json:"randomNumber"`
}

type Fortune struct {
	Id      uint16 `json:"id"`
	Message string `json:"message"`
}

// Databases
const (
	connectionString   = "benchmarkdbuser:benchmarkdbpass@tcp(localhost:3306)/hello_world?interpolateParams=true"
	worldRowCount      = 10000
	maxConnectionCount = 256
)

var (
	worldSelectStmt   *sql.Stmt
	worldUpdateStmt   *sql.Stmt
	fortuneSelectStmt *sql.Stmt
)

const helloWorldString = "Hello, World!"

var (
	// Templates
	tmpl = template.Must(template.ParseFiles("templates/layout.html", "templates/fortune.html"))

	// Database
	db *sql.DB

	helloWorldBytes = []byte(helloWorldString)
)

var (
	listenAddr = flag.String("listenAddr", ":8080", "Address to listen to")
	prefork    = flag.Bool("prefork", false, "use prefork")
	child      = flag.Bool("child", false, "is child proc")
)

func main() {
	flag.Parse()

	var listener net.Listener
	if !*prefork {
		runtime.GOMAXPROCS(runtime.NumCPU())
	} else {
		listener = doPrefork()
	}

	var err error
	db, err = sql.Open("mysql", connectionString)
	if err != nil {
		log.Fatalf("Error opening database: %s", err)
	}
	if err = db.Ping(); err != nil {
		log.Fatalf("Cannot connect to db: %s", err)
	}

	dbConnCount := maxConnectionCount
	if *prefork {
		dbConnCount = (dbConnCount + runtime.NumCPU()-1) / runtime.NumCPU()
	}
	db.SetMaxIdleConns(dbConnCount)
	db.SetMaxOpenConns(dbConnCount * 2)

	worldSelectStmt = mustPrepare(db, "SELECT id, randomNumber FROM World WHERE id = ?")
	worldUpdateStmt = mustPrepare(db, "UPDATE World SET randomNumber = ? WHERE id = ?")
	fortuneSelectStmt = mustPrepare(db, "SELECT id, message FROM Fortune")

	s := &fasthttp.Server{
		Handler: mainHandler,
		Name:    "fasthttp",
	}
	if !*prefork {
		s.ListenAndServe(*listenAddr)
	} else {
		s.Serve(listener)
	}
}

func mustPrepare(db *sql.DB, query string) *sql.Stmt {
	stmt, err := db.Prepare(query)
	if err != nil {
		log.Fatalf("Error when preparing statement %q: %s", query, err)
	}
	return stmt
}

func doPrefork() net.Listener {
	if !*child {
		children := make([]*exec.Cmd, runtime.NumCPU())
		for i := range children {
			children[i] = exec.Command(os.Args[0], "-prefork", "-child")
			children[i].Stdout = os.Stdout
			children[i].Stderr = os.Stderr
			if err := children[i].Start(); err != nil {
				log.Fatal(err)
			}
		}
		for _, ch := range children {
			if err := ch.Wait(); err != nil {
				log.Print(err)
			}
		}
		os.Exit(0)
		return nil
	}

	runtime.GOMAXPROCS(1)
	listener, err := reuseport.Listen("tcp4", *listenAddr)
	if err != nil {
		log.Fatal(err)
	}
	return listener
}

func mainHandler(ctx *fasthttp.RequestCtx) {
	path := ctx.Path()
	switch {
	case fasthttp.EqualBytesStr(path, "/plaintext"):
		plaintextHandler(ctx)
	case fasthttp.EqualBytesStr(path, "/json"):
		jsonHandler(ctx)
	case fasthttp.EqualBytesStr(path, "/db"):
		dbHandler(ctx)
	case fasthttp.EqualBytesStr(path, "/queries"):
		queriesHandler(ctx)
	case fasthttp.EqualBytesStr(path, "/fortune"):
		fortuneHandler(ctx)
	case fasthttp.EqualBytesStr(path, "/update"):
		updateHandler(ctx)
	default:
		ctx.Error("unexpected path", fasthttp.StatusBadRequest)
	}
}

// Test 1: JSON serialization
func jsonHandler(ctx *fasthttp.RequestCtx) {
	jsonMarshal(ctx, &Message{helloWorldString})
}

// Test 2: Single database query
func dbHandler(ctx *fasthttp.RequestCtx) {
	var w World
	fetchRandomWorld(&w)
	jsonMarshal(ctx, &w)
}

// Test 3: Multiple database queries
func queriesHandler(ctx *fasthttp.RequestCtx) {
	n := getQueriesCount(ctx)

	worlds := make([]World, n)
	for i := 0; i < n; i++ {
		fetchRandomWorld(&worlds[i])
	}

	jsonMarshal(ctx, worlds)
}

// Test 4: Fortunes
func fortuneHandler(ctx *fasthttp.RequestCtx) {
	rows, err := fortuneSelectStmt.Query()
	if err != nil {
		log.Fatalf("Error preparing statement: %v", err)
	}

	fortunes := make(Fortunes, 0, 16)
	for rows.Next() {
		var f Fortune
		if err := rows.Scan(&f.Id, &f.Message); err != nil {
			log.Fatalf("Error scanning fortune row: %s", err)
		}
		fortunes = append(fortunes, &f)
	}
	rows.Close()
	fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."})

	sort.Sort(ByMessage{fortunes})

	ctx.SetContentType("text/html")
	if err := tmpl.Execute(ctx, fortunes); err != nil {
		log.Fatalf("Error executing fortune: %s", err)
	}
}

// Test 5: Database updates
func updateHandler(ctx *fasthttp.RequestCtx) {
	n := getQueriesCount(ctx)

	worlds := make([]World, n)
	for i := 0; i < n; i++ {
		w := &worlds[i]
		fetchRandomWorld(w)
		w.RandomNumber = uint16(randomWorldNum())
		if _, err := worldUpdateStmt.Exec(w.RandomNumber, w.Id); err != nil {
			log.Fatalf("Error updating world row: %s", err)
		}
	}

	jsonMarshal(ctx, worlds)
}

// Test 6: Plaintext
func plaintextHandler(ctx *fasthttp.RequestCtx) {
	ctx.Success("text/plain", helloWorldBytes)
}

func jsonMarshal(ctx *fasthttp.RequestCtx, v interface{}) {
	ctx.SetContentType("application/json")
	if err := json.NewEncoder(ctx).Encode(v); err != nil {
		log.Fatalf("error in json.Encoder.Encode: %s", err)
	}
}

func fetchRandomWorld(w *World) {
	n := randomWorldNum()
	if err := worldSelectStmt.QueryRow(n).Scan(&w.Id, &w.RandomNumber); err != nil {
		log.Fatalf("Error scanning world row: %s", err)
	}
}

func randomWorldNum() int {
	return rand.Intn(worldRowCount) + 1
}

func getQueriesCount(ctx *fasthttp.RequestCtx) int {
	n := ctx.QueryArgs().GetUintOrZero("queries")
	if n < 1 {
		n = 1
	} else if n > 500 {
		n = 500
	}
	return n
}

type Fortunes []*Fortune

func (s Fortunes) Len() int      { return len(s) }
func (s Fortunes) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

type ByMessage struct{ Fortunes }

func (s ByMessage) Less(i, j int) bool { return s.Fortunes[i].Message < s.Fortunes[j].Message }
<commit_msg>Update world rows in a transaction<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"flag"
	"html/template"
	"log"
	"math/rand"
	"net"
	"os"
	"os/exec"
	"runtime"
	"sort"

	_ "github.com/go-sql-driver/mysql"
	"github.com/valyala/fasthttp"
	"github.com/valyala/fasthttp/reuseport"
)

type Message struct {
	Message string `json:"message"`
}

type World struct {
	Id           uint16 `json:"id"`
	RandomNumber uint16 `json:"randomNumber"`
}

type Fortune struct {
	Id      uint16 `json:"id"`
	Message string `json:"message"`
}

// Databases
const (
	connectionString   = "benchmarkdbuser:benchmarkdbpass@tcp(localhost:3306)/hello_world?interpolateParams=true"
	worldRowCount      = 10000
	maxConnectionCount = 256
)

var (
	worldSelectStmt   *sql.Stmt
	worldUpdateStmt   *sql.Stmt
	fortuneSelectStmt *sql.Stmt
)

const helloWorldString = "Hello, World!"

var (
	// Templates
	tmpl = template.Must(template.ParseFiles("templates/layout.html", "templates/fortune.html"))

	// Database
	db *sql.DB

	helloWorldBytes = []byte(helloWorldString)
)

var (
	listenAddr = flag.String("listenAddr", ":8080", "Address to listen to")
	prefork    = flag.Bool("prefork", false, "use prefork")
	child      = flag.Bool("child", false, "is child proc")
)

func main() {
	flag.Parse()

	var listener net.Listener
	if !*prefork {
		runtime.GOMAXPROCS(runtime.NumCPU())
	} else {
		listener = doPrefork()
	}

	var err error
	db, err = sql.Open("mysql", connectionString)
	if err != nil {
		log.Fatalf("Error opening database: %s", err)
	}
	if err = db.Ping(); err != nil {
		log.Fatalf("Cannot connect to db: %s", err)
	}

	dbConnCount := maxConnectionCount
	if *prefork {
		dbConnCount = (dbConnCount + runtime.NumCPU() - 1) / runtime.NumCPU()
	}
	db.SetMaxIdleConns(dbConnCount)
	db.SetMaxOpenConns(dbConnCount * 2)

	worldSelectStmt = mustPrepare(db, "SELECT id, randomNumber FROM World WHERE id = ?")
	worldUpdateStmt = mustPrepare(db, "UPDATE World SET randomNumber = ? WHERE id = ?")
	fortuneSelectStmt = mustPrepare(db, "SELECT id, message FROM Fortune")

	s := &fasthttp.Server{
		Handler: mainHandler,
		Name:    "fasthttp",
	}
	if !*prefork {
		s.ListenAndServe(*listenAddr)
	} else {
		s.Serve(listener)
	}
}

func mustPrepare(db *sql.DB, query string) *sql.Stmt {
	stmt, err := db.Prepare(query)
	if err != nil {
		log.Fatalf("Error when preparing statement %q: %s", query, err)
	}
	return stmt
}

func doPrefork() net.Listener {
	if !*child {
		children := make([]*exec.Cmd, runtime.NumCPU())
		for i := range children {
			children[i] = exec.Command(os.Args[0], "-prefork", "-child")
			children[i].Stdout = os.Stdout
			children[i].Stderr = os.Stderr
			if err := children[i].Start(); err != nil {
				log.Fatal(err)
			}
		}
		for _, ch := range children {
			if err := ch.Wait(); err != nil {
				log.Print(err)
			}
		}
		os.Exit(0)
		return nil
	}

	runtime.GOMAXPROCS(1)
	listener, err := reuseport.Listen("tcp4", *listenAddr)
	if err != nil {
		log.Fatal(err)
	}
	return listener
}

func mainHandler(ctx *fasthttp.RequestCtx) {
	path := ctx.Path()
	switch {
	case fasthttp.EqualBytesStr(path, "/plaintext"):
		plaintextHandler(ctx)
	case fasthttp.EqualBytesStr(path, "/json"):
		jsonHandler(ctx)
	case fasthttp.EqualBytesStr(path, "/db"):
		dbHandler(ctx)
	case fasthttp.EqualBytesStr(path, "/queries"):
		queriesHandler(ctx)
	case fasthttp.EqualBytesStr(path, "/fortune"):
		fortuneHandler(ctx)
	case fasthttp.EqualBytesStr(path, "/update"):
		updateHandler(ctx)
	default:
		ctx.Error("unexpected path", fasthttp.StatusBadRequest)
	}
}

// Test 1: JSON serialization
func jsonHandler(ctx *fasthttp.RequestCtx) {
	jsonMarshal(ctx, &Message{helloWorldString})
}

// Test 2: Single database query
func dbHandler(ctx *fasthttp.RequestCtx) {
	var w World
	fetchRandomWorld(&w)
	jsonMarshal(ctx, &w)
}

// Test 3: Multiple database queries
func queriesHandler(ctx *fasthttp.RequestCtx) {
	n := getQueriesCount(ctx)

	worlds := make([]World, n)
	for i := 0; i < n; i++ {
		fetchRandomWorld(&worlds[i])
	}

	jsonMarshal(ctx, worlds)
}

// Test 4: Fortunes
func fortuneHandler(ctx *fasthttp.RequestCtx) {
	rows, err := fortuneSelectStmt.Query()
	if err != nil {
		log.Fatalf("Error preparing statement: %v", err)
	}

	fortunes := make(Fortunes, 0, 16)
	for rows.Next() {
		var f Fortune
		if err := rows.Scan(&f.Id, &f.Message); err != nil {
			log.Fatalf("Error scanning fortune row: %s", err)
		}
		fortunes = append(fortunes, &f)
	}
	rows.Close()
	fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."})

	sort.Sort(ByMessage{fortunes})

	ctx.SetContentType("text/html")
	if err := tmpl.Execute(ctx, fortunes); err != nil {
		log.Fatalf("Error executing fortune: %s", err)
	}
}

// Test 5: Database updates
func updateHandler(ctx *fasthttp.RequestCtx) {
	n := getQueriesCount(ctx)

	worlds := make([]World, n)
	for i := 0; i < n; i++ {
		w := &worlds[i]
		fetchRandomWorld(w)
		w.RandomNumber = uint16(randomWorldNum())
	}

	txn, err := db.Begin()
	if err != nil {
		log.Fatalf("Error starting transaction: %s", err)
	}
	stmt := txn.Stmt(worldUpdateStmt)
	for i := 0; i < n; i++ {
		w := &worlds[i]
		if _, err := stmt.Exec(w.RandomNumber, w.Id); err != nil {
			log.Fatalf("Error updating world row %d: %s", i, err)
		}
	}
	if err = txn.Commit(); err != nil {
		log.Fatalf("Error when commiting world rows: %s", err)
	}

	jsonMarshal(ctx, worlds)
}

// Test 6: Plaintext
func plaintextHandler(ctx *fasthttp.RequestCtx) {
	ctx.Success("text/plain", helloWorldBytes)
}

func jsonMarshal(ctx *fasthttp.RequestCtx, v interface{}) {
	ctx.SetContentType("application/json")
	if err := json.NewEncoder(ctx).Encode(v); err != nil {
		log.Fatalf("error in json.Encoder.Encode: %s", err)
	}
}

func fetchRandomWorld(w *World) {
	n := randomWorldNum()
	if err := worldSelectStmt.QueryRow(n).Scan(&w.Id, &w.RandomNumber); err != nil {
		log.Fatalf("Error scanning world row: %s", err)
	}
}

func randomWorldNum() int {
	return rand.Intn(worldRowCount) + 1
}

func getQueriesCount(ctx *fasthttp.RequestCtx) int {
	n := ctx.QueryArgs().GetUintOrZero("queries")
	if n < 1 {
		n = 1
	} else if n > 500 {
		n = 500
	}
	return n
}

type Fortunes []*Fortune

func (s Fortunes) Len() int      { return len(s) }
func (s Fortunes) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

type ByMessage struct{ Fortunes }

func (s ByMessage) Less(i, j int) bool { return s.Fortunes[i].Message < s.Fortunes[j].Message }
<|endoftext|>