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

package persistent

import (
	"fmt"
	"math/rand"
	"reflect"
	"sync/atomic"
	"testing"
)

type mapEntry struct {
	key   int
	value int
}

type validatedMap struct {
	impl     *Map
	expected map[int]int
	deleted  map[mapEntry]struct{}
	seen     map[mapEntry]struct{}
}

func TestSimpleMap(t *testing.T) {
	deletedEntries := make(map[mapEntry]struct{})
	seenEntries := make(map[mapEntry]struct{})

	m1 := &validatedMap{
		impl: NewMap(func(a, b interface{}) bool {
			return a.(int) < b.(int)
		}),
		expected: make(map[int]int),
		deleted:  deletedEntries,
		seen:     seenEntries,
	}

	m3 := m1.clone()
	validateRef(t, m1, m3)
	m3.set(t, 8, 8)
	validateRef(t, m1, m3)
	m3.destroy()

	assertSameMap(t, deletedEntries, map[mapEntry]struct{}{
		{key: 8, value: 8}: {},
	})

	validateRef(t, m1)
	m1.set(t, 1, 1)
	validateRef(t, m1)
	m1.set(t, 2, 2)
	validateRef(t, m1)
	m1.set(t, 3, 3)
	validateRef(t, m1)
	m1.remove(t, 2)
	validateRef(t, m1)
	m1.set(t, 6, 6)
	validateRef(t, m1)

	assertSameMap(t, deletedEntries, map[mapEntry]struct{}{
		{key: 2, value: 2}: {},
		{key: 8, value: 8}: {},
	})

	m2 := m1.clone()
	validateRef(t, m1, m2)
	m1.set(t, 6, 60)
	validateRef(t, m1, m2)
	m1.remove(t, 1)
	validateRef(t, m1, m2)

	gotAllocs := int(testing.AllocsPerRun(10, func() {
		m1.impl.Delete(100)
		m1.impl.Delete(1)
	}))
	wantAllocs := 0
	if gotAllocs != wantAllocs {
		t.Errorf("wanted %d allocs, got %d", wantAllocs, gotAllocs)
	}

	for i := 10; i < 14; i++ {
		m1.set(t, i, i)
		validateRef(t, m1, m2)
	}

	m1.set(t, 10, 100)
	validateRef(t, m1, m2)

	m1.remove(t, 12)
	validateRef(t, m1, m2)

	m2.set(t, 4, 4)
	validateRef(t, m1, m2)
	m2.set(t, 5, 5)
	validateRef(t, m1, m2)

	m1.destroy()

	assertSameMap(t, deletedEntries, map[mapEntry]struct{}{
		{key: 2, value: 2}:    {},
		{key: 6, value: 60}:   {},
		{key: 8, value: 8}:    {},
		{key: 10, value: 10}:  {},
		{key: 10, value: 100}: {},
		{key: 11, value: 11}:  {},
		{key: 12, value: 12}:  {},
		{key: 13, value: 13}:  {},
	})

	m2.set(t, 7, 7)
	validateRef(t, m2)

	m2.destroy()

	assertSameMap(t, seenEntries, deletedEntries)
}

func TestRandomMap(t *testing.T) {
	deletedEntries := make(map[mapEntry]struct{})
	seenEntries := make(map[mapEntry]struct{})

	m := &validatedMap{
		impl: NewMap(func(a, b interface{}) bool {
			return a.(int) < b.(int)
		}),
		expected: make(map[int]int),
		deleted:  deletedEntries,
		seen:     seenEntries,
	}

	keys := make([]int, 0, 1000)
	for i := 0; i < 1000; i++ {
		key := rand.Int()
		m.set(t, key, key)
		keys = append(keys, key)

		if i%10 == 1 {
			index := rand.Intn(len(keys))
			last := len(keys) - 1
			key = keys[index]
			keys[index], keys[last] = keys[last], keys[index]
			keys = keys[:last]

			m.remove(t, key)
		}
	}

	m.destroy()
	assertSameMap(t, seenEntries, deletedEntries)
}

func TestUpdate(t *testing.T) {
	deletedEntries := make(map[mapEntry]struct{})
	seenEntries := make(map[mapEntry]struct{})

	m1 := &validatedMap{
		impl: NewMap(func(a, b interface{}) bool {
			return a.(int) < b.(int)
		}),
		expected: make(map[int]int),
		deleted:  deletedEntries,
		seen:     seenEntries,
	}
	m2 := m1.clone()

	m1.set(t, 1, 1)
	m1.set(t, 2, 2)
	m2.set(t, 2, 20)
	m2.set(t, 3, 3)
	m1.setAll(t, m2)

	m1.destroy()
	m2.destroy()
	assertSameMap(t, seenEntries, deletedEntries)
}

func (vm *validatedMap) onDelete(t *testing.T, key, value int) {
	entry := mapEntry{key: key, value: value}
	if _, ok := vm.deleted[entry]; ok {
		t.Fatalf("tried to delete entry twice, key: %d, value: %d", key, value)
	}
	vm.deleted[entry] = struct{}{}
}

func validateRef(t *testing.T, maps ...*validatedMap) {
	t.Helper()

	actualCountByEntry := make(map[mapEntry]int32)
	nodesByEntry := make(map[mapEntry]map[*mapNode]struct{})
	expectedCountByEntry := make(map[mapEntry]int32)
	for i, m := range maps {
		dfsRef(m.impl.root, actualCountByEntry, nodesByEntry)
		dumpMap(t, fmt.Sprintf("%d:", i), m.impl.root)
	}
	for entry, nodes := range nodesByEntry {
		expectedCountByEntry[entry] = int32(len(nodes))
	}
	assertSameMap(t, expectedCountByEntry, actualCountByEntry)
}

func dfsRef(node *mapNode, countByEntry map[mapEntry]int32, nodesByEntry map[mapEntry]map[*mapNode]struct{}) {
	if node == nil {
		return
	}

	entry := mapEntry{key: node.key.(int), value: node.value.value.(int)}
	countByEntry[entry] = atomic.LoadInt32(&node.value.refCount)

	nodes, ok := nodesByEntry[entry]
	if !ok {
		nodes = make(map[*mapNode]struct{})
		nodesByEntry[entry] = nodes
	}
	nodes[node] = struct{}{}

	dfsRef(node.left, countByEntry, nodesByEntry)
	dfsRef(node.right, countByEntry, nodesByEntry)
}

func dumpMap(t *testing.T, prefix string, n *mapNode) {
	if n == nil {
		t.Logf("%s nil", prefix)
		return
	}
	t.Logf("%s {key: %v, value: %v (ref: %v), ref: %v, weight: %v}", prefix, n.key, n.value.value, n.value.refCount, n.refCount, n.weight)
	dumpMap(t, prefix+"l", n.left)
	dumpMap(t, prefix+"r", n.right)
}

func (vm *validatedMap) validate(t *testing.T) {
	t.Helper()

	validateNode(t, vm.impl.root, vm.impl.less)

	for key, value := range vm.expected {
		entry := mapEntry{key: key, value: value}
		if _, ok := vm.deleted[entry]; ok {
			t.Fatalf("entry is deleted prematurely, key: %d, value: %d", key, value)
		}
	}

	actualMap := make(map[int]int, len(vm.expected))
	vm.impl.Range(func(key, value interface{}) {
		if other, ok := actualMap[key.(int)]; ok {
			t.Fatalf("key is present twice, key: %d, first value: %d, second value: %d", key, value, other)
		}
		actualMap[key.(int)] = value.(int)
	})

	assertSameMap(t, actualMap, vm.expected)
}

func validateNode(t *testing.T, node *mapNode, less func(a, b interface{}) bool) {
	if node == nil {
		return
	}

	if node.left != nil {
		if less(node.key, node.left.key) {
			t.Fatalf("left child has larger key: %v vs %v", node.left.key, node.key)
		}
		if node.left.weight > node.weight {
			t.Fatalf("left child has larger weight: %v vs %v", node.left.weight, node.weight)
		}
	}

	if node.right != nil {
		if less(node.right.key, node.key) {
			t.Fatalf("right child has smaller key: %v vs %v", node.right.key, node.key)
		}
		if node.right.weight > node.weight {
			t.Fatalf("right child has larger weight: %v vs %v", node.right.weight, node.weight)
		}
	}

	validateNode(t, node.left, less)
	validateNode(t, node.right, less)
}

func (vm *validatedMap) setAll(t *testing.T, other *validatedMap) {
	vm.impl.SetAll(other.impl)
	for key, value := range other.expected {
		vm.expected[key] = value
	}
	vm.validate(t)
}

func (vm *validatedMap) set(t *testing.T, key, value int) {
	vm.seen[mapEntry{key: key, value: value}] = struct{}{}
	vm.impl.Set(key, value, func(deletedKey, deletedValue interface{}) {
		if deletedKey != key || deletedValue != value {
			t.Fatalf("unexpected passed in deleted entry: %v/%v, expected: %v/%v", deletedKey, deletedValue, key, value)
		}
		vm.onDelete(t, key, value)
	})
	vm.expected[key] = value
	vm.validate(t)

	gotValue, ok := vm.impl.Get(key)
	if !ok || gotValue != value {
		t.Fatalf("unexpected get result after insertion, key: %v, expected: %v, got: %v (%v)", key, value, gotValue, ok)
	}
}

func (vm *validatedMap) remove(t *testing.T, key int) {
	vm.impl.Delete(key)
	delete(vm.expected, key)
	vm.validate(t)

	gotValue, ok := vm.impl.Get(key)
	if ok {
		t.Fatalf("unexpected get result after removal, key: %v, got: %v", key, gotValue)
	}
}

func (vm *validatedMap) clone() *validatedMap {
	expected := make(map[int]int, len(vm.expected))
	for key, value := range vm.expected {
		expected[key] = value
	}

	return &validatedMap{
		impl:     vm.impl.Clone(),
		expected: expected,
		deleted:  vm.deleted,
		seen:     vm.seen,
	}
}

func (vm *validatedMap) destroy() {
	vm.impl.Destroy()
}

func assertSameMap(t *testing.T, map1, map2 interface{}) {
	t.Helper()

	if !reflect.DeepEqual(map1, map2) {
		t.Fatalf("different maps:\n%v\nvs\n%v", map1, map2)
	}
}
<commit_msg>internal/persistent: avoid incorrect map validation due to multiple keys<commit_after>// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package persistent

import (
	"fmt"
	"math/rand"
	"reflect"
	"sync/atomic"
	"testing"
)

type mapEntry struct {
	key   int
	value int
}

type validatedMap struct {
	impl     *Map
	expected map[int]int      // current key-value mapping.
	deleted  map[mapEntry]int // maps deleted entries to their clock time of last deletion
	seen     map[mapEntry]int // maps seen entries to their clock time of last insertion
	clock    int
}

func TestSimpleMap(t *testing.T) {
	deletedEntries := make(map[mapEntry]int)
	seenEntries := make(map[mapEntry]int)

	m1 := &validatedMap{
		impl: NewMap(func(a, b interface{}) bool {
			return a.(int) < b.(int)
		}),
		expected: make(map[int]int),
		deleted:  deletedEntries,
		seen:     seenEntries,
	}

	m3 := m1.clone()
	validateRef(t, m1, m3)
	m3.set(t, 8, 8)
	validateRef(t, m1, m3)
	m3.destroy()

	assertSameMap(t, entrySet(deletedEntries), map[mapEntry]struct{}{
		{key: 8, value: 8}: {},
	})

	validateRef(t, m1)
	m1.set(t, 1, 1)
	validateRef(t, m1)
	m1.set(t, 2, 2)
	validateRef(t, m1)
	m1.set(t, 3, 3)
	validateRef(t, m1)
	m1.remove(t, 2)
	validateRef(t, m1)
	m1.set(t, 6, 6)
	validateRef(t, m1)

	assertSameMap(t, entrySet(deletedEntries), map[mapEntry]struct{}{
		{key: 2, value: 2}: {},
		{key: 8, value: 8}: {},
	})

	m2 := m1.clone()
	validateRef(t, m1, m2)
	m1.set(t, 6, 60)
	validateRef(t, m1, m2)
	m1.remove(t, 1)
	validateRef(t, m1, m2)

	gotAllocs := int(testing.AllocsPerRun(10, func() {
		m1.impl.Delete(100)
		m1.impl.Delete(1)
	}))
	wantAllocs := 0
	if gotAllocs != wantAllocs {
		t.Errorf("wanted %d allocs, got %d", wantAllocs, gotAllocs)
	}

	for i := 10; i < 14; i++ {
		m1.set(t, i, i)
		validateRef(t, m1, m2)
	}

	m1.set(t, 10, 100)
	validateRef(t, m1, m2)

	m1.remove(t, 12)
	validateRef(t, m1, m2)

	m2.set(t, 4, 4)
	validateRef(t, m1, m2)
	m2.set(t, 5, 5)
	validateRef(t, m1, m2)

	m1.destroy()

	assertSameMap(t, entrySet(deletedEntries), map[mapEntry]struct{}{
		{key: 2, value: 2}:    {},
		{key: 6, value: 60}:   {},
		{key: 8, value: 8}:    {},
		{key: 10, value: 10}:  {},
		{key: 10, value: 100}: {},
		{key: 11, value: 11}:  {},
		{key: 12, value: 12}:  {},
		{key: 13, value: 13}:  {},
	})

	m2.set(t, 7, 7)
	validateRef(t, m2)

	m2.destroy()

	assertSameMap(t, entrySet(seenEntries), entrySet(deletedEntries))
}

func TestRandomMap(t *testing.T) {
	deletedEntries := make(map[mapEntry]int)
	seenEntries := make(map[mapEntry]int)

	m := &validatedMap{
		impl: NewMap(func(a, b interface{}) bool {
			return a.(int) < b.(int)
		}),
		expected: make(map[int]int),
		deleted:  deletedEntries,
		seen:     seenEntries,
	}

	keys := make([]int, 0, 1000)
	for i := 0; i < 1000; i++ {
		key := rand.Intn(10000)
		m.set(t, key, key)
		keys = append(keys, key)

		if i%10 == 1 {
			index := rand.Intn(len(keys))
			last := len(keys) - 1
			key = keys[index]
			keys[index], keys[last] = keys[last], keys[index]
			keys = keys[:last]

			m.remove(t, key)
		}
	}

	m.destroy()
	assertSameMap(t, entrySet(seenEntries), entrySet(deletedEntries))
}

func entrySet(m map[mapEntry]int) map[mapEntry]struct{} {
	set := make(map[mapEntry]struct{})
	for k := range m {
		set[k] = struct{}{}
	}
	return set
}

func TestUpdate(t *testing.T) {
	deletedEntries := make(map[mapEntry]int)
	seenEntries := make(map[mapEntry]int)

	m1 := &validatedMap{
		impl: NewMap(func(a, b interface{}) bool {
			return a.(int) < b.(int)
		}),
		expected: make(map[int]int),
		deleted:  deletedEntries,
		seen:     seenEntries,
	}
	m2 := m1.clone()

	m1.set(t, 1, 1)
	m1.set(t, 2, 2)
	m2.set(t, 2, 20)
	m2.set(t, 3, 3)
	m1.setAll(t, m2)

	m1.destroy()
	m2.destroy()
	assertSameMap(t, entrySet(seenEntries), entrySet(deletedEntries))
}

func validateRef(t *testing.T, maps ...*validatedMap) {
	t.Helper()

	actualCountByEntry := make(map[mapEntry]int32)
	nodesByEntry := make(map[mapEntry]map[*mapNode]struct{})
	expectedCountByEntry := make(map[mapEntry]int32)
	for i, m := range maps {
		dfsRef(m.impl.root, actualCountByEntry, nodesByEntry)
		dumpMap(t, fmt.Sprintf("%d:", i), m.impl.root)
	}
	for entry, nodes := range nodesByEntry {
		expectedCountByEntry[entry] = int32(len(nodes))
	}
	assertSameMap(t, expectedCountByEntry, actualCountByEntry)
}

func dfsRef(node *mapNode, countByEntry map[mapEntry]int32, nodesByEntry map[mapEntry]map[*mapNode]struct{}) {
	if node == nil {
		return
	}

	entry := mapEntry{key: node.key.(int), value: node.value.value.(int)}
	countByEntry[entry] = atomic.LoadInt32(&node.value.refCount)

	nodes, ok := nodesByEntry[entry]
	if !ok {
		nodes = make(map[*mapNode]struct{})
		nodesByEntry[entry] = nodes
	}
	nodes[node] = struct{}{}

	dfsRef(node.left, countByEntry, nodesByEntry)
	dfsRef(node.right, countByEntry, nodesByEntry)
}

func dumpMap(t *testing.T, prefix string, n *mapNode) {
	if n == nil {
		t.Logf("%s nil", prefix)
		return
	}
	t.Logf("%s {key: %v, value: %v (ref: %v), ref: %v, weight: %v}", prefix, n.key, n.value.value, n.value.refCount, n.refCount, n.weight)
	dumpMap(t, prefix+"l", n.left)
	dumpMap(t, prefix+"r", n.right)
}

func (vm *validatedMap) validate(t *testing.T) {
	t.Helper()

	validateNode(t, vm.impl.root, vm.impl.less)

	// Note: this validation may not make sense if maps were constructed using
	// SetAll operations. If this proves to be problematic, remove the clock,
	// deleted, and seen fields.
	for key, value := range vm.expected {
		entry := mapEntry{key: key, value: value}
		if deleteAt := vm.deleted[entry]; deleteAt > vm.seen[entry] {
			t.Fatalf("entry is deleted prematurely, key: %d, value: %d", key, value)
		}
	}

	actualMap := make(map[int]int, len(vm.expected))
	vm.impl.Range(func(key, value interface{}) {
		if other, ok := actualMap[key.(int)]; ok {
			t.Fatalf("key is present twice, key: %d, first value: %d, second value: %d", key, value, other)
		}
		actualMap[key.(int)] = value.(int)
	})

	assertSameMap(t, actualMap, vm.expected)
}

func validateNode(t *testing.T, node *mapNode, less func(a, b interface{}) bool) {
	if node == nil {
		return
	}

	if node.left != nil {
		if less(node.key, node.left.key) {
			t.Fatalf("left child has larger key: %v vs %v", node.left.key, node.key)
		}
		if node.left.weight > node.weight {
			t.Fatalf("left child has larger weight: %v vs %v", node.left.weight, node.weight)
		}
	}

	if node.right != nil {
		if less(node.right.key, node.key) {
			t.Fatalf("right child has smaller key: %v vs %v", node.right.key, node.key)
		}
		if node.right.weight > node.weight {
			t.Fatalf("right child has larger weight: %v vs %v", node.right.weight, node.weight)
		}
	}

	validateNode(t, node.left, less)
	validateNode(t, node.right, less)
}

func (vm *validatedMap) setAll(t *testing.T, other *validatedMap) {
	vm.impl.SetAll(other.impl)

	// Note: this is buggy because we are not updating vm.clock, vm.deleted, or
	// vm.seen.
	for key, value := range other.expected {
		vm.expected[key] = value
	}
	vm.validate(t)
}

func (vm *validatedMap) set(t *testing.T, key, value int) {
	entry := mapEntry{key: key, value: value}

	vm.clock++
	vm.seen[entry] = vm.clock

	vm.impl.Set(key, value, func(deletedKey, deletedValue interface{}) {
		if deletedKey != key || deletedValue != value {
			t.Fatalf("unexpected passed in deleted entry: %v/%v, expected: %v/%v", deletedKey, deletedValue, key, value)
		}
		// Not safe if closure shared between two validatedMaps.
		vm.deleted[entry] = vm.clock
	})
	vm.expected[key] = value
	vm.validate(t)

	gotValue, ok := vm.impl.Get(key)
	if !ok || gotValue != value {
		t.Fatalf("unexpected get result after insertion, key: %v, expected: %v, got: %v (%v)", key, value, gotValue, ok)
	}
}

func (vm *validatedMap) remove(t *testing.T, key int) {
	vm.clock++
	vm.impl.Delete(key)
	delete(vm.expected, key)
	vm.validate(t)

	gotValue, ok := vm.impl.Get(key)
	if ok {
		t.Fatalf("unexpected get result after removal, key: %v, got: %v", key, gotValue)
	}
}

func (vm *validatedMap) clone() *validatedMap {
	expected := make(map[int]int, len(vm.expected))
	for key, value := range vm.expected {
		expected[key] = value
	}

	return &validatedMap{
		impl:     vm.impl.Clone(),
		expected: expected,
		deleted:  vm.deleted,
		seen:     vm.seen,
	}
}

func (vm *validatedMap) destroy() {
	vm.impl.Destroy()
}

func assertSameMap(t *testing.T, map1, map2 interface{}) {
	t.Helper()

	if !reflect.DeepEqual(map1, map2) {
		t.Fatalf("different maps:\n%v\nvs\n%v", map1, map2)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 save

import (
	"io/ioutil"
	"os"
	"path"
	"syscall"
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/jacobsa/comeback/internal/blob"
	"github.com/jacobsa/comeback/internal/state"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"github.com/jacobsa/timeutil"
)

func TestScoreMap(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type scoreMapTest struct {
	ctx      context.Context
	scoreMap state.ScoreMap
	clock    timeutil.SimulatedClock

	node fsNode

	// A temporary directory removed at the end of the test.
	dir string
}

var _ SetUpInterface = &scoreMapTest{}
var _ TearDownInterface = &scoreMapTest{}

func (t *scoreMapTest) SetUp(ti *TestInfo) {
	var err error

	t.ctx = ti.Ctx
	t.scoreMap = state.NewScoreMap()

	// Set up the clock with a default time far in the future, so that recent
	// modifications in the file system appear old.
	t.clock.SetTime(time.Now().Add(365 * 24 * time.Hour))

	// Set up the directory.
	t.dir, err = ioutil.TempDir("", "score_map_test")
	AssertEq(nil, err)
}

func (t *scoreMapTest) TearDown() {
	var err error

	err = os.RemoveAll(t.dir)
	AssertEq(nil, err)
}

////////////////////////////////////////////////////////////////////////
// makeScoreMapKey
////////////////////////////////////////////////////////////////////////

type MakeScoreMapKeyTest struct {
	scoreMapTest
}

func init() { RegisterTestSuite(&MakeScoreMapKeyTest{}) }

func (t *MakeScoreMapKeyTest) call() (key *state.ScoreMapKey) {
	var err error

	// Set up the Info field.
	t.node.Info, err = os.Lstat(path.Join(t.dir, t.node.RelPath))
	AssertEq(nil, err)

	// Call through.
	key = makeScoreMapKey(&t.node, &t.clock)

	return
}

func (t *MakeScoreMapKeyTest) Directory() {
	key := t.call()
	ExpectEq(nil, key)
}

func (t *MakeScoreMapKeyTest) Symlink() {
	var err error

	// Set up
	t.node.RelPath = "foo"

	err = os.Symlink("blah", path.Join(t.dir, t.node.RelPath))
	AssertEq(nil, err)

	// Call
	key := t.call()
	ExpectEq(nil, key)
}

func (t *MakeScoreMapKeyTest) RecentlyModified() {
	var err error
	var key *state.ScoreMapKey

	// Set up
	t.node.RelPath = "foo"

	f, err := os.Create(path.Join(t.dir, t.node.RelPath))
	AssertEq(nil, err)
	defer f.Close()

	fi, err := f.Stat()
	AssertEq(nil, err)

	// A short while ago
	t.clock.SetTime(fi.ModTime().Add(10 * time.Second))

	key = t.call()
	ExpectEq(nil, key)

	// Now
	t.clock.SetTime(fi.ModTime())

	key = t.call()
	ExpectEq(nil, key)

	// A short while in the future
	t.clock.SetTime(fi.ModTime().Add(-10 * time.Second))

	key = t.call()
	ExpectEq(nil, key)

	// Far in the future
	t.clock.SetTime(fi.ModTime().Add(-365 * 24 * time.Hour))

	key = t.call()
	ExpectEq(nil, key)
}

func (t *MakeScoreMapKeyTest) Valid() {
	var err error

	// Set up
	t.node.RelPath = "foo"

	f, err := os.Create(path.Join(t.dir, t.node.RelPath))
	AssertEq(nil, err)
	defer f.Close()

	_, err = f.Write([]byte("tacoburrito"))
	AssertEq(nil, err)

	fi, err := f.Stat()
	AssertEq(nil, err)

	// Call
	key := t.call()
	AssertNe(nil, key)

	ExpectEq(t.node.RelPath, key.Path)
	ExpectEq(fi.Mode()&os.ModePerm, key.Permissions)
	ExpectEq(fi.Sys().(*syscall.Stat_t).Uid, key.Uid)
	ExpectEq(fi.Sys().(*syscall.Stat_t).Gid, key.Gid)
	ExpectThat(key.MTime, timeutil.TimeEq(fi.ModTime()))
	ExpectEq(fi.Sys().(*syscall.Stat_t).Ino, key.Inode)
	ExpectEq(fi.Size(), key.Size)
}

////////////////////////////////////////////////////////////////////////
// consultScoreMap
////////////////////////////////////////////////////////////////////////

type ConsultScoreMapTest struct {
	scoreMapTest
	expectedKey *state.ScoreMapKey
}

func init() { RegisterTestSuite(&ConsultScoreMapTest{}) }

func (t *ConsultScoreMapTest) SetUp(ti *TestInfo) {
	t.scoreMapTest.SetUp(ti)
	var err error

	// Make sure the node is eligible by default.
	t.node.RelPath = "foo"

	f, err := os.Create(path.Join(t.dir, t.node.RelPath))
	AssertEq(nil, err)
	defer f.Close()

	t.node.Info, err = f.Stat()
	AssertEq(nil, err)

	t.expectedKey = makeScoreMapKey(&t.node, &t.clock)
	AssertNe(nil, t.expectedKey)
}

func (t *ConsultScoreMapTest) call() (err error) {
	nodesIn := make(chan *fsNode, 1)
	nodesIn <- &t.node
	close(nodesIn)

	err = consultScoreMap(
		t.ctx,
		t.scoreMap,
		&t.clock,
		nodesIn,
		make(chan *fsNode, 1)) // Ignore output

	return
}

func (t *ConsultScoreMapTest) NodeNotEligible() {
	var err error

	// Make the node appear as a directory.
	t.node.Info, err = os.Stat(t.dir)
	AssertEq(nil, err)

	// Call. Nothing should be changed about the Scores field.
	err = t.call()
	AssertEq(nil, err)

	ExpectEq(nil, t.node.Scores)
	ExpectEq(nil, t.node.scoreMapKey)
}

func (t *ConsultScoreMapTest) PresentInScoreMap() {
	var err error

	// Prepare score map
	score1 := blob.ComputeScore([]byte("taco"))
	score2 := blob.ComputeScore([]byte("burrito"))

	t.scoreMap.Set(*t.expectedKey, []blob.Score{score1, score2})

	// Call
	err = t.call()
	AssertEq(nil, err)

	ExpectThat(t.node.Scores, ElementsAre(score1, score2))
	ExpectEq(nil, t.node.scoreMapKey)
}

func (t *ConsultScoreMapTest) AbsentInScoreMap() {
	var err error

	// Call
	err = t.call()
	AssertEq(nil, err)

	ExpectEq(nil, t.node.Scores)
	ExpectThat(t.node.scoreMapKey, Pointee(DeepEquals(*t.expectedKey)))
}

////////////////////////////////////////////////////////////////////////
// updateScoreMap
////////////////////////////////////////////////////////////////////////

type UpdateScoreMapTest struct {
	scoreMapTest
	expectedKey *state.ScoreMapKey
}

func init() { RegisterTestSuite(&UpdateScoreMapTest{}) }

func (t *UpdateScoreMapTest) SetUp(ti *TestInfo) {
	t.scoreMapTest.SetUp(ti)
	var err error

	// Make sure the node is eligible by default.
	t.node.RelPath = "foo"

	f, err := os.Create(path.Join(t.dir, t.node.RelPath))
	AssertEq(nil, err)
	defer f.Close()

	t.node.Info, err = f.Stat()
	AssertEq(nil, err)

	t.expectedKey = makeScoreMapKey(&t.node, &t.clock)
	AssertNe(nil, t.expectedKey)
}

func (t *UpdateScoreMapTest) call() (err error) {
	nodesIn := make(chan *fsNode, 1)
	nodesIn <- &t.node
	close(nodesIn)

	err = updateScoreMap(t.ctx, t.scoreMap, nodesIn)
	return
}

func (t *UpdateScoreMapTest) NodeNotEligible() {
	var err error

	// Make the node appear as a directory.
	t.node.Info, err = os.Stat(t.dir)
	AssertEq(nil, err)

	// Nothing bad should happen.
	err = t.call()
	AssertEq(nil, err)
}

func (t *UpdateScoreMapTest) NodeWasAlreadyPresent() {
	var err error

	// Prepare
	t.node.Scores = []blob.Score{
		blob.ComputeScore([]byte("taco")),
		blob.ComputeScore([]byte("burrito")),
	}

	t.node.scoreMapKey = nil

	// Call
	err = t.call()
	AssertEq(nil, err)
	ExpectEq(nil, t.scoreMap.Get(*t.expectedKey))
}

func (t *UpdateScoreMapTest) NodeWasntAlreadyPresent() {
	var err error

	// Prepare
	t.node.Scores = []blob.Score{
		blob.ComputeScore([]byte("taco")),
		blob.ComputeScore([]byte("burrito")),
	}

	t.node.scoreMapKey = t.expectedKey

	// Call
	err = t.call()
	AssertEq(nil, err)

	ExpectThat(
		t.scoreMap.Get(*t.expectedKey),
		ElementsAre(t.node.Scores[0], t.node.Scores[1]))
}
<commit_msg>Fixed score_map_test.go.<commit_after>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 save

import (
	"os"
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/jacobsa/comeback/internal/blob"
	"github.com/jacobsa/comeback/internal/fs"
	"github.com/jacobsa/comeback/internal/state"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"github.com/jacobsa/timeutil"
)

func TestScoreMap(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type scoreMapTest struct {
	ctx      context.Context
	scoreMap state.ScoreMap
	clock    timeutil.SimulatedClock

	node fsNode
}

var _ SetUpInterface = &scoreMapTest{}

func (t *scoreMapTest) SetUp(ti *TestInfo) {
	t.ctx = ti.Ctx
	t.scoreMap = state.NewScoreMap()
	t.clock.SetTime(time.Date(2012, time.August, 15, 12, 56, 00, 0, time.Local))
}

////////////////////////////////////////////////////////////////////////
// makeScoreMapKey
////////////////////////////////////////////////////////////////////////

type MakeScoreMapKeyTest struct {
	scoreMapTest
}

func init() { RegisterTestSuite(&MakeScoreMapKeyTest{}) }

func (t *MakeScoreMapKeyTest) call() (key *state.ScoreMapKey) {
	key = makeScoreMapKey(&t.node, &t.clock)
	return
}

func (t *MakeScoreMapKeyTest) Directory() {
	t.node.Info.Type = fs.TypeDirectory

	key := t.call()
	ExpectEq(nil, key)
}

func (t *MakeScoreMapKeyTest) Symlink() {
	// Set up
	t.node.RelPath = "foo"
	t.node.Info = fs.DirectoryEntry{
		Type: fs.TypeSymlink,
	}

	// Call
	key := t.call()
	ExpectEq(nil, key)
}

func (t *MakeScoreMapKeyTest) RecentlyModified() {
	var key *state.ScoreMapKey

	// Set up
	t.node.RelPath = "foo"
	t.node.Info = fs.DirectoryEntry{
		Type: fs.TypeFile,
	}

	// A short while ago
	t.node.Info.MTime = t.clock.Now().Add(-10 * time.Second)
	key = t.call()
	ExpectEq(nil, key)

	// Now
	t.node.Info.MTime = t.clock.Now()
	key = t.call()
	ExpectEq(nil, key)

	// A short while in the future
	t.node.Info.MTime = t.clock.Now().Add(10 * time.Second)
	key = t.call()
	ExpectEq(nil, key)

	// Far in the future
	t.node.Info.MTime = t.clock.Now().Add(365 * 24 * time.Hour)
	key = t.call()
	ExpectEq(nil, key)
}

func (t *MakeScoreMapKeyTest) Valid() {
	// Set up
	t.node.RelPath = "foo"
	t.node.Info = fs.DirectoryEntry{
		Permissions: 0745,
		Uid:         17,
		Gid:         19,
		MTime:       t.clock.Now().Add(-10 * time.Hour),
		Inode:       23,
		Size:        31,
	}

	// Call
	key := t.call()
	AssertNe(nil, key)

	ExpectEq(t.node.RelPath, key.Path)
	ExpectEq(os.FileMode(0745), key.Permissions)
	ExpectEq(17, key.Uid)
	ExpectEq(19, key.Gid)
	ExpectThat(key.MTime, timeutil.TimeEq(t.node.Info.MTime))
	ExpectEq(23, key.Inode)
	ExpectEq(31, key.Size)
}

////////////////////////////////////////////////////////////////////////
// consultScoreMap
////////////////////////////////////////////////////////////////////////

type ConsultScoreMapTest struct {
	scoreMapTest
	expectedKey *state.ScoreMapKey
}

func init() { RegisterTestSuite(&ConsultScoreMapTest{}) }

func (t *ConsultScoreMapTest) SetUp(ti *TestInfo) {
	t.scoreMapTest.SetUp(ti)

	// Make sure the node is eligible by default.
	t.node.RelPath = "foo"
	t.node.Info = fs.DirectoryEntry{
		Type:  fs.TypeFile,
		MTime: t.clock.Now().Add(-10 * time.Hour),
	}

	t.expectedKey = makeScoreMapKey(&t.node, &t.clock)
	AssertNe(nil, t.expectedKey)
}

func (t *ConsultScoreMapTest) call() (err error) {
	nodesIn := make(chan *fsNode, 1)
	nodesIn <- &t.node
	close(nodesIn)

	err = consultScoreMap(
		t.ctx,
		t.scoreMap,
		&t.clock,
		nodesIn,
		make(chan *fsNode, 1)) // Ignore output

	return
}

func (t *ConsultScoreMapTest) NodeNotEligible() {
	var err error

	// Make the node appear as a directory.
	t.node.Info.Type = fs.TypeDirectory

	// Call. Nothing should be changed about the Scores field.
	err = t.call()
	AssertEq(nil, err)

	ExpectEq(nil, t.node.Scores)
	ExpectEq(nil, t.node.scoreMapKey)
}

func (t *ConsultScoreMapTest) PresentInScoreMap() {
	var err error

	// Prepare score map
	score1 := blob.ComputeScore([]byte("taco"))
	score2 := blob.ComputeScore([]byte("burrito"))

	t.scoreMap.Set(*t.expectedKey, []blob.Score{score1, score2})

	// Call
	err = t.call()
	AssertEq(nil, err)

	ExpectThat(t.node.Scores, ElementsAre(score1, score2))
	ExpectEq(nil, t.node.scoreMapKey)
}

func (t *ConsultScoreMapTest) AbsentInScoreMap() {
	var err error

	// Call
	err = t.call()
	AssertEq(nil, err)

	ExpectEq(nil, t.node.Scores)
	ExpectThat(t.node.scoreMapKey, Pointee(DeepEquals(*t.expectedKey)))
}

////////////////////////////////////////////////////////////////////////
// updateScoreMap
////////////////////////////////////////////////////////////////////////

type UpdateScoreMapTest struct {
	scoreMapTest
}

func init() { RegisterTestSuite(&UpdateScoreMapTest{}) }

func (t *UpdateScoreMapTest) call() (err error) {
	nodesIn := make(chan *fsNode, 1)
	nodesIn <- &t.node
	close(nodesIn)

	err = updateScoreMap(t.ctx, t.scoreMap, nodesIn)
	return
}

func (t *UpdateScoreMapTest) ScoreMapKeyMissing() {
	var err error

	// Prepare
	t.node.Scores = []blob.Score{
		blob.ComputeScore([]byte("taco")),
		blob.ComputeScore([]byte("burrito")),
	}

	t.node.scoreMapKey = nil

	// Call
	err = t.call()
	AssertEq(nil, err)
}

func (t *UpdateScoreMapTest) ScoreMapKeyPresent() {
	var err error

	// Prepare
	t.node.Scores = []blob.Score{
		blob.ComputeScore([]byte("taco")),
		blob.ComputeScore([]byte("burrito")),
	}

	t.node.scoreMapKey = &state.ScoreMapKey{
		Uid: 17,
	}

	// Call
	err = t.call()
	AssertEq(nil, err)

	ExpectThat(
		t.scoreMap.Get(*t.node.scoreMapKey),
		ElementsAre(t.node.Scores[0], t.node.Scores[1]))
}
<|endoftext|>


<commit_before>// Copyright 2015 The Vanadium 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 testutil

import (
	"path/filepath"
	"time"

	"v.io/x/devtools/internal/collect"
	"v.io/x/devtools/internal/runutil"
	"v.io/x/devtools/internal/tool"
	"v.io/x/devtools/internal/util"
	"v.io/x/devtools/internal/xunit"
)

const (
	defaultJSTestTimeout = 10 * time.Minute
)

// runJSTest is a harness for executing javascript tests.
func runJSTest(ctx *tool.Context, testName, testDir, target string, cleanFn func() error, env map[string]string) (_ *TestResult, e error) {
	// Initialize the test.
	cleanup, err := initTest(ctx, testName, []string{"web"})
	if err != nil {
		return nil, internalTestError{err, "Init"}
	}
	defer collect.Error(func() error { return cleanup() }, &e)

	// Navigate to the target directory.
	if err := ctx.Run().Chdir(testDir); err != nil {
		return nil, err
	}

	// Clean up after previous instances of the test.
	opts := ctx.Run().Opts()
	for key, value := range env {
		opts.Env[key] = value
	}
	if err := ctx.Run().CommandWithOpts(opts, "make", "clean"); err != nil {
		return nil, err
	}
	if cleanFn != nil {
		if err := cleanFn(); err != nil {
			return nil, err
		}
	}

	// Run the test target.
	if err := ctx.Run().TimedCommandWithOpts(defaultJSTestTimeout, opts, "make", target); err != nil {
		if err == runutil.CommandTimedOutErr {
			return &TestResult{
				Status:       TestTimedOut,
				TimeoutValue: defaultJSTestTimeout,
			}, nil
		} else {
			return nil, internalTestError{err, "Make " + target}
		}
	}

	return &TestResult{Status: TestPassed}, nil
}

// vanadiumJSBuildExtension tests the vanadium javascript build extension.
func vanadiumJSBuildExtension(ctx *tool.Context, testName string, _ ...TestOpt) (*TestResult, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	testDir := filepath.Join(root, "release", "javascript", "core")
	target := "extension/vanadium.zip"
	return runJSTest(ctx, testName, testDir, target, nil, nil)
}

// vanadiumJSDoc (re)generates the content of the vanadium javascript
// documentation server.
func vanadiumJSDoc(ctx *tool.Context, testName string, _ ...TestOpt) (*TestResult, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	testDir := filepath.Join(root, "release", "javascript", "core")
	target := "docs"

	result, err := runJSTest(ctx, testName, testDir, target, nil, nil)
	if err != nil {
		return nil, err
	}

	return result, nil
}

// vanadiumJSBrowserIntegration runs the vanadium javascript integration test in a browser environment using nacl plugin.
func vanadiumJSBrowserIntegration(ctx *tool.Context, testName string, _ ...TestOpt) (*TestResult, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	testDir := filepath.Join(root, "release", "javascript", "core")
	target := "test-integration-browser"
	env := map[string]string{}
	setCommonJSEnv(env)
	env["BROWSER_OUTPUT"] = xunit.ReportPath(testName)
	return runJSTest(ctx, testName, testDir, target, nil, env)
}

// vanadiumJSNodeIntegration runs the vanadium javascript integration test in NodeJS environment using wspr.
func vanadiumJSNodeIntegration(ctx *tool.Context, testName string, _ ...TestOpt) (*TestResult, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	testDir := filepath.Join(root, "release", "javascript", "core")
	target := "test-integration-node"
	env := map[string]string{}
	setCommonJSEnv(env)
	env["NODE_OUTPUT"] = xunit.ReportPath(testName)
	return runJSTest(ctx, testName, testDir, target, nil, env)
}

// vanadiumJSUnit runs the vanadium javascript unit test.
func vanadiumJSUnit(ctx *tool.Context, testName string, _ ...TestOpt) (*TestResult, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	testDir := filepath.Join(root, "release", "javascript", "core")
	target := "test-unit"
	env := map[string]string{}
	setCommonJSEnv(env)
	env["NODE_OUTPUT"] = xunit.ReportPath(testName)
	return runJSTest(ctx, testName, testDir, target, nil, env)
}

// vanadiumJSVdl runs the vanadium javascript vdl test.
func vanadiumJSVdl(ctx *tool.Context, testName string, _ ...TestOpt) (*TestResult, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	testDir := filepath.Join(root, "release", "javascript", "core")
	target := "test-vdl"
	env := map[string]string{}
	setCommonJSEnv(env)
	env["NODE_OUTPUT"] = xunit.ReportPath(testName)
	return runJSTest(ctx, testName, testDir, target, nil, env)
}

// vanadiumJSVom runs the vanadium javascript vom test.
func vanadiumJSVom(ctx *tool.Context, testName string, _ ...TestOpt) (*TestResult, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	testDir := filepath.Join(root, "release", "javascript", "core")
	target := "test-vom"
	env := map[string]string{}
	setCommonJSEnv(env)
	env["NODE_OUTPUT"] = xunit.ReportPath(testName)
	return runJSTest(ctx, testName, testDir, target, nil, env)
}

func setCommonJSEnv(env map[string]string) {
	env["XUNIT"] = "true"
}
<commit_msg>TBR: devtools/internal/testutil: increase timeout of js tests to 15 minutes.<commit_after>// Copyright 2015 The Vanadium 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 testutil

import (
	"path/filepath"
	"time"

	"v.io/x/devtools/internal/collect"
	"v.io/x/devtools/internal/runutil"
	"v.io/x/devtools/internal/tool"
	"v.io/x/devtools/internal/util"
	"v.io/x/devtools/internal/xunit"
)

const (
	defaultJSTestTimeout = 15 * time.Minute
)

// runJSTest is a harness for executing javascript tests.
func runJSTest(ctx *tool.Context, testName, testDir, target string, cleanFn func() error, env map[string]string) (_ *TestResult, e error) {
	// Initialize the test.
	cleanup, err := initTest(ctx, testName, []string{"web"})
	if err != nil {
		return nil, internalTestError{err, "Init"}
	}
	defer collect.Error(func() error { return cleanup() }, &e)

	// Navigate to the target directory.
	if err := ctx.Run().Chdir(testDir); err != nil {
		return nil, err
	}

	// Clean up after previous instances of the test.
	opts := ctx.Run().Opts()
	for key, value := range env {
		opts.Env[key] = value
	}
	if err := ctx.Run().CommandWithOpts(opts, "make", "clean"); err != nil {
		return nil, err
	}
	if cleanFn != nil {
		if err := cleanFn(); err != nil {
			return nil, err
		}
	}

	// Run the test target.
	if err := ctx.Run().TimedCommandWithOpts(defaultJSTestTimeout, opts, "make", target); err != nil {
		if err == runutil.CommandTimedOutErr {
			return &TestResult{
				Status:       TestTimedOut,
				TimeoutValue: defaultJSTestTimeout,
			}, nil
		} else {
			return nil, internalTestError{err, "Make " + target}
		}
	}

	return &TestResult{Status: TestPassed}, nil
}

// vanadiumJSBuildExtension tests the vanadium javascript build extension.
func vanadiumJSBuildExtension(ctx *tool.Context, testName string, _ ...TestOpt) (*TestResult, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	testDir := filepath.Join(root, "release", "javascript", "core")
	target := "extension/vanadium.zip"
	return runJSTest(ctx, testName, testDir, target, nil, nil)
}

// vanadiumJSDoc (re)generates the content of the vanadium javascript
// documentation server.
func vanadiumJSDoc(ctx *tool.Context, testName string, _ ...TestOpt) (*TestResult, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	testDir := filepath.Join(root, "release", "javascript", "core")
	target := "docs"

	result, err := runJSTest(ctx, testName, testDir, target, nil, nil)
	if err != nil {
		return nil, err
	}

	return result, nil
}

// vanadiumJSBrowserIntegration runs the vanadium javascript integration test in a browser environment using nacl plugin.
func vanadiumJSBrowserIntegration(ctx *tool.Context, testName string, _ ...TestOpt) (*TestResult, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	testDir := filepath.Join(root, "release", "javascript", "core")
	target := "test-integration-browser"
	env := map[string]string{}
	setCommonJSEnv(env)
	env["BROWSER_OUTPUT"] = xunit.ReportPath(testName)
	return runJSTest(ctx, testName, testDir, target, nil, env)
}

// vanadiumJSNodeIntegration runs the vanadium javascript integration test in NodeJS environment using wspr.
func vanadiumJSNodeIntegration(ctx *tool.Context, testName string, _ ...TestOpt) (*TestResult, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	testDir := filepath.Join(root, "release", "javascript", "core")
	target := "test-integration-node"
	env := map[string]string{}
	setCommonJSEnv(env)
	env["NODE_OUTPUT"] = xunit.ReportPath(testName)
	return runJSTest(ctx, testName, testDir, target, nil, env)
}

// vanadiumJSUnit runs the vanadium javascript unit test.
func vanadiumJSUnit(ctx *tool.Context, testName string, _ ...TestOpt) (*TestResult, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	testDir := filepath.Join(root, "release", "javascript", "core")
	target := "test-unit"
	env := map[string]string{}
	setCommonJSEnv(env)
	env["NODE_OUTPUT"] = xunit.ReportPath(testName)
	return runJSTest(ctx, testName, testDir, target, nil, env)
}

// vanadiumJSVdl runs the vanadium javascript vdl test.
func vanadiumJSVdl(ctx *tool.Context, testName string, _ ...TestOpt) (*TestResult, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	testDir := filepath.Join(root, "release", "javascript", "core")
	target := "test-vdl"
	env := map[string]string{}
	setCommonJSEnv(env)
	env["NODE_OUTPUT"] = xunit.ReportPath(testName)
	return runJSTest(ctx, testName, testDir, target, nil, env)
}

// vanadiumJSVom runs the vanadium javascript vom test.
func vanadiumJSVom(ctx *tool.Context, testName string, _ ...TestOpt) (*TestResult, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	testDir := filepath.Join(root, "release", "javascript", "core")
	target := "test-vom"
	env := map[string]string{}
	setCommonJSEnv(env)
	env["NODE_OUTPUT"] = xunit.ReportPath(testName)
	return runJSTest(ctx, testName, testDir, target, nil, env)
}

func setCommonJSEnv(env map[string]string) {
	env["XUNIT"] = "true"
}
<|endoftext|>


<commit_before>package coremain

// Various CoreDNS constants.
const (
	CoreVersion = "1.6.3"
	coreName    = "CoreDNS"
	serverType  = "dns"
)
<commit_msg>Set version to 1.6.4 (#3317)<commit_after>package coremain

// Various CoreDNS constants.
const (
	CoreVersion = "1.6.4"
	coreName    = "CoreDNS"
	serverType  = "dns"
)
<|endoftext|>


<commit_before>package point

import (
	"sync"
	"time"

	"github.com/v2ray/v2ray-core/app"
	"github.com/v2ray/v2ray-core/common/dice"
	"github.com/v2ray/v2ray-core/common/log"
	v2net "github.com/v2ray/v2ray-core/common/net"
	"github.com/v2ray/v2ray-core/common/retry"
	"github.com/v2ray/v2ray-core/proxy"
	proxyrepo "github.com/v2ray/v2ray-core/proxy/repo"
)

type InboundDetourHandlerDynamic struct {
	sync.RWMutex
	space       app.Space
	config      *InboundDetourConfig
	portsInUse  map[v2net.Port]bool
	ichInUse    []*InboundConnectionHandlerWithPort
	ich2Recycle []*InboundConnectionHandlerWithPort
	lastRefresh time.Time
	started     bool
}

func NewInboundDetourHandlerDynamic(space app.Space, config *InboundDetourConfig) (*InboundDetourHandlerDynamic, error) {
	handler := &InboundDetourHandlerDynamic{
		space:      space,
		config:     config,
		portsInUse: make(map[v2net.Port]bool),
	}
	if err := handler.refresh(); err != nil {
		return nil, err
	}
	return handler, nil
}

func (this *InboundDetourHandlerDynamic) refresh() error {
	this.Lock()
	defer this.Unlock()

	this.ich2Recycle, this.ichInUse = this.ichInUse, this.ich2Recycle
	if this.ich2Recycle != nil {
		time.AfterFunc(time.Minute, func() {
			for i := 0; i < len(this.ich2Recycle); i++ {
				ich := this.ich2Recycle[i]
				if ich != nil {
					ich.handler.Close()
					delete(this.portsInUse, ich.port)
				}
				this.ich2Recycle[i] = nil
			}
		})
	}

	ichCount := this.config.Allocation.Concurrency
	// TODO: check ichCount
	if this.ichInUse == nil {
		this.ichInUse = make([]*InboundConnectionHandlerWithPort, ichCount)
	}

	for idx, _ := range this.ichInUse {
		port := this.pickUnusedPort()
		ich, err := proxyrepo.CreateInboundConnectionHandler(this.config.Protocol, this.space, this.config.Settings)
		if err != nil {
			log.Error("Point: Failed to create inbound connection handler: ", err)
			return err
		}
		this.ichInUse[idx] = &InboundConnectionHandlerWithPort{
			port:    port,
			handler: ich,
		}
	}
	if this.started {
		this.Start()
	}

	this.lastRefresh = time.Now()
	time.AfterFunc(time.Duration(this.config.Allocation.Refresh)*time.Minute, func() {
		this.refresh()
	})

	return nil
}

func (this *InboundDetourHandlerDynamic) pickUnusedPort() v2net.Port {
	delta := int(this.config.PortRange.To) - int(this.config.PortRange.From) + 1
	for {
		r := dice.Roll(delta)
		port := this.config.PortRange.From + v2net.Port(r)
		_, used := this.portsInUse[port]
		if !used {
			this.portsInUse[port] = true
			return port
		}
	}
}

func (this *InboundDetourHandlerDynamic) GetConnectionHandler() (proxy.InboundConnectionHandler, int) {
	this.RLock()
	defer this.RUnlock()
	ich := this.ichInUse[dice.Roll(len(this.ichInUse))]
	until := this.config.Allocation.Refresh - int((time.Now().Unix()-this.lastRefresh.Unix())/60/1000)
	if until < 0 {
		until = 0
	}
	return ich.handler, int(until)
}

func (this *InboundDetourHandlerDynamic) Close() {
	this.Lock()
	defer this.Unlock()
	for _, ich := range this.ichInUse {
		ich.handler.Close()
	}
	if this.ich2Recycle != nil {
		for _, ich := range this.ich2Recycle {
			if ich != nil && ich.handler != nil {
				ich.handler.Close()
			}
		}
	}
}

func (this *InboundDetourHandlerDynamic) Start() error {
	for _, ich := range this.ichInUse {
		err := retry.Timed(100 /* times */, 100 /* ms */).On(func() error {
			err := ich.handler.Listen(ich.port)
			if err != nil {
				log.Error("Point: Failed to start inbound detour on port ", ich.port, ": ", err)
				return err
			}
			return nil
		})
		if err != nil {
			return err
		}
	}
	this.started = true
	return nil
}
<commit_msg>reuse connection handler<commit_after>package point

import (
	"sync"
	"time"

	"github.com/v2ray/v2ray-core/app"
	"github.com/v2ray/v2ray-core/common/dice"
	"github.com/v2ray/v2ray-core/common/log"
	v2net "github.com/v2ray/v2ray-core/common/net"
	"github.com/v2ray/v2ray-core/common/retry"
	"github.com/v2ray/v2ray-core/proxy"
	proxyrepo "github.com/v2ray/v2ray-core/proxy/repo"
)

type InboundDetourHandlerDynamic struct {
	sync.RWMutex
	space       app.Space
	config      *InboundDetourConfig
	portsInUse  map[v2net.Port]bool
	ichInUse    []*InboundConnectionHandlerWithPort
	ich2Recycle []*InboundConnectionHandlerWithPort
	lastRefresh time.Time
}

func NewInboundDetourHandlerDynamic(space app.Space, config *InboundDetourConfig) (*InboundDetourHandlerDynamic, error) {
	handler := &InboundDetourHandlerDynamic{
		space:      space,
		config:     config,
		portsInUse: make(map[v2net.Port]bool),
	}
	ichCount := config.Allocation.Concurrency
	ichArray := make([]*InboundConnectionHandlerWithPort, ichCount*2)
	for idx, _ := range ichArray {
		//port := handler.pickUnusedPort()
		ich, err := proxyrepo.CreateInboundConnectionHandler(config.Protocol, space, config.Settings)
		if err != nil {
			log.Error("Point: Failed to create inbound connection handler: ", err)
			return nil, err
		}
		ichArray[idx] = &InboundConnectionHandlerWithPort{
			port:    0,
			handler: ich,
		}
	}
	handler.ichInUse = ichArray[:ichCount]
	handler.ich2Recycle = ichArray[ichCount:]
	return handler, nil
}

func (this *InboundDetourHandlerDynamic) pickUnusedPort() v2net.Port {
	delta := int(this.config.PortRange.To) - int(this.config.PortRange.From) + 1
	for {
		r := dice.Roll(delta)
		port := this.config.PortRange.From + v2net.Port(r)
		_, used := this.portsInUse[port]
		if !used {
			this.portsInUse[port] = true
			return port
		}
	}
}

func (this *InboundDetourHandlerDynamic) GetConnectionHandler() (proxy.InboundConnectionHandler, int) {
	this.RLock()
	defer this.RUnlock()
	ich := this.ichInUse[dice.Roll(len(this.ichInUse))]
	until := this.config.Allocation.Refresh - int((time.Now().Unix()-this.lastRefresh.Unix())/60/1000)
	if until < 0 {
		until = 0
	}
	return ich.handler, int(until)
}

func (this *InboundDetourHandlerDynamic) Close() {
	this.Lock()
	defer this.Unlock()
	for _, ich := range this.ichInUse {
		ich.handler.Close()
	}
	if this.ich2Recycle != nil {
		for _, ich := range this.ich2Recycle {
			if ich != nil && ich.handler != nil {
				ich.handler.Close()
			}
		}
	}
}

func (this *InboundDetourHandlerDynamic) Start() error {
	this.Lock()
	defer this.Unlock()

	this.ich2Recycle, this.ichInUse = this.ichInUse, this.ich2Recycle
	time.AfterFunc(time.Minute, func() {
		this.Lock()
		defer this.Unlock()
		for _, ich := range this.ich2Recycle {
			if ich != nil {
				ich.handler.Close()
				delete(this.portsInUse, ich.port)
			}
		}
	})

	this.lastRefresh = time.Now()
	time.AfterFunc(time.Duration(this.config.Allocation.Refresh)*time.Minute, func() {
		this.Start()
	})

	for _, ich := range this.ichInUse {
		port := this.pickUnusedPort()
		ich.port = port
		err := retry.Timed(100 /* times */, 100 /* ms */).On(func() error {
			err := ich.handler.Listen(ich.port)
			if err != nil {
				log.Error("Point: Failed to start inbound detour on port ", ich.port, ": ", err)
				return err
			}
			return nil
		})
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright ©2014 The gonum 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 stat

import (
	"math"

	"github.com/gonum/floats"
	"github.com/gonum/matrix/mat64"
)

// CovarianceMatrix calculates a covariance matrix (also known as a
// variance-covariance matrix) from a matrix of data, using a two-pass
// algorithm.
//
// The weights must have length equal to the number of rows in
// input data matrix x. If cov is nil, then a new matrix with appropriate size will
// be constructed. If cov is not nil, it should have the same number of columns as the
// input data matrix x, and it will be used as the destination for the covariance
// data. Weights must not be negative.
func CovarianceMatrix(cov *mat64.SymDense, x mat64.Matrix, weights []float64) *mat64.SymDense {
	// This is the matrix version of the two-pass algorithm. It doesn't use the
	// additional floating point error correction that the Covariance function uses
	// to reduce the impact of rounding during centering.

	r, c := x.Dims()

	if cov == nil {
		cov = mat64.NewSymDense(c, nil)
	} else if n := cov.Symmetric(); n != c {
		panic(mat64.ErrShape)
	}

	var xt mat64.Dense
	xt.Clone(x.T())
	// Subtract the mean of each of the columns.
	for i := 0; i < c; i++ {
		v := xt.RawRowView(i)
		// This will panic with ErrShape if len(weights) != len(v), so
		// we don't have to check the size later.
		mean := Mean(v, weights)
		floats.AddConst(-mean, v)
	}

	if weights == nil {
		// Calculate the normalization factor
		// scaled by the sample size.
		cov.SymOuterK(1/(float64(r)-1), &xt)
		return cov
	}

	// Multiply by the sqrt of the weights, so that multiplication is symmetric.
	sqrtwts := make([]float64, r)
	for i, w := range weights {
		if w < 0 {
			panic("stat: negative covariance matrix weights")
		}
		sqrtwts[i] = math.Sqrt(w)
	}
	// Weight the rows.
	for i := 0; i < c; i++ {
		v := xt.RawRowView(i)
		floats.Mul(v, sqrtwts)
	}

	// Calculate the normalization factor
	// scaled by the weighted sample size.
	cov.SymOuterK(1/(floats.Sum(weights)-1), &xt)
	return cov
}

// CorrelationMatrix calculates a correlation matrix from a matrix of data
// using a two-pass algorithm.
//
// The weights must have length equal to the number of rows in
// input data matrix x. If corr is nil, then a new matrix with appropriate size will
// be constructed. If corr is not nil, it should have the same number of columns
// as the input data matrix x, and it will be used as the destination for the
// correlation data. Weights must not be negative.
func CorrelationMatrix(corr *mat64.SymDense, x mat64.Matrix, weights []float64) *mat64.SymDense {
	// This will panic if the sizes don't match, or if weights is the wrong size.
	corr = CovarianceMatrix(corr, x, weights)
	covToCorr(corr)
	return corr
}

// covToCorr converts a covariance matrix to a correlation matrix.
func covToCorr(c *mat64.SymDense) {
	r := c.Symmetric()

	s := make([]float64, r)
	for i := 0; i < r; i++ {
		s[i] = 1 / math.Sqrt(c.At(i, i))
	}
	for i, sx := range s {
		// Ensure that the diagonal has exactly ones.
		c.SetSym(i, i, 1)
		for j := i + 1; j < r; j++ {
			v := c.At(i, j)
			c.SetSym(i, j, v*sx*s[j])
		}
	}
}

// corrToCov converts a correlation matrix to a covariance matrix.
// The input sigma should be vector of standard deviations corresponding
// to the covariance.  It will panic if len(sigma) is not equal to the
// number of rows in the correlation matrix.
func corrToCov(c *mat64.SymDense, sigma []float64) {
	r, _ := c.Dims()

	if r != len(sigma) {
		panic(mat64.ErrShape)
	}
	for i, sx := range sigma {
		// Ensure that the diagonal has exactly sigma squared.
		c.SetSym(i, i, sx*sx)
		for j := i + 1; j < r; j++ {
			v := c.At(i, j)
			c.SetSym(i, j, v*sx*sigma[j])
		}
	}
}
<commit_msg>stat: update matrix error imports<commit_after>// Copyright ©2014 The gonum 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 stat

import (
	"math"

	"github.com/gonum/floats"
	"github.com/gonum/matrix"
	"github.com/gonum/matrix/mat64"
)

// CovarianceMatrix calculates a covariance matrix (also known as a
// variance-covariance matrix) from a matrix of data, using a two-pass
// algorithm.
//
// The weights must have length equal to the number of rows in
// input data matrix x. If cov is nil, then a new matrix with appropriate size will
// be constructed. If cov is not nil, it should have the same number of columns as the
// input data matrix x, and it will be used as the destination for the covariance
// data. Weights must not be negative.
func CovarianceMatrix(cov *mat64.SymDense, x mat64.Matrix, weights []float64) *mat64.SymDense {
	// This is the matrix version of the two-pass algorithm. It doesn't use the
	// additional floating point error correction that the Covariance function uses
	// to reduce the impact of rounding during centering.

	r, c := x.Dims()

	if cov == nil {
		cov = mat64.NewSymDense(c, nil)
	} else if n := cov.Symmetric(); n != c {
		panic(matrix.ErrShape)
	}

	var xt mat64.Dense
	xt.Clone(x.T())
	// Subtract the mean of each of the columns.
	for i := 0; i < c; i++ {
		v := xt.RawRowView(i)
		// This will panic with ErrShape if len(weights) != len(v), so
		// we don't have to check the size later.
		mean := Mean(v, weights)
		floats.AddConst(-mean, v)
	}

	if weights == nil {
		// Calculate the normalization factor
		// scaled by the sample size.
		cov.SymOuterK(1/(float64(r)-1), &xt)
		return cov
	}

	// Multiply by the sqrt of the weights, so that multiplication is symmetric.
	sqrtwts := make([]float64, r)
	for i, w := range weights {
		if w < 0 {
			panic("stat: negative covariance matrix weights")
		}
		sqrtwts[i] = math.Sqrt(w)
	}
	// Weight the rows.
	for i := 0; i < c; i++ {
		v := xt.RawRowView(i)
		floats.Mul(v, sqrtwts)
	}

	// Calculate the normalization factor
	// scaled by the weighted sample size.
	cov.SymOuterK(1/(floats.Sum(weights)-1), &xt)
	return cov
}

// CorrelationMatrix calculates a correlation matrix from a matrix of data
// using a two-pass algorithm.
//
// The weights must have length equal to the number of rows in
// input data matrix x. If corr is nil, then a new matrix with appropriate size will
// be constructed. If corr is not nil, it should have the same number of columns
// as the input data matrix x, and it will be used as the destination for the
// correlation data. Weights must not be negative.
func CorrelationMatrix(corr *mat64.SymDense, x mat64.Matrix, weights []float64) *mat64.SymDense {
	// This will panic if the sizes don't match, or if weights is the wrong size.
	corr = CovarianceMatrix(corr, x, weights)
	covToCorr(corr)
	return corr
}

// covToCorr converts a covariance matrix to a correlation matrix.
func covToCorr(c *mat64.SymDense) {
	r := c.Symmetric()

	s := make([]float64, r)
	for i := 0; i < r; i++ {
		s[i] = 1 / math.Sqrt(c.At(i, i))
	}
	for i, sx := range s {
		// Ensure that the diagonal has exactly ones.
		c.SetSym(i, i, 1)
		for j := i + 1; j < r; j++ {
			v := c.At(i, j)
			c.SetSym(i, j, v*sx*s[j])
		}
	}
}

// corrToCov converts a correlation matrix to a covariance matrix.
// The input sigma should be vector of standard deviations corresponding
// to the covariance.  It will panic if len(sigma) is not equal to the
// number of rows in the correlation matrix.
func corrToCov(c *mat64.SymDense, sigma []float64) {
	r, _ := c.Dims()

	if r != len(sigma) {
		panic(matrix.ErrShape)
	}
	for i, sx := range sigma {
		// Ensure that the diagonal has exactly sigma squared.
		c.SetSym(i, i, sx*sx)
		for j := i + 1; j < r; j++ {
			v := c.At(i, j)
			c.SetSym(i, j, v*sx*sigma[j])
		}
	}
}
<|endoftext|>


<commit_before>// Code generated by MockGen. DO NOT EDIT.
// Source: request.go

// Package restpc is a generated GoMock package.
package restpc

import (
	gomock "github.com/golang/mock/gomock"
	url "net/url"
	reflect "reflect"
	time "time"
)

// MockRequest is a mock of Request interface
type MockRequest struct {
	ctrl     *gomock.Controller
	recorder *MockRequestMockRecorder
}

// MockRequestMockRecorder is the mock recorder for MockRequest
type MockRequestMockRecorder struct {
	mock *MockRequest
}

// NewMockRequest creates a new mock instance
func NewMockRequest(ctrl *gomock.Controller) *MockRequest {
	mock := &MockRequest{ctrl: ctrl}
	mock.recorder = &MockRequestMockRecorder{mock}
	return mock
}

// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockRequest) EXPECT() *MockRequestMockRecorder {
	return m.recorder
}

// RemoteIP mocks base method
func (m *MockRequest) RemoteIP() (string, error) {
	ret := m.ctrl.Call(m, "RemoteIP")
	ret0, _ := ret[0].(string)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// RemoteIP indicates an expected call of RemoteIP
func (mr *MockRequestMockRecorder) RemoteIP() *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoteIP", reflect.TypeOf((*MockRequest)(nil).RemoteIP))
}

// URL mocks base method
func (m *MockRequest) URL() *url.URL {
	ret := m.ctrl.Call(m, "URL")
	ret0, _ := ret[0].(*url.URL)
	return ret0
}

// URL indicates an expected call of URL
func (mr *MockRequestMockRecorder) URL() *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "URL", reflect.TypeOf((*MockRequest)(nil).URL))
}

// Host mocks base method
func (m *MockRequest) Host() string {
	ret := m.ctrl.Call(m, "Host")
	ret0, _ := ret[0].(string)
	return ret0
}

// Host indicates an expected call of Host
func (mr *MockRequestMockRecorder) Host() *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Host", reflect.TypeOf((*MockRequest)(nil).Host))
}

// Body mocks base method
func (m *MockRequest) Body() ([]byte, error) {
	ret := m.ctrl.Call(m, "Body")
	ret0, _ := ret[0].([]byte)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// Body indicates an expected call of Body
func (mr *MockRequestMockRecorder) Body() *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Body", reflect.TypeOf((*MockRequest)(nil).Body))
}

// BodyMap mocks base method
func (m *MockRequest) BodyMap() (map[string]interface{}, error) {
	ret := m.ctrl.Call(m, "BodyMap")
	ret0, _ := ret[0].(map[string]interface{})
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// BodyMap indicates an expected call of BodyMap
func (mr *MockRequestMockRecorder) BodyMap() *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BodyMap", reflect.TypeOf((*MockRequest)(nil).BodyMap))
}

// BodyTo mocks base method
func (m *MockRequest) BodyTo(model interface{}) error {
	ret := m.ctrl.Call(m, "BodyTo", model)
	ret0, _ := ret[0].(error)
	return ret0
}

// BodyTo indicates an expected call of BodyTo
func (mr *MockRequestMockRecorder) BodyTo(model interface{}) *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BodyTo", reflect.TypeOf((*MockRequest)(nil).BodyTo), model)
}

// GetHeader mocks base method
func (m *MockRequest) GetHeader(arg0 string) string {
	ret := m.ctrl.Call(m, "GetHeader", arg0)
	ret0, _ := ret[0].(string)
	return ret0
}

// GetHeader indicates an expected call of GetHeader
func (mr *MockRequestMockRecorder) GetHeader(arg0 interface{}) *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHeader", reflect.TypeOf((*MockRequest)(nil).GetHeader), arg0)
}

// GetString mocks base method
func (m *MockRequest) GetString(key string, flags ...ParamFlag) (*string, error) {
	varargs := []interface{}{key}
	for _, a := range flags {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "GetString", varargs...)
	ret0, _ := ret[0].(*string)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetString indicates an expected call of GetString
func (mr *MockRequestMockRecorder) GetString(key interface{}, flags ...interface{}) *gomock.Call {
	varargs := append([]interface{}{key}, flags...)
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetString", reflect.TypeOf((*MockRequest)(nil).GetString), varargs...)
}

// GetStringList mocks base method
func (m *MockRequest) GetStringList(key string, flags ...ParamFlag) ([]string, error) {
	varargs := []interface{}{key}
	for _, a := range flags {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "GetStringList", varargs...)
	ret0, _ := ret[0].([]string)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetStringList indicates an expected call of GetStringList
func (mr *MockRequestMockRecorder) GetStringList(key interface{}, flags ...interface{}) *gomock.Call {
	varargs := append([]interface{}{key}, flags...)
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStringList", reflect.TypeOf((*MockRequest)(nil).GetStringList), varargs...)
}

// GetInt mocks base method
func (m *MockRequest) GetInt(key string, flags ...ParamFlag) (*int, error) {
	varargs := []interface{}{key}
	for _, a := range flags {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "GetInt", varargs...)
	ret0, _ := ret[0].(*int)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetInt indicates an expected call of GetInt
func (mr *MockRequestMockRecorder) GetInt(key interface{}, flags ...interface{}) *gomock.Call {
	varargs := append([]interface{}{key}, flags...)
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInt", reflect.TypeOf((*MockRequest)(nil).GetInt), varargs...)
}

// GetFloat mocks base method
func (m *MockRequest) GetFloat(key string, flags ...ParamFlag) (*float64, error) {
	varargs := []interface{}{key}
	for _, a := range flags {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "GetFloat", varargs...)
	ret0, _ := ret[0].(*float64)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetFloat indicates an expected call of GetFloat
func (mr *MockRequestMockRecorder) GetFloat(key interface{}, flags ...interface{}) *gomock.Call {
	varargs := append([]interface{}{key}, flags...)
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFloat", reflect.TypeOf((*MockRequest)(nil).GetFloat), varargs...)
}

// GetBool mocks base method
func (m *MockRequest) GetBool(key string, flags ...ParamFlag) (*bool, error) {
	varargs := []interface{}{key}
	for _, a := range flags {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "GetBool", varargs...)
	ret0, _ := ret[0].(*bool)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetBool indicates an expected call of GetBool
func (mr *MockRequestMockRecorder) GetBool(key interface{}, flags ...interface{}) *gomock.Call {
	varargs := append([]interface{}{key}, flags...)
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBool", reflect.TypeOf((*MockRequest)(nil).GetBool), varargs...)
}

// GetTime mocks base method
func (m *MockRequest) GetTime(key string, flags ...ParamFlag) (*time.Time, error) {
	varargs := []interface{}{key}
	for _, a := range flags {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "GetTime", varargs...)
	ret0, _ := ret[0].(*time.Time)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetTime indicates an expected call of GetTime
func (mr *MockRequestMockRecorder) GetTime(key interface{}, flags ...interface{}) *gomock.Call {
	varargs := append([]interface{}{key}, flags...)
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTime", reflect.TypeOf((*MockRequest)(nil).GetTime), varargs...)
}
<commit_msg>update mock_request.go<commit_after>// Code generated by MockGen. DO NOT EDIT.
// Source: request.go

// Package restpc is a generated GoMock package.
package restpc

import (
	gomock "github.com/golang/mock/gomock"
	url "net/url"
	reflect "reflect"
	time "time"
)

// MockRequest is a mock of Request interface
type MockRequest struct {
	ctrl     *gomock.Controller
	recorder *MockRequestMockRecorder
}

// MockRequestMockRecorder is the mock recorder for MockRequest
type MockRequestMockRecorder struct {
	mock *MockRequest
}

// NewMockRequest creates a new mock instance
func NewMockRequest(ctrl *gomock.Controller) *MockRequest {
	mock := &MockRequest{ctrl: ctrl}
	mock.recorder = &MockRequestMockRecorder{mock}
	return mock
}

// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockRequest) EXPECT() *MockRequestMockRecorder {
	return m.recorder
}

// RemoteIP mocks base method
func (m *MockRequest) RemoteIP() (string, error) {
	ret := m.ctrl.Call(m, "RemoteIP")
	ret0, _ := ret[0].(string)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// RemoteIP indicates an expected call of RemoteIP
func (mr *MockRequestMockRecorder) RemoteIP() *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoteIP", reflect.TypeOf((*MockRequest)(nil).RemoteIP))
}

// URL mocks base method
func (m *MockRequest) URL() *url.URL {
	ret := m.ctrl.Call(m, "URL")
	ret0, _ := ret[0].(*url.URL)
	return ret0
}

// URL indicates an expected call of URL
func (mr *MockRequestMockRecorder) URL() *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "URL", reflect.TypeOf((*MockRequest)(nil).URL))
}

// Host mocks base method
func (m *MockRequest) Host() string {
	ret := m.ctrl.Call(m, "Host")
	ret0, _ := ret[0].(string)
	return ret0
}

// Host indicates an expected call of Host
func (mr *MockRequestMockRecorder) Host() *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Host", reflect.TypeOf((*MockRequest)(nil).Host))
}

// Body mocks base method
func (m *MockRequest) Body() ([]byte, error) {
	ret := m.ctrl.Call(m, "Body")
	ret0, _ := ret[0].([]byte)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// Body indicates an expected call of Body
func (mr *MockRequestMockRecorder) Body() *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Body", reflect.TypeOf((*MockRequest)(nil).Body))
}

// BodyMap mocks base method
func (m *MockRequest) BodyMap() (map[string]interface{}, error) {
	ret := m.ctrl.Call(m, "BodyMap")
	ret0, _ := ret[0].(map[string]interface{})
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// BodyMap indicates an expected call of BodyMap
func (mr *MockRequestMockRecorder) BodyMap() *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BodyMap", reflect.TypeOf((*MockRequest)(nil).BodyMap))
}

// BodyTo mocks base method
func (m *MockRequest) BodyTo(model interface{}) error {
	ret := m.ctrl.Call(m, "BodyTo", model)
	ret0, _ := ret[0].(error)
	return ret0
}

// BodyTo indicates an expected call of BodyTo
func (mr *MockRequestMockRecorder) BodyTo(model interface{}) *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BodyTo", reflect.TypeOf((*MockRequest)(nil).BodyTo), model)
}

// GetHeader mocks base method
func (m *MockRequest) GetHeader(arg0 string) string {
	ret := m.ctrl.Call(m, "GetHeader", arg0)
	ret0, _ := ret[0].(string)
	return ret0
}

// GetHeader indicates an expected call of GetHeader
func (mr *MockRequestMockRecorder) GetHeader(arg0 interface{}) *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHeader", reflect.TypeOf((*MockRequest)(nil).GetHeader), arg0)
}

// GetString mocks base method
func (m *MockRequest) GetString(key string, flags ...ParamFlag) (*string, error) {
	varargs := []interface{}{key}
	for _, a := range flags {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "GetString", varargs...)
	ret0, _ := ret[0].(*string)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetString indicates an expected call of GetString
func (mr *MockRequestMockRecorder) GetString(key interface{}, flags ...interface{}) *gomock.Call {
	varargs := append([]interface{}{key}, flags...)
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetString", reflect.TypeOf((*MockRequest)(nil).GetString), varargs...)
}

// GetStringList mocks base method
func (m *MockRequest) GetStringList(key string, flags ...ParamFlag) ([]string, error) {
	varargs := []interface{}{key}
	for _, a := range flags {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "GetStringList", varargs...)
	ret0, _ := ret[0].([]string)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetStringList indicates an expected call of GetStringList
func (mr *MockRequestMockRecorder) GetStringList(key interface{}, flags ...interface{}) *gomock.Call {
	varargs := append([]interface{}{key}, flags...)
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStringList", reflect.TypeOf((*MockRequest)(nil).GetStringList), varargs...)
}

// GetInt mocks base method
func (m *MockRequest) GetInt(key string, flags ...ParamFlag) (*int, error) {
	varargs := []interface{}{key}
	for _, a := range flags {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "GetInt", varargs...)
	ret0, _ := ret[0].(*int)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetInt indicates an expected call of GetInt
func (mr *MockRequestMockRecorder) GetInt(key interface{}, flags ...interface{}) *gomock.Call {
	varargs := append([]interface{}{key}, flags...)
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInt", reflect.TypeOf((*MockRequest)(nil).GetInt), varargs...)
}

// GetFloat mocks base method
func (m *MockRequest) GetFloat(key string, flags ...ParamFlag) (*float64, error) {
	varargs := []interface{}{key}
	for _, a := range flags {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "GetFloat", varargs...)
	ret0, _ := ret[0].(*float64)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetFloat indicates an expected call of GetFloat
func (mr *MockRequestMockRecorder) GetFloat(key interface{}, flags ...interface{}) *gomock.Call {
	varargs := append([]interface{}{key}, flags...)
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFloat", reflect.TypeOf((*MockRequest)(nil).GetFloat), varargs...)
}

// GetBool mocks base method
func (m *MockRequest) GetBool(key string, flags ...ParamFlag) (*bool, error) {
	varargs := []interface{}{key}
	for _, a := range flags {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "GetBool", varargs...)
	ret0, _ := ret[0].(*bool)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetBool indicates an expected call of GetBool
func (mr *MockRequestMockRecorder) GetBool(key interface{}, flags ...interface{}) *gomock.Call {
	varargs := append([]interface{}{key}, flags...)
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBool", reflect.TypeOf((*MockRequest)(nil).GetBool), varargs...)
}

// GetTime mocks base method
func (m *MockRequest) GetTime(key string, flags ...ParamFlag) (*time.Time, error) {
	varargs := []interface{}{key}
	for _, a := range flags {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "GetTime", varargs...)
	ret0, _ := ret[0].(*time.Time)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetTime indicates an expected call of GetTime
func (mr *MockRequestMockRecorder) GetTime(key interface{}, flags ...interface{}) *gomock.Call {
	varargs := append([]interface{}{key}, flags...)
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTime", reflect.TypeOf((*MockRequest)(nil).GetTime), varargs...)
}

// FullMap mocks base method
func (m *MockRequest) FullMap() map[string]interface{} {
	ret := m.ctrl.Call(m, "FullMap")
	ret0, _ := ret[0].(map[string]interface{})
	return ret0
}

// FullMap indicates an expected call of FullMap
func (mr *MockRequestMockRecorder) FullMap() *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FullMap", reflect.TypeOf((*MockRequest)(nil).FullMap))
}
<|endoftext|>


<commit_before>package collectors

import (
	"bufio"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/StackExchange/slog"
	"github.com/bosun-monitor/scollector/opentsdb"
	"github.com/bosun-monitor/scollector/util"
)

type ProgramCollector struct {
	Path     string
	Interval time.Duration
}

func InitPrograms(cpath string) {
	cdir, err := os.Open(cpath)
	if err != nil {
		slog.Infoln(err)
		return
	}
	idirs, err := cdir.Readdir(0)
	if err != nil {
		slog.Infoln(err)
		return
	}
	for _, idir := range idirs {
		i, err := strconv.Atoi(idir.Name())
		if err != nil || i < 0 {
			slog.Infoln("invalid collector folder name:", idir.Name())
			continue
		}
		interval := time.Second * time.Duration(i)
		dir, err := os.Open(filepath.Join(cdir.Name(), idir.Name()))
		if err != nil {
			slog.Infoln(err)
			continue
		}
		files, err := dir.Readdir(0)
		if err != nil {
			slog.Infoln(err)
			continue
		}
		for _, file := range files {
			if !isExecutable(file) {
				continue
			}
			collectors = append(collectors, &ProgramCollector{
				Path:     filepath.Join(dir.Name(), file.Name()),
				Interval: interval,
			})
		}
	}
}

func isExecutable(f os.FileInfo) bool {
	switch runtime.GOOS {
	case "windows":
		exts := strings.Split(os.Getenv("PATHEXT"), ";")
		fileExt := filepath.Ext(strings.ToUpper(f.Name()))
		for _, ext := range exts {
			if filepath.Ext(strings.ToUpper(ext)) == fileExt {
				return true
			}
		}
		return false
	default:
		return f.Mode()&0111 != 0
	}
}

func (c *ProgramCollector) Run(dpchan chan<- *opentsdb.DataPoint) {
	if c.Interval == 0 {
		for {
			next := time.After(DefaultFreq)
			if err := c.runProgram(dpchan); err != nil {
				slog.Infoln(err)
			}
			<-next
			slog.Infoln("restarting", c.Path)
		}
	} else {
		for {
			next := time.After(c.Interval)
			c.runProgram(dpchan)
			<-next
		}
	}
}

func (c *ProgramCollector) Init() {
}

func (c *ProgramCollector) runProgram(dpchan chan<- *opentsdb.DataPoint) (progError error) {
	cmd := exec.Command(c.Path)
	pr, pw := io.Pipe()
	s := bufio.NewScanner(pr)
	cmd.Stdout = pw
	er, ew := io.Pipe()
	cmd.Stderr = ew
	if err := cmd.Start(); err != nil {
		return err
	}
	go func() {
		progError = cmd.Wait()
		pw.Close()
		ew.Close()
	}()
	go func() {
		es := bufio.NewScanner(er)
		for es.Scan() {
			line := strings.TrimSpace(es.Text())
			slog.Error(line)
		}
	}()
Loop:
	for s.Scan() {
		line := strings.TrimSpace(s.Text())
		sp := strings.Fields(line)
		if len(sp) < 3 {
			slog.Errorf("bad line in program %s: %s", c.Path, line)
			continue
		}
		ts, err := strconv.ParseInt(sp[1], 10, 64)
		if err != nil {
			slog.Errorf("bad timestamp in program %s: %s", c.Path, sp[1])
			continue
		}
		val, err := strconv.ParseInt(sp[2], 10, 64)
		if err != nil {
			slog.Errorf("bad value in program %s: %s", c.Path, sp[2])
			continue
		}
		dp := opentsdb.DataPoint{
			Metric:    sp[0],
			Timestamp: ts,
			Value:     val,
			Tags:      opentsdb.TagSet{"host": util.Hostname},
		}
		for _, tag := range sp[3:] {
			tags, err := opentsdb.ParseTags(tag)
			if v, ok := tags["host"]; ok && v == "" {
				delete(dp.Tags, "host")
			} else if err != nil {
				slog.Errorf("bad tag in program %s, metric %s: %v", c.Path, sp[0], tag)
				continue Loop
			} else {
				dp.Tags.Merge(tags)
			}
		}
		dpchan <- &dp
	}
	if err := s.Err(); err != nil {
		return err
	}
	return
}

func (c *ProgramCollector) Name() string {
	return c.Path
}
<commit_msg>cmd/scollector: Values are floats, not inst<commit_after>package collectors

import (
	"bufio"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/StackExchange/slog"
	"github.com/bosun-monitor/scollector/opentsdb"
	"github.com/bosun-monitor/scollector/util"
)

type ProgramCollector struct {
	Path     string
	Interval time.Duration
}

func InitPrograms(cpath string) {
	cdir, err := os.Open(cpath)
	if err != nil {
		slog.Infoln(err)
		return
	}
	idirs, err := cdir.Readdir(0)
	if err != nil {
		slog.Infoln(err)
		return
	}
	for _, idir := range idirs {
		i, err := strconv.Atoi(idir.Name())
		if err != nil || i < 0 {
			slog.Infoln("invalid collector folder name:", idir.Name())
			continue
		}
		interval := time.Second * time.Duration(i)
		dir, err := os.Open(filepath.Join(cdir.Name(), idir.Name()))
		if err != nil {
			slog.Infoln(err)
			continue
		}
		files, err := dir.Readdir(0)
		if err != nil {
			slog.Infoln(err)
			continue
		}
		for _, file := range files {
			if !isExecutable(file) {
				continue
			}
			collectors = append(collectors, &ProgramCollector{
				Path:     filepath.Join(dir.Name(), file.Name()),
				Interval: interval,
			})
		}
	}
}

func isExecutable(f os.FileInfo) bool {
	switch runtime.GOOS {
	case "windows":
		exts := strings.Split(os.Getenv("PATHEXT"), ";")
		fileExt := filepath.Ext(strings.ToUpper(f.Name()))
		for _, ext := range exts {
			if filepath.Ext(strings.ToUpper(ext)) == fileExt {
				return true
			}
		}
		return false
	default:
		return f.Mode()&0111 != 0
	}
}

func (c *ProgramCollector) Run(dpchan chan<- *opentsdb.DataPoint) {
	if c.Interval == 0 {
		for {
			next := time.After(DefaultFreq)
			if err := c.runProgram(dpchan); err != nil {
				slog.Infoln(err)
			}
			<-next
			slog.Infoln("restarting", c.Path)
		}
	} else {
		for {
			next := time.After(c.Interval)
			c.runProgram(dpchan)
			<-next
		}
	}
}

func (c *ProgramCollector) Init() {
}

func (c *ProgramCollector) runProgram(dpchan chan<- *opentsdb.DataPoint) (progError error) {
	cmd := exec.Command(c.Path)
	pr, pw := io.Pipe()
	s := bufio.NewScanner(pr)
	cmd.Stdout = pw
	er, ew := io.Pipe()
	cmd.Stderr = ew
	if err := cmd.Start(); err != nil {
		return err
	}
	go func() {
		progError = cmd.Wait()
		pw.Close()
		ew.Close()
	}()
	go func() {
		es := bufio.NewScanner(er)
		for es.Scan() {
			line := strings.TrimSpace(es.Text())
			slog.Error(line)
		}
	}()
Loop:
	for s.Scan() {
		line := strings.TrimSpace(s.Text())
		sp := strings.Fields(line)
		if len(sp) < 3 {
			slog.Errorf("bad line in program %s: %s", c.Path, line)
			continue
		}
		ts, err := strconv.ParseInt(sp[1], 10, 64)
		if err != nil {
			slog.Errorf("bad timestamp in program %s: %s", c.Path, sp[1])
			continue
		}
		val, err := strconv.ParseFloat(sp[2], 64)
		if err != nil {
			slog.Errorf("bad value in program %s: %s", c.Path, sp[2])
			continue
		}
		dp := opentsdb.DataPoint{
			Metric:    sp[0],
			Timestamp: ts,
			Value:     val,
			Tags:      opentsdb.TagSet{"host": util.Hostname},
		}
		for _, tag := range sp[3:] {
			tags, err := opentsdb.ParseTags(tag)
			if v, ok := tags["host"]; ok && v == "" {
				delete(dp.Tags, "host")
			} else if err != nil {
				slog.Errorf("bad tag in program %s, metric %s: %v", c.Path, sp[0], tag)
				continue Loop
			} else {
				dp.Tags.Merge(tags)
			}
		}
		dpchan <- &dp
	}
	if err := s.Err(); err != nil {
		return err
	}
	return
}

func (c *ProgramCollector) Name() string {
	return c.Path
}
<|endoftext|>


<commit_before>/*-
 * Copyright (c) 2016, 1&1 Internet SE
 * Copyright (c) 2016, Jörg Pernfuß
 *
 * Use of this source code is governed by a 2-clause BSD license
 * that can be found in the LICENSE file.
 */
package main

import (
	"database/sql"
	"fmt"

	"github.com/1and1/soma/internal/stmt"
)

func (tk *treeKeeper) startTx() (
	*sql.Tx, map[string]*sql.Stmt, error) {

	var err error
	var tx *sql.Tx
	open := false
	stMap := map[string]*sql.Stmt{}

	if tx, err = tk.conn.Begin(); err != nil {
		goto bailout
	}
	open = true

	//
	// PROPERTY STATEMENTS
	for name, statement := range map[string]string{
		`PropertyInstanceCreate`:          stmt.TxPropertyInstanceCreate,
		`PropertyInstanceDelete`:          stmt.TxPropertyInstanceDelete,
		`RepositoryPropertyOncallCreate`:  stmt.TxRepositoryPropertyOncallCreate,
		`RepositoryPropertyOncallDelete`:  stmt.TxRepositoryPropertyOncallDelete,
		`RepositoryPropertyServiceCreate`: stmt.TxRepositoryPropertyServiceCreate,
		`RepositoryPropertyServiceDelete`: stmt.TxRepositoryPropertyServiceDelete,
		`RepositoryPropertySystemCreate`:  stmt.TxRepositoryPropertySystemCreate,
		`RepositoryPropertySystemDelete`:  stmt.TxRepositoryPropertySystemDelete,
		`RepositoryPropertyCustomCreate`:  stmt.TxRepositoryPropertyCustomCreate,
		`RepositoryPropertyCustomDelete`:  stmt.TxRepositoryPropertyCustomDelete,
		`BucketPropertyOncallCreate`:      stmt.TxBucketPropertyOncallCreate,
		`BucketPropertyOncallDelete`:      stmt.TxBucketPropertyOncallDelete,
		`BucketPropertyServiceCreate`:     stmt.TxBucketPropertyServiceCreate,
		`BucketPropertyServiceDelete`:     stmt.TxBucketPropertyServiceDelete,
		`BucketPropertySystemCreate`:      stmt.TxBucketPropertySystemCreate,
		`BucketPropertySystemDelete`:      stmt.TxBucketPropertySystemDelete,
		`BucketPropertyCustomCreate`:      stmt.TxBucketPropertyCustomCreate,
		`BucketPropertyCustomDelete`:      stmt.TxBucketPropertyCustomDelete,
		`GroupPropertyOncallCreate`:       stmt.TxGroupPropertyOncallCreate,
		`GroupPropertyOncallDelete`:       stmt.TxGroupPropertyOncallDelete,
		`GroupPropertyServiceCreate`:      stmt.TxGroupPropertyServiceCreate,
		`GroupPropertyServiceDelete`:      stmt.TxGroupPropertyServiceDelete,
		`GroupPropertySystemCreate`:       stmt.TxGroupPropertySystemCreate,
		`GroupPropertySystemDelete`:       stmt.TxGroupPropertySystemDelete,
		`GroupPropertyCustomCreate`:       stmt.TxGroupPropertyCustomCreate,
		`GroupPropertyCustomDelete`:       stmt.TxGroupPropertyCustomDelete,
		`ClusterPropertyOncallCreate`:     stmt.TxClusterPropertyOncallCreate,
		`ClusterPropertyOncallDelete`:     stmt.TxClusterPropertyOncallDelete,
		`ClusterPropertyServiceCreate`:    stmt.TxClusterPropertyServiceCreate,
		`ClusterPropertyServiceDelete`:    stmt.TxClusterPropertyServiceDelete,
		`ClusterPropertySystemCreate`:     stmt.TxClusterPropertySystemCreate,
		`ClusterPropertySystemDelete`:     stmt.TxClusterPropertySystemDelete,
		`ClusterPropertyCustomCreate`:     stmt.TxClusterPropertyCustomCreate,
		`ClusterPropertyCustomDelete`:     stmt.TxClusterPropertyCustomDelete,
		`NodePropertyOncallCreate`:        stmt.TxNodePropertyOncallCreate,
		`NodePropertyOncallDelete`:        stmt.TxNodePropertyOncallDelete,
		`NodePropertyServiceCreate`:       stmt.TxNodePropertyServiceCreate,
		`NodePropertyServiceDelete`:       stmt.TxNodePropertyServiceDelete,
		`NodePropertySystemCreate`:        stmt.TxNodePropertySystemCreate,
		`NodePropertySystemDelete`:        stmt.TxNodePropertySystemDelete,
		`NodePropertyCustomCreate`:        stmt.TxNodePropertyCustomCreate,
		`NodePropertyCustomDelete`:        stmt.TxNodePropertyCustomDelete,
	} {
		if stMap[name], err = tx.Prepare(statement); err != nil {
			err = fmt.Errorf("tk.Prepare(%s) error: %s",
				name, err.Error())
			delete(stMap, name)
			goto bailout
		}
	}

	//
	// CHECK STATEMENTS
	for name, statement := range map[string]string{
		`CreateCheck`: stmt.TxCreateCheck,
		`DeleteCheck`: stmt.TxMarkCheckDeleted,
	} {
		if stMap[name], err = tx.Prepare(statement); err != nil {
			err = fmt.Errorf("tk.Prepare(%s) error: %s",
				name, err.Error())
			delete(stMap, name)
			goto bailout
		}
	}

	//
	// CHECK INSTANCE STATEMENTS
	for name, statement := range map[string]string{
		`CreateCheckInstance`:              stmt.TxCreateCheckInstance,
		`CreateCheckInstanceConfiguration`: stmt.TxCreateCheckInstanceConfiguration,
		`DeleteCheckInstance`:              stmt.TxMarkCheckInstanceDeleted,
	} {
		if stMap[name], err = tx.Prepare(statement); err != nil {
			err = fmt.Errorf("tk.Prepare(%s) error: %s",
				name, err.Error())
			delete(stMap, name)
			goto bailout
		}
	}

	//
	// CHECK CONFIGURATION STATEMENTS
	for name, statement := range map[string]string{
		`CreateCheckConfigurationBase`:                stmt.TxCreateCheckConfigurationBase,
		`CreateCheckConfigurationThreshold`:           stmt.TxCreateCheckConfigurationThreshold,
		`CreateCheckConfigurationConstraintSystem`:    stmt.TxCreateCheckConfigurationConstraintSystem,
		`CreateCheckConfigurationConstraintNative`:    stmt.TxCreateCheckConfigurationConstraintNative,
		`CreateCheckConfigurationConstraintOncall`:    stmt.TxCreateCheckConfigurationConstraintOncall,
		`CreateCheckConfigurationConstraintCustom`:    stmt.TxCreateCheckConfigurationConstraintCustom,
		`CreateCheckConfigurationConstraintService`:   stmt.TxCreateCheckConfigurationConstraintService,
		`CreateCheckConfigurationConstraintAttribute`: stmt.TxCreateCheckConfigurationConstraintAttribute,
	} {
		if stMap[name], err = tx.Prepare(statement); err != nil {
			err = fmt.Errorf("tk.Prepare(%s) error: %s",
				name, err.Error())
			delete(stMap, name)
			goto bailout
		}
	}

	//
	// TREE MANIPULATION STATEMENTS
	for name, statement := range map[string]string{
		`BucketAssignNode`:         stmt.TxBucketAssignNode,
		`ClusterCreate`:            stmt.TxClusterCreate,
		`ClusterDelete`:            stmt.TxClusterDelete,
		`ClusterMemberNew`:         stmt.TxClusterMemberNew,
		`ClusterMemberRemove`:      stmt.TxClusterMemberRemove,
		`ClusterUpdate`:            stmt.TxClusterUpdate,
		`CreateBucket`:             stmt.TxCreateBucket,
		`GroupCreate`:              stmt.TxGroupCreate,
		`GroupDelete`:              stmt.TxGroupDelete,
		`GroupMemberNewCluster`:    stmt.TxGroupMemberNewCluster,
		`GroupMemberNewGroup`:      stmt.TxGroupMemberNewGroup,
		`GroupMemberNewNode`:       stmt.TxGroupMemberNewNode,
		`GroupMemberRemoveCluster`: stmt.TxGroupMemberRemoveCluster,
		`GroupMemberRemoveGroup`:   stmt.TxGroupMemberRemoveGroup,
		`GroupMemberRemoveNode`:    stmt.TxGroupMemberRemoveNode,
		`GroupUpdate`:              stmt.TxGroupUpdate,
		`NodeUnassignFromBucket`:   stmt.TxNodeUnassignFromBucket,
		`UpdateNodeState`:          stmt.TxUpdateNodeState,
	} {
		if stMap[name], err = tx.Prepare(statement); err != nil {
			err = fmt.Errorf("tk.Prepare(%s) error: %s",
				name, err.Error())
			delete(stMap, name)
			goto bailout
		}
	}

	return tx, stMap, nil

bailout:
	if open {
		defer tx.Rollback()
	}
	for _, statement := range stMap {
		defer statement.Close()
	}
	return nil, nil, err
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Fix double .Close() of TX context SQL statements<commit_after>/*-
 * Copyright (c) 2016, 1&1 Internet SE
 * Copyright (c) 2016, Jörg Pernfuß
 *
 * Use of this source code is governed by a 2-clause BSD license
 * that can be found in the LICENSE file.
 */
package main

import (
	"database/sql"
	"fmt"

	"github.com/1and1/soma/internal/stmt"
)

func (tk *treeKeeper) startTx() (
	*sql.Tx, map[string]*sql.Stmt, error) {

	var err error
	var tx *sql.Tx
	open := false
	stMap := map[string]*sql.Stmt{}

	if tx, err = tk.conn.Begin(); err != nil {
		goto bailout
	}
	open = true

	//
	// PROPERTY STATEMENTS
	for name, statement := range map[string]string{
		`PropertyInstanceCreate`:          stmt.TxPropertyInstanceCreate,
		`PropertyInstanceDelete`:          stmt.TxPropertyInstanceDelete,
		`RepositoryPropertyOncallCreate`:  stmt.TxRepositoryPropertyOncallCreate,
		`RepositoryPropertyOncallDelete`:  stmt.TxRepositoryPropertyOncallDelete,
		`RepositoryPropertyServiceCreate`: stmt.TxRepositoryPropertyServiceCreate,
		`RepositoryPropertyServiceDelete`: stmt.TxRepositoryPropertyServiceDelete,
		`RepositoryPropertySystemCreate`:  stmt.TxRepositoryPropertySystemCreate,
		`RepositoryPropertySystemDelete`:  stmt.TxRepositoryPropertySystemDelete,
		`RepositoryPropertyCustomCreate`:  stmt.TxRepositoryPropertyCustomCreate,
		`RepositoryPropertyCustomDelete`:  stmt.TxRepositoryPropertyCustomDelete,
		`BucketPropertyOncallCreate`:      stmt.TxBucketPropertyOncallCreate,
		`BucketPropertyOncallDelete`:      stmt.TxBucketPropertyOncallDelete,
		`BucketPropertyServiceCreate`:     stmt.TxBucketPropertyServiceCreate,
		`BucketPropertyServiceDelete`:     stmt.TxBucketPropertyServiceDelete,
		`BucketPropertySystemCreate`:      stmt.TxBucketPropertySystemCreate,
		`BucketPropertySystemDelete`:      stmt.TxBucketPropertySystemDelete,
		`BucketPropertyCustomCreate`:      stmt.TxBucketPropertyCustomCreate,
		`BucketPropertyCustomDelete`:      stmt.TxBucketPropertyCustomDelete,
		`GroupPropertyOncallCreate`:       stmt.TxGroupPropertyOncallCreate,
		`GroupPropertyOncallDelete`:       stmt.TxGroupPropertyOncallDelete,
		`GroupPropertyServiceCreate`:      stmt.TxGroupPropertyServiceCreate,
		`GroupPropertyServiceDelete`:      stmt.TxGroupPropertyServiceDelete,
		`GroupPropertySystemCreate`:       stmt.TxGroupPropertySystemCreate,
		`GroupPropertySystemDelete`:       stmt.TxGroupPropertySystemDelete,
		`GroupPropertyCustomCreate`:       stmt.TxGroupPropertyCustomCreate,
		`GroupPropertyCustomDelete`:       stmt.TxGroupPropertyCustomDelete,
		`ClusterPropertyOncallCreate`:     stmt.TxClusterPropertyOncallCreate,
		`ClusterPropertyOncallDelete`:     stmt.TxClusterPropertyOncallDelete,
		`ClusterPropertyServiceCreate`:    stmt.TxClusterPropertyServiceCreate,
		`ClusterPropertyServiceDelete`:    stmt.TxClusterPropertyServiceDelete,
		`ClusterPropertySystemCreate`:     stmt.TxClusterPropertySystemCreate,
		`ClusterPropertySystemDelete`:     stmt.TxClusterPropertySystemDelete,
		`ClusterPropertyCustomCreate`:     stmt.TxClusterPropertyCustomCreate,
		`ClusterPropertyCustomDelete`:     stmt.TxClusterPropertyCustomDelete,
		`NodePropertyOncallCreate`:        stmt.TxNodePropertyOncallCreate,
		`NodePropertyOncallDelete`:        stmt.TxNodePropertyOncallDelete,
		`NodePropertyServiceCreate`:       stmt.TxNodePropertyServiceCreate,
		`NodePropertyServiceDelete`:       stmt.TxNodePropertyServiceDelete,
		`NodePropertySystemCreate`:        stmt.TxNodePropertySystemCreate,
		`NodePropertySystemDelete`:        stmt.TxNodePropertySystemDelete,
		`NodePropertyCustomCreate`:        stmt.TxNodePropertyCustomCreate,
		`NodePropertyCustomDelete`:        stmt.TxNodePropertyCustomDelete,
	} {
		if stMap[name], err = tx.Prepare(statement); err != nil {
			err = fmt.Errorf("tk.Prepare(%s) error: %s",
				name, err.Error())
			delete(stMap, name)
			goto bailout
		}
	}

	//
	// CHECK STATEMENTS
	for name, statement := range map[string]string{
		`CreateCheck`: stmt.TxCreateCheck,
		`DeleteCheck`: stmt.TxMarkCheckDeleted,
	} {
		if stMap[name], err = tx.Prepare(statement); err != nil {
			err = fmt.Errorf("tk.Prepare(%s) error: %s",
				name, err.Error())
			delete(stMap, name)
			goto bailout
		}
	}

	//
	// CHECK INSTANCE STATEMENTS
	for name, statement := range map[string]string{
		`CreateCheckInstance`:              stmt.TxCreateCheckInstance,
		`CreateCheckInstanceConfiguration`: stmt.TxCreateCheckInstanceConfiguration,
		`DeleteCheckInstance`:              stmt.TxMarkCheckInstanceDeleted,
	} {
		if stMap[name], err = tx.Prepare(statement); err != nil {
			err = fmt.Errorf("tk.Prepare(%s) error: %s",
				name, err.Error())
			delete(stMap, name)
			goto bailout
		}
	}

	//
	// CHECK CONFIGURATION STATEMENTS
	for name, statement := range map[string]string{
		`CreateCheckConfigurationBase`:                stmt.TxCreateCheckConfigurationBase,
		`CreateCheckConfigurationThreshold`:           stmt.TxCreateCheckConfigurationThreshold,
		`CreateCheckConfigurationConstraintSystem`:    stmt.TxCreateCheckConfigurationConstraintSystem,
		`CreateCheckConfigurationConstraintNative`:    stmt.TxCreateCheckConfigurationConstraintNative,
		`CreateCheckConfigurationConstraintOncall`:    stmt.TxCreateCheckConfigurationConstraintOncall,
		`CreateCheckConfigurationConstraintCustom`:    stmt.TxCreateCheckConfigurationConstraintCustom,
		`CreateCheckConfigurationConstraintService`:   stmt.TxCreateCheckConfigurationConstraintService,
		`CreateCheckConfigurationConstraintAttribute`: stmt.TxCreateCheckConfigurationConstraintAttribute,
	} {
		if stMap[name], err = tx.Prepare(statement); err != nil {
			err = fmt.Errorf("tk.Prepare(%s) error: %s",
				name, err.Error())
			delete(stMap, name)
			goto bailout
		}
	}

	//
	// TREE MANIPULATION STATEMENTS
	for name, statement := range map[string]string{
		`BucketAssignNode`:         stmt.TxBucketAssignNode,
		`ClusterCreate`:            stmt.TxClusterCreate,
		`ClusterDelete`:            stmt.TxClusterDelete,
		`ClusterMemberNew`:         stmt.TxClusterMemberNew,
		`ClusterMemberRemove`:      stmt.TxClusterMemberRemove,
		`ClusterUpdate`:            stmt.TxClusterUpdate,
		`CreateBucket`:             stmt.TxCreateBucket,
		`GroupCreate`:              stmt.TxGroupCreate,
		`GroupDelete`:              stmt.TxGroupDelete,
		`GroupMemberNewCluster`:    stmt.TxGroupMemberNewCluster,
		`GroupMemberNewGroup`:      stmt.TxGroupMemberNewGroup,
		`GroupMemberNewNode`:       stmt.TxGroupMemberNewNode,
		`GroupMemberRemoveCluster`: stmt.TxGroupMemberRemoveCluster,
		`GroupMemberRemoveGroup`:   stmt.TxGroupMemberRemoveGroup,
		`GroupMemberRemoveNode`:    stmt.TxGroupMemberRemoveNode,
		`GroupUpdate`:              stmt.TxGroupUpdate,
		`NodeUnassignFromBucket`:   stmt.TxNodeUnassignFromBucket,
		`UpdateNodeState`:          stmt.TxUpdateNodeState,
	} {
		if stMap[name], err = tx.Prepare(statement); err != nil {
			err = fmt.Errorf("tk.Prepare(%s) error: %s",
				name, err.Error())
			delete(stMap, name)
			goto bailout
		}
	}

	return tx, stMap, nil

bailout:
	if open {
		// if the transaction was opened, then tx.Rollback() will close all
		// prepared statements. If the transaction was not opened yet, then
		// no statements have been prepared inside it - there is nothing to
		// close
		defer tx.Rollback()
	}
	return nil, nil, err
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>