<commit_before>package ardrone

import (
	"testing"

	"github.com/hybridgroup/gobot"
)

func initTestArdroneDriver() *ArdroneDriver {
	a := NewArdroneAdaptor("drone")
	a.connect = func(a *ArdroneAdaptor) (drone, error) {
		return &testDrone{}, nil
	}
	d := NewArdroneDriver(a, "drone")
	a.Connect()
	return d
}

func TestArdroneDriverStart(t *testing.T) {
	d := initTestArdroneDriver()
	gobot.Assert(t, d.Name(), "drone")
	gobot.Assert(t, d.Connection().Name(), "drone")
}

func TestArdroneDriverHalt(t *testing.T) {
	d := initTestArdroneDriver()
	gobot.Assert(t, len(d.Halt()), 0)
}
func TestArdroneDriverTakeOff(t *testing.T) {
	d := initTestArdroneDriver()
	d.TakeOff()
}

func TestArdroneDriverand(t *testing.T) {
	d := initTestArdroneDriver()
	d.Land()
}

func TestArdroneDriverUp(t *testing.T) {
	d := initTestArdroneDriver()
	d.Up(1)
}

func TestArdroneDriverDown(t *testing.T) {
	d := initTestArdroneDriver()
	d.Down(1)
}

func TestArdroneDriverLeft(t *testing.T) {
	d := initTestArdroneDriver()
	d.Left(1)
}

func TestArdroneDriverRight(t *testing.T) {
	d := initTestArdroneDriver()
	d.Right(1)
}

func TestArdroneDriverForward(t *testing.T) {
	d := initTestArdroneDriver()
	d.Forward(1)
}

func TestArdroneDriverackward(t *testing.T) {
	d := initTestArdroneDriver()
	d.Backward(1)
}

func TestArdroneDriverClockwise(t *testing.T) {
	d := initTestArdroneDriver()
	d.Clockwise(1)
}

func TestArdroneDriverCounterClockwise(t *testing.T) {
	d := initTestArdroneDriver()
	d.CounterClockwise(1)
}

func TestArdroneDriverHover(t *testing.T) {
	d := initTestArdroneDriver()
	d.Hover()
}
<commit_msg>Add Start test for ArdroneDriver<commit_after>package ardrone

import (
	"testing"

	"github.com/hybridgroup/gobot"
)

func initTestArdroneDriver() *ArdroneDriver {
	a := NewArdroneAdaptor("drone")
	a.connect = func(a *ArdroneAdaptor) (drone, error) {
		return &testDrone{}, nil
	}
	d := NewArdroneDriver(a, "drone")
	a.Connect()
	return d
}

func TestArdroneDriver(t *testing.T) {
	d := initTestArdroneDriver()
	gobot.Assert(t, d.Name(), "drone")
	gobot.Assert(t, d.Connection().Name(), "drone")
}

func TestArdroneDriverStart(t *testing.T) {
	d := initTestArdroneDriver()
	gobot.Assert(t, len(d.Start()), 0)
}

func TestArdroneDriverHalt(t *testing.T) {
	d := initTestArdroneDriver()
	gobot.Assert(t, len(d.Halt()), 0)
}
func TestArdroneDriverTakeOff(t *testing.T) {
	d := initTestArdroneDriver()
	d.TakeOff()
}

func TestArdroneDriverand(t *testing.T) {
	d := initTestArdroneDriver()
	d.Land()
}

func TestArdroneDriverUp(t *testing.T) {
	d := initTestArdroneDriver()
	d.Up(1)
}

func TestArdroneDriverDown(t *testing.T) {
	d := initTestArdroneDriver()
	d.Down(1)
}

func TestArdroneDriverLeft(t *testing.T) {
	d := initTestArdroneDriver()
	d.Left(1)
}

func TestArdroneDriverRight(t *testing.T) {
	d := initTestArdroneDriver()
	d.Right(1)
}

func TestArdroneDriverForward(t *testing.T) {
	d := initTestArdroneDriver()
	d.Forward(1)
}

func TestArdroneDriverackward(t *testing.T) {
	d := initTestArdroneDriver()
	d.Backward(1)
}

func TestArdroneDriverClockwise(t *testing.T) {
	d := initTestArdroneDriver()
	d.Clockwise(1)
}

func TestArdroneDriverCounterClockwise(t *testing.T) {
	d := initTestArdroneDriver()
	d.CounterClockwise(1)
}

func TestArdroneDriverHover(t *testing.T) {
	d := initTestArdroneDriver()
	d.Hover()
}
<|endoftext|>


<commit_before>package goredis

import (
	"fmt"
	"testing"
	"time"
)

var (
	network  = "tcp"
	address  = "192.168.84.250:6379"
	db       = 1
	password = ""
	timeout  = 5 * time.Second
	maxidle  = 1
	r        *Redis

	format = "tcp://auth:%s@%s/%d?timeout=%s&maxidle=%d"
)

func init() {
	client, err := Dial(&DialConfig{network, address, db, password, timeout, maxidle})
	if err != nil {
		panic(err)
	}
	r = client
}

func TestDial(t *testing.T) {
	redis, err := Dial(&DialConfig{network, address, db, password, timeout, maxidle})
	if err != nil {
		t.Error(err)
	} else if err := redis.Ping(); err != nil {
		t.Error(err)
	}
	redis.pool.Close()
}

func TestDialTimeout(t *testing.T) {
	redis, err := Dial(&DialConfig{network, address, db, password, timeout, maxidle})
	if err != nil {
		t.Error(err)
	} else if err := redis.Ping(); err != nil {
		t.Error(err)
	}
	redis.pool.Close()
}

func TestDiaURL(t *testing.T) {
	redis, err := DialURL(fmt.Sprintf(format, password, address, db, timeout.String(), maxidle))
	if err != nil {
		t.Fatal(err)
	} else if err := redis.Ping(); err != nil {
		t.Error(err)
	}
	redis.pool.Close()
}
<commit_msg>test: change test redis server to local<commit_after>package goredis

import (
	"fmt"
	"testing"
	"time"
)

var (
	network  = "tcp"
	address  = "127.0.0.1:6379"
	db       = 1
	password = ""
	timeout  = 5 * time.Second
	maxidle  = 1
	r        *Redis

	format = "tcp://auth:%s@%s/%d?timeout=%s&maxidle=%d"
)

func init() {
	client, err := Dial(&DialConfig{network, address, db, password, timeout, maxidle})
	if err != nil {
		panic(err)
	}
	r = client
}

func TestDial(t *testing.T) {
	redis, err := Dial(&DialConfig{network, address, db, password, timeout, maxidle})
	if err != nil {
		t.Error(err)
	} else if err := redis.Ping(); err != nil {
		t.Error(err)
	}
	redis.pool.Close()
}

func TestDialTimeout(t *testing.T) {
	redis, err := Dial(&DialConfig{network, address, db, password, timeout, maxidle})
	if err != nil {
		t.Error(err)
	} else if err := redis.Ping(); err != nil {
		t.Error(err)
	}
	redis.pool.Close()
}

func TestDiaURL(t *testing.T) {
	redis, err := DialURL(fmt.Sprintf(format, password, address, db, timeout.String(), maxidle))
	if err != nil {
		t.Fatal(err)
	} else if err := redis.Ping(); err != nil {
		t.Error(err)
	}
	redis.pool.Close()
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 contiv

import (
	"context"
	"reflect"
	"strings"
	"testing"

	"git.fd.io/govpp.git/adapter/mock"
	govppmock "git.fd.io/govpp.git/adapter/mock"
	"git.fd.io/govpp.git/adapter/mock/binapi"
	"git.fd.io/govpp.git/api"
	govpp "git.fd.io/govpp.git/core"

	"github.com/contiv/vpp/mock/localclient"
	"github.com/contiv/vpp/plugins/contiv/containeridx"
	"github.com/contiv/vpp/plugins/contiv/model/cni"
	"github.com/contiv/vpp/plugins/kvdbproxy"

	"github.com/ligato/cn-infra/core"
	"github.com/ligato/cn-infra/logging/logroot"
	"github.com/ligato/vpp-agent/idxvpp/nametoidx"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/bin_api/af_packet"
	interfaces_bin "github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/bin_api/interfaces"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/bin_api/ip"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/bin_api/memif"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/bin_api/tap"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/bin_api/vpe"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/bin_api/vxlan"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/ifaceidx"
	vpp_intf "github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/model/interfaces"

	"github.com/contiv/vpp/plugins/contiv/bin_api/session"
	"github.com/contiv/vpp/plugins/contiv/bin_api/stn"
	"github.com/contiv/vpp/plugins/contiv/ipam"
	"github.com/onsi/gomega"
)

const (
	containerID = "sadfja813227wdhfjkh2319784dgh"
	podName     = "ubuntu"
)

var swIfIndexSeq uint32

var req = cni.CNIRequest{
	Version:          "0.2.3",
	InterfaceName:    "eth0",
	ContainerId:      containerID,
	NetworkNamespace: "/var/run/2345243",
	ExtraArguments:   "IgnoreUnknown=1;K8S_POD_NAMESPACE=default;K8S_POD_NAME=" + podName + ";K8S_POD_INFRA_CONTAINER_ID=7d673108b0ff9b2f59f977ca5f4cef347cb9ca66888614068882fbfaba4de752",
}

var ipamConfig = ipam.Config{
	PodSubnetCIDR:           "10.1.0.0/16",
	PodNetworkPrefixLen:     24,
	VSwitchSubnetCIDR:       "172.30.0.0/16",
	VSwitchNetworkPrefixLen: 24,
	HostNodeSubnetCidr:      "192.168.16.0/24",
}

func TestVeth1NameFromRequest(t *testing.T) {
	gomega.RegisterTestingT(t)

	txns := localclient.NewTxnTracker(nil)

	server, err := newRemoteCNIServer(logroot.StandardLogger(),
		txns.NewDataChangeTxn,
		&kvdbproxy.Plugin{},
		nil,
		nil,
		nil,
		"testlabel",
		&ipamConfig,
		0)
	gomega.Expect(err).To(gomega.BeNil())

	hostIfName := server.veth1HostIfNameFromRequest(&req)
	gomega.Expect(hostIfName).To(gomega.BeEquivalentTo("eth0"))
}

func TestAdd(t *testing.T) {
	gomega.RegisterTestingT(t)

	swIfIdx := swIfIndexMock()
	txns := localclient.NewTxnTracker(addIfsIntoTheIndex(swIfIdx))
	configuredContainers := containeridx.NewConfigIndex(logroot.StandardLogger(), core.PluginName("Plugin-name"), "title")

	server, err := newRemoteCNIServer(logroot.StandardLogger(),
		txns.NewDataChangeTxn,
		kvdbproxy.NewKvdbsyncMock(),
		configuredContainers,
		vppChanMock(),
		swIfIdx,
		"testLabel",
		&ipamConfig,
		0)
	gomega.Expect(err).To(gomega.BeNil())
	server.hostCalls = &mockLinuxCalls{}

	reply, err := server.Add(context.Background(), &req)

	gomega.Expect(err).To(gomega.BeNil())
	gomega.Expect(reply).NotTo(gomega.BeNil())

	gomega.Expect(len(txns.PendingTxns)).To(gomega.BeEquivalentTo(0))
	gomega.Expect(len(txns.CommittedTxns)).To(gomega.BeEquivalentTo(1))
	// TODO add asserts for txns / currently applied config

	res := configuredContainers.LookupPodName(podName)
	gomega.Expect(len(res)).To(gomega.BeEquivalentTo(1))
	gomega.Expect(res).To(gomega.ContainElement(containerID))

	txns.Clear()

	reply, err = server.Delete(context.Background(), &req)
	gomega.Expect(err).To(gomega.BeNil())
	gomega.Expect(reply).NotTo(gomega.BeNil())

}

func vppChanMock() *api.Channel {
	vppMock := &mock.VppAdapter{}
	vppMock.RegisterBinAPITypes(interfaces_bin.Types)
	vppMock.RegisterBinAPITypes(memif.Types)
	vppMock.RegisterBinAPITypes(tap.Types)
	vppMock.RegisterBinAPITypes(af_packet.Types)
	vppMock.RegisterBinAPITypes(vpe.Types)
	vppMock.RegisterBinAPITypes(vxlan.Types)
	vppMock.RegisterBinAPITypes(ip.Types)
	vppMock.RegisterBinAPITypes(stn.Types)
	vppMock.RegisterBinAPITypes(session.Types)

	vppMock.MockReplyHandler(func(request govppmock.MessageDTO) (reply []byte, msgID uint16, prepared bool) {
		reqName, found := vppMock.GetMsgNameByID(request.MsgID)
		if !found {
			logroot.StandardLogger().Error("Not existing req msg name for MsgID=", request.MsgID)
			return reply, 0, false
		}
		logroot.StandardLogger().Debug("MockReplyHandler ", request.MsgID, " ", reqName)

		if reqName == "sw_interface_dump" {
			codec := govpp.MsgCodec{}
			ifDump := interfaces_bin.SwInterfaceDump{}
			err := codec.DecodeMsg(request.Data, &ifDump)
			if err != nil {
				logroot.StandardLogger().Error(err)
				return reply, 0, false
			}
			msgID, err := vppMock.GetMsgID("sw_interface_details", "")
			if err != nil {
				logroot.StandardLogger().Error(err)
				return reply, 0, false
			}

			if ifDump.NameFilterValid == 1 {
				ifDetail := interfaces_bin.SwInterfaceDetails{}
				ifDetail.InterfaceName = ifDump.NameFilter
				reply, err := vppMock.ReplyBytes(request, &ifDetail)
				if err == nil {
					return reply, msgID, true
				}
			}

		} else if strings.HasSuffix(reqName, "_dump") {
			//do nothing and let reply next time for control_ping
		} else {
			if replyMsg, msgID, ok := vppMock.ReplyFor(reqName); ok {
				val := reflect.ValueOf(replyMsg)
				valType := val.Type()
				if binapi.HasSwIfIdx(valType) {
					swIfIndexSeq++
					logroot.StandardLogger().Debug("Succ default reply for ", reqName, " ", msgID, " sw_if_idx=", swIfIndexSeq)
					binapi.SetSwIfIdx(val, swIfIndexSeq)
				} else {
					logroot.StandardLogger().Debug("Succ default reply for ", reqName, " ", msgID)
				}

				reply, err := vppMock.ReplyBytes(request, replyMsg)
				if err == nil {
					return reply, msgID, true
				}
				logroot.StandardLogger().Error("Error creating bytes ", err)
			} else {
				logroot.StandardLogger().Info("No default reply for ", reqName, ", ", request.MsgID)
			}
		}

		return reply, 0, false
	})

	conn, err := govpp.Connect(vppMock)
	if err != nil {
		return nil
	}

	c, _ := conn.NewAPIChannel()
	return c
}

func addIfsIntoTheIndex(mapping ifaceidx.SwIfIndexRW) func(txn *localclient.Txn) error {
	return func(txn *localclient.Txn) error {
		var cnt uint32 = 1
		if txn.DataChangeTxn == nil {
			// RESYNC not handled
			return nil
		}
		for _, op := range txn.DataChangeTxn.Ops {
			if op.Value != nil /* Put */ && strings.HasPrefix(op.Key, vpp_intf.InterfaceKeyPrefix()) {
				name, err := vpp_intf.ParseNameFromKey(op.Key)
				if err != nil {
					return err
				}
				if data, ok := (op.Value).(*vpp_intf.Interfaces_Interface); ok {
					mapping.RegisterName(name, cnt, data)
					cnt++
				}
			}
		}
		return nil
	}
}

func swIfIndexMock() ifaceidx.SwIfIndexRW {
	mapping := nametoidx.NewNameToIdx(logroot.StandardLogger(), "plugin", "swIf", ifaceidx.IndexMetadata)

	return ifaceidx.NewSwIfIndex(mapping)
}
<commit_msg>fixed tests for changes<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 contiv

import (
	"context"
	"reflect"
	"strings"
	"testing"

	"git.fd.io/govpp.git/adapter/mock"
	govppmock "git.fd.io/govpp.git/adapter/mock"
	"git.fd.io/govpp.git/adapter/mock/binapi"
	"git.fd.io/govpp.git/api"
	govpp "git.fd.io/govpp.git/core"

	"github.com/contiv/vpp/mock/localclient"
	"github.com/contiv/vpp/plugins/contiv/containeridx"
	"github.com/contiv/vpp/plugins/contiv/model/cni"
	"github.com/contiv/vpp/plugins/kvdbproxy"

	"github.com/ligato/cn-infra/core"
	"github.com/ligato/cn-infra/logging/logroot"
	"github.com/ligato/vpp-agent/idxvpp/nametoidx"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/bin_api/af_packet"
	interfaces_bin "github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/bin_api/interfaces"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/bin_api/ip"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/bin_api/memif"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/bin_api/tap"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/bin_api/vpe"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/bin_api/vxlan"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/ifaceidx"
	vpp_intf "github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/model/interfaces"

	"github.com/contiv/vpp/plugins/contiv/bin_api/session"
	"github.com/contiv/vpp/plugins/contiv/bin_api/stn"
	"github.com/contiv/vpp/plugins/contiv/ipam"
	"github.com/onsi/gomega"
)

const (
	containerID = "sadfja813227wdhfjkh2319784dgh"
	podName     = "ubuntu"
)

var swIfIndexSeq uint32

var req = cni.CNIRequest{
	Version:          "0.2.3",
	InterfaceName:    "eth0",
	ContainerId:      containerID,
	NetworkNamespace: "/var/run/2345243",
	ExtraArguments:   "IgnoreUnknown=1;K8S_POD_NAMESPACE=default;K8S_POD_NAME=" + podName + ";K8S_POD_INFRA_CONTAINER_ID=7d673108b0ff9b2f59f977ca5f4cef347cb9ca66888614068882fbfaba4de752",
}

var config = Config{
	IPAMConfig: ipam.Config{
		PodSubnetCIDR:           "10.1.0.0/16",
		PodNetworkPrefixLen:     24,
		VSwitchSubnetCIDR:       "172.30.0.0/16",
		VSwitchNetworkPrefixLen: 24,
		HostNodeSubnetCidr:      "192.168.16.0/24",
	},
}

func TestVeth1NameFromRequest(t *testing.T) {
	gomega.RegisterTestingT(t)

	txns := localclient.NewTxnTracker(nil)

	server, err := newRemoteCNIServer(logroot.StandardLogger(),
		txns.NewDataChangeTxn,
		&kvdbproxy.Plugin{},
		nil,
		nil,
		nil,
		"testlabel",
		&config,
		0)
	gomega.Expect(err).To(gomega.BeNil())

	hostIfName := server.veth1HostIfNameFromRequest(&req)
	gomega.Expect(hostIfName).To(gomega.BeEquivalentTo("eth0"))
}

func TestAdd(t *testing.T) {
	gomega.RegisterTestingT(t)

	swIfIdx := swIfIndexMock()
	txns := localclient.NewTxnTracker(addIfsIntoTheIndex(swIfIdx))
	configuredContainers := containeridx.NewConfigIndex(logroot.StandardLogger(), core.PluginName("Plugin-name"), "title")

	server, err := newRemoteCNIServer(logroot.StandardLogger(),
		txns.NewDataChangeTxn,
		kvdbproxy.NewKvdbsyncMock(),
		configuredContainers,
		vppChanMock(),
		swIfIdx,
		"testLabel",
		&config,
		0)
	gomega.Expect(err).To(gomega.BeNil())
	server.hostCalls = &mockLinuxCalls{}

	reply, err := server.Add(context.Background(), &req)

	gomega.Expect(err).To(gomega.BeNil())
	gomega.Expect(reply).NotTo(gomega.BeNil())

	gomega.Expect(len(txns.PendingTxns)).To(gomega.BeEquivalentTo(0))
	gomega.Expect(len(txns.CommittedTxns)).To(gomega.BeEquivalentTo(1))
	// TODO add asserts for txns / currently applied config

	res := configuredContainers.LookupPodName(podName)
	gomega.Expect(len(res)).To(gomega.BeEquivalentTo(1))
	gomega.Expect(res).To(gomega.ContainElement(containerID))

	txns.Clear()

	reply, err = server.Delete(context.Background(), &req)
	gomega.Expect(err).To(gomega.BeNil())
	gomega.Expect(reply).NotTo(gomega.BeNil())

}

func vppChanMock() *api.Channel {
	vppMock := &mock.VppAdapter{}
	vppMock.RegisterBinAPITypes(interfaces_bin.Types)
	vppMock.RegisterBinAPITypes(memif.Types)
	vppMock.RegisterBinAPITypes(tap.Types)
	vppMock.RegisterBinAPITypes(af_packet.Types)
	vppMock.RegisterBinAPITypes(vpe.Types)
	vppMock.RegisterBinAPITypes(vxlan.Types)
	vppMock.RegisterBinAPITypes(ip.Types)
	vppMock.RegisterBinAPITypes(stn.Types)
	vppMock.RegisterBinAPITypes(session.Types)

	vppMock.MockReplyHandler(func(request govppmock.MessageDTO) (reply []byte, msgID uint16, prepared bool) {
		reqName, found := vppMock.GetMsgNameByID(request.MsgID)
		if !found {
			logroot.StandardLogger().Error("Not existing req msg name for MsgID=", request.MsgID)
			return reply, 0, false
		}
		logroot.StandardLogger().Debug("MockReplyHandler ", request.MsgID, " ", reqName)

		if reqName == "sw_interface_dump" {
			codec := govpp.MsgCodec{}
			ifDump := interfaces_bin.SwInterfaceDump{}
			err := codec.DecodeMsg(request.Data, &ifDump)
			if err != nil {
				logroot.StandardLogger().Error(err)
				return reply, 0, false
			}
			msgID, err := vppMock.GetMsgID("sw_interface_details", "")
			if err != nil {
				logroot.StandardLogger().Error(err)
				return reply, 0, false
			}

			if ifDump.NameFilterValid == 1 {
				ifDetail := interfaces_bin.SwInterfaceDetails{}
				ifDetail.InterfaceName = ifDump.NameFilter
				reply, err := vppMock.ReplyBytes(request, &ifDetail)
				if err == nil {
					return reply, msgID, true
				}
			}

		} else if strings.HasSuffix(reqName, "_dump") {
			//do nothing and let reply next time for control_ping
		} else {
			if replyMsg, msgID, ok := vppMock.ReplyFor(reqName); ok {
				val := reflect.ValueOf(replyMsg)
				valType := val.Type()
				if binapi.HasSwIfIdx(valType) {
					swIfIndexSeq++
					logroot.StandardLogger().Debug("Succ default reply for ", reqName, " ", msgID, " sw_if_idx=", swIfIndexSeq)
					binapi.SetSwIfIdx(val, swIfIndexSeq)
				} else {
					logroot.StandardLogger().Debug("Succ default reply for ", reqName, " ", msgID)
				}

				reply, err := vppMock.ReplyBytes(request, replyMsg)
				if err == nil {
					return reply, msgID, true
				}
				logroot.StandardLogger().Error("Error creating bytes ", err)
			} else {
				logroot.StandardLogger().Info("No default reply for ", reqName, ", ", request.MsgID)
			}
		}

		return reply, 0, false
	})

	conn, err := govpp.Connect(vppMock)
	if err != nil {
		return nil
	}

	c, _ := conn.NewAPIChannel()
	return c
}

func addIfsIntoTheIndex(mapping ifaceidx.SwIfIndexRW) func(txn *localclient.Txn) error {
	return func(txn *localclient.Txn) error {
		var cnt uint32 = 1
		if txn.DataChangeTxn == nil {
			// RESYNC not handled
			return nil
		}
		for _, op := range txn.DataChangeTxn.Ops {
			if op.Value != nil /* Put */ && strings.HasPrefix(op.Key, vpp_intf.InterfaceKeyPrefix()) {
				name, err := vpp_intf.ParseNameFromKey(op.Key)
				if err != nil {
					return err
				}
				if data, ok := (op.Value).(*vpp_intf.Interfaces_Interface); ok {
					mapping.RegisterName(name, cnt, data)
					cnt++
				}
			}
		}
		return nil
	}
}

func swIfIndexMock() ifaceidx.SwIfIndexRW {
	mapping := nametoidx.NewNameToIdx(logroot.StandardLogger(), "plugin", "swIf", ifaceidx.IndexMetadata)

	return ifaceidx.NewSwIfIndex(mapping)
}
<|endoftext|>


<commit_before><commit_msg>remove the dependency to Json<commit_after><|endoftext|>


<commit_before><commit_msg>Fix TSDB race while reading histograms<commit_after><|endoftext|>


<commit_before>package credsutil

import (
	"fmt"
	"time"

	"github.com/hashicorp/vault/builtin/logical/database/dbplugin"
)

const (
	NoneLength int = -1
)

// SQLCredentialsProducer implements CredentialsProducer and provides a generic credentials producer for most sql database types.
type SQLCredentialsProducer struct {
	DisplayNameLen int
	RoleNameLen    int
	UsernameLen    int
	Separator      string
}

func (scp *SQLCredentialsProducer) GenerateUsername(config dbplugin.UsernameConfig) (string, error) {
	username := "v"

	displayName := config.DisplayName
	if scp.DisplayNameLen > 0 && len(displayName) > scp.DisplayNameLen {
		displayName = displayName[:scp.DisplayNameLen]
	} else if scp.DisplayNameLen == NoneLength {
		displayName = ""
	}

	if len(displayName) > 0 {
		username = fmt.Sprintf("%s%s%s", username, scp.Separator, displayName)
	}

	roleName := config.RoleName
	if scp.RoleNameLen > 0 && len(roleName) > scp.RoleNameLen {
		roleName = roleName[:scp.RoleNameLen]
	} else if scp.RoleNameLen == NoneLength {
		roleName = ""
	}

	if len(roleName) > 0 {
		username = fmt.Sprintf("%s%s%s", username, scp.Separator, roleName)
	}

	userUUID, err := RandomAlphaNumeric(20, false)
	if err != nil {
		return "", err
	}

	username = fmt.Sprintf("%s%s%s", username, scp.Separator, userUUID)
	username = fmt.Sprintf("%s%s%s", username, scp.Separator, fmt.Sprint(time.Now().UTC().Unix()))
	if scp.UsernameLen > 0 && len(username) > scp.UsernameLen {
		username = username[:scp.UsernameLen]
	}

	return username, nil
}

func (scp *SQLCredentialsProducer) GeneratePassword() (string, error) {
	password, err := RandomAlphaNumeric(20, true)
	if err != nil {
		return "", err
	}

	return password, nil
}

func (scp *SQLCredentialsProducer) GenerateExpiration(ttl time.Time) (string, error) {
	return ttl.Format("2006-01-02 15:04:05-0700"), nil
}
<commit_msg>Remove UTC call from SQL creds helper (#4336)<commit_after>package credsutil

import (
	"fmt"
	"time"

	"github.com/hashicorp/vault/builtin/logical/database/dbplugin"
)

const (
	NoneLength int = -1
)

// SQLCredentialsProducer implements CredentialsProducer and provides a generic credentials producer for most sql database types.
type SQLCredentialsProducer struct {
	DisplayNameLen int
	RoleNameLen    int
	UsernameLen    int
	Separator      string
}

func (scp *SQLCredentialsProducer) GenerateUsername(config dbplugin.UsernameConfig) (string, error) {
	username := "v"

	displayName := config.DisplayName
	if scp.DisplayNameLen > 0 && len(displayName) > scp.DisplayNameLen {
		displayName = displayName[:scp.DisplayNameLen]
	} else if scp.DisplayNameLen == NoneLength {
		displayName = ""
	}

	if len(displayName) > 0 {
		username = fmt.Sprintf("%s%s%s", username, scp.Separator, displayName)
	}

	roleName := config.RoleName
	if scp.RoleNameLen > 0 && len(roleName) > scp.RoleNameLen {
		roleName = roleName[:scp.RoleNameLen]
	} else if scp.RoleNameLen == NoneLength {
		roleName = ""
	}

	if len(roleName) > 0 {
		username = fmt.Sprintf("%s%s%s", username, scp.Separator, roleName)
	}

	userUUID, err := RandomAlphaNumeric(20, false)
	if err != nil {
		return "", err
	}

	username = fmt.Sprintf("%s%s%s", username, scp.Separator, userUUID)
	username = fmt.Sprintf("%s%s%s", username, scp.Separator, fmt.Sprint(time.Now().Unix()))
	if scp.UsernameLen > 0 && len(username) > scp.UsernameLen {
		username = username[:scp.UsernameLen]
	}

	return username, nil
}

func (scp *SQLCredentialsProducer) GeneratePassword() (string, error) {
	password, err := RandomAlphaNumeric(20, true)
	if err != nil {
		return "", err
	}

	return password, nil
}

func (scp *SQLCredentialsProducer) GenerateExpiration(ttl time.Time) (string, error) {
	return ttl.Format("2006-01-02 15:04:05-0700"), nil
}
<|endoftext|>


<commit_before>package geohash

import "testing"

type TestCase struct {
	hashInt  uint64
	hash     string
	lat, lng float64
}

func TestEncode(t *testing.T) {
	for _, c := range testcases {
		hash := Encode(c.lat, c.lng)
		if c.hash != hash {
			t.Errorf("incorrect encode string result for (%v,%v): %s != %s",
				c.lat, c.lng, c.hash, hash)
		}
	}
}

func TestEncodeInt(t *testing.T) {
	for _, c := range testcases {
		hashInt := EncodeInt(c.lat, c.lng)
		if c.hashInt != hashInt {
			t.Errorf("incorrect encode integer result for (%v,%v): %016x != %016x xor %016x",
				c.lat, c.lng, c.hashInt, hashInt, c.hashInt^hashInt)
		}
	}
}
<commit_msg>comments in extensive tests<commit_after>package geohash

import "testing"

// TestCase objects are generated from independent code to verify we get the
// same results. See testcases_test.go.
type TestCase struct {
	hashInt  uint64
	hash     string
	lat, lng float64
}

// Test we get the same string geohashes.
func TestEncode(t *testing.T) {
	for _, c := range testcases {
		hash := Encode(c.lat, c.lng)
		if c.hash != hash {
			t.Errorf("incorrect encode string result for (%v,%v): %s != %s",
				c.lat, c.lng, c.hash, hash)
		}
	}
}

// Test we get the same integer geohashes.
func TestEncodeInt(t *testing.T) {
	for _, c := range testcases {
		hashInt := EncodeInt(c.lat, c.lng)
		if c.hashInt != hashInt {
			t.Errorf("incorrect encode integer result for (%v,%v): %016x != %016x xor %016x",
				c.lat, c.lng, c.hashInt, hashInt, c.hashInt^hashInt)
		}
	}
}
<|endoftext|>


<commit_before>package gokeepasslib

import (
	"bytes"
	"encoding/binary"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
)

// Inner header bytes
const (
	InnerHeaderTerminator byte = 0x00 // Inner header terminator byte
	InnerHeaderIRSID      byte = 0x01 // Inner header InnerRandomStreamID byte
	InnerHeaderIRSKey     byte = 0x02 // Inner header InnerRandomStreamKey byte
	InnerHeaderBinary     byte = 0x03 // Inner header binary byte
)

// DBContent is a container for all elements of a keepass database
type DBContent struct {
	RawData     []byte       `xml:"-"` // XML encoded original data
	InnerHeader *InnerHeader `xml:"-"`
	XMLName     xml.Name     `xml:"KeePassFile"`
	Meta        *MetaData    `xml:"Meta"`
	Root        *RootData    `xml:"Root"`
}

// InnerHeader is the container of crypt options and binaries, only for Kdbx v4
type InnerHeader struct {
	InnerRandomStreamID  uint32
	InnerRandomStreamKey []byte
	Binaries             Binaries
}

// NewContent creates a new database content with some good defaults
func NewContent() *DBContent {
	// Not necessary create InnerHeader because this will be a KDBX v3.1
	return &DBContent{
		Meta: NewMetaData(),
		Root: NewRootData(),
	}
}

// readFrom reads the InnerHeader from an io.Reader
func (ih *InnerHeader) readFrom(r io.Reader) error {
	binaryCount := 0 // Var used to count and index every binary
	for {
		var headerType byte
		var length int32
		var data []byte

		if err := binary.Read(r, binary.LittleEndian, &headerType); err != nil {
			return err
		}
		if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
			return err
		}
		data = make([]byte, length)
		if err := binary.Read(r, binary.LittleEndian, &data); err != nil {
			return err
		}

		switch headerType {
		case InnerHeaderTerminator:
			// End of inner header
			break
		case InnerHeaderIRSID:
			// Found InnerRandomStream ID
			ih.InnerRandomStreamID = binary.LittleEndian.Uint32(data)
		case InnerHeaderIRSKey:
			// Found InnerRandomStream Key
			ih.InnerRandomStreamKey = data
		case InnerHeaderBinary:
			// Found a binary
			var protection byte
			reader := bytes.NewReader(data)

			binary.Read(reader, binary.LittleEndian, &protection) // Read memory protection flag
			content, _ := ioutil.ReadAll(reader)                  // Read content

			ih.Binaries = append(ih.Binaries, Binary{
				ID:               binaryCount,
				MemoryProtection: protection,
				Content:          content,
			})

			binaryCount = binaryCount + 1
		default:
			return ErrUnknownInnerHeaderID(typ)
		}
	}
	return nil
}

// writeTo the InnerHeader to the given io.Writer
func (ih *InnerHeader) writeTo(w io.Writer) error {
	irsID := make([]byte, 4)
	binary.LittleEndian.PutUint32(irsID, ih.InnerRandomStreamID)

	if err := writeToInnerHeader(w, InnerHeaderIRSID, irsID); err != nil {
		return err
	}
	if err := writeToInnerHeader(w, InnerHeaderIRSKey, ih.InnerRandomStreamKey); err != nil {
		return err
	}

	for _, item := range ih.Binaries {
		buf := []byte{item.MemoryProtection}
		buf = append(buf, item.Content...)
		if err := writeToInnerHeader(w, InnerHeaderBinary, buf); err != nil {
			return err
		}
	}
	// End inner header
	if err := binary.Write(w, binary.LittleEndian, InnerHeaderTerminator); err != nil {
		return err
	}
	return binary.Write(w, binary.LittleEndian, uint32(0))
}

// writeToInnerHeader is an helper to write an inner header item to the given io.Writer
func writeToInnerHeader(w io.Writer, id uint8, data []byte) error {
	if len(data) > 0 {
		if err := binary.Write(w, binary.LittleEndian, id); err != nil {
			return err
		}
		if err := binary.Write(w, binary.LittleEndian, uint32(len(data))); err != nil {
			return err
		}
		if err := binary.Write(w, binary.LittleEndian, data); err != nil {
			return err
		}
	}
	return nil
}

func (ih InnerHeader) String() string {
	return fmt.Sprintf(
		"1) InnerRandomStreamID: %d\n"+
			"2) InnerRandomStreamKey: %x\n"+
			"3) Binaries: %s\n",
		ih.InnerRandomStreamID,
		ih.InnerRandomStreamKey,
		ih.Binaries,
	)
}

// ErrEndOfInnerHeaders is the error returned when the end of inner header is read
var ErrEndOfInnerHeaders = errors.New("gokeepasslib: inner header id was 0, end of inner headers")

// ErrUnknownInnerHeaderID is the error returned if an unknown inner header is read
type ErrUnknownInnerHeaderID byte

func (i ErrUnknownInnerHeaderID) Error() string {
	return fmt.Sprintf("gokeepasslib: unknown inner header ID of %x", i)
}
<commit_msg>Fix for change variable name<commit_after>package gokeepasslib

import (
	"bytes"
	"encoding/binary"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
)

// Inner header bytes
const (
	InnerHeaderTerminator byte = 0x00 // Inner header terminator byte
	InnerHeaderIRSID      byte = 0x01 // Inner header InnerRandomStreamID byte
	InnerHeaderIRSKey     byte = 0x02 // Inner header InnerRandomStreamKey byte
	InnerHeaderBinary     byte = 0x03 // Inner header binary byte
)

// DBContent is a container for all elements of a keepass database
type DBContent struct {
	RawData     []byte       `xml:"-"` // XML encoded original data
	InnerHeader *InnerHeader `xml:"-"`
	XMLName     xml.Name     `xml:"KeePassFile"`
	Meta        *MetaData    `xml:"Meta"`
	Root        *RootData    `xml:"Root"`
}

// InnerHeader is the container of crypt options and binaries, only for Kdbx v4
type InnerHeader struct {
	InnerRandomStreamID  uint32
	InnerRandomStreamKey []byte
	Binaries             Binaries
}

// NewContent creates a new database content with some good defaults
func NewContent() *DBContent {
	// Not necessary create InnerHeader because this will be a KDBX v3.1
	return &DBContent{
		Meta: NewMetaData(),
		Root: NewRootData(),
	}
}

// readFrom reads the InnerHeader from an io.Reader
func (ih *InnerHeader) readFrom(r io.Reader) error {
	binaryCount := 0 // Var used to count and index every binary
	for {
		var headerType byte
		var length int32
		var data []byte

		if err := binary.Read(r, binary.LittleEndian, &headerType); err != nil {
			return err
		}
		if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
			return err
		}
		data = make([]byte, length)
		if err := binary.Read(r, binary.LittleEndian, &data); err != nil {
			return err
		}

		switch headerType {
		case InnerHeaderTerminator:
			// End of inner header
			break
		case InnerHeaderIRSID:
			// Found InnerRandomStream ID
			ih.InnerRandomStreamID = binary.LittleEndian.Uint32(data)
		case InnerHeaderIRSKey:
			// Found InnerRandomStream Key
			ih.InnerRandomStreamKey = data
		case InnerHeaderBinary:
			// Found a binary
			var protection byte
			reader := bytes.NewReader(data)

			binary.Read(reader, binary.LittleEndian, &protection) // Read memory protection flag
			content, _ := ioutil.ReadAll(reader)                  // Read content

			ih.Binaries = append(ih.Binaries, Binary{
				ID:               binaryCount,
				MemoryProtection: protection,
				Content:          content,
			})

			binaryCount = binaryCount + 1
		default:
			return ErrUnknownInnerHeaderID(headerType)
		}
	}
	return nil
}

// writeTo the InnerHeader to the given io.Writer
func (ih *InnerHeader) writeTo(w io.Writer) error {
	irsID := make([]byte, 4)
	binary.LittleEndian.PutUint32(irsID, ih.InnerRandomStreamID)

	if err := writeToInnerHeader(w, InnerHeaderIRSID, irsID); err != nil {
		return err
	}
	if err := writeToInnerHeader(w, InnerHeaderIRSKey, ih.InnerRandomStreamKey); err != nil {
		return err
	}

	for _, item := range ih.Binaries {
		buf := []byte{item.MemoryProtection}
		buf = append(buf, item.Content...)
		if err := writeToInnerHeader(w, InnerHeaderBinary, buf); err != nil {
			return err
		}
	}
	// End inner header
	if err := binary.Write(w, binary.LittleEndian, InnerHeaderTerminator); err != nil {
		return err
	}
	return binary.Write(w, binary.LittleEndian, uint32(0))
}

// writeToInnerHeader is an helper to write an inner header item to the given io.Writer
func writeToInnerHeader(w io.Writer, id uint8, data []byte) error {
	if len(data) > 0 {
		if err := binary.Write(w, binary.LittleEndian, id); err != nil {
			return err
		}
		if err := binary.Write(w, binary.LittleEndian, uint32(len(data))); err != nil {
			return err
		}
		if err := binary.Write(w, binary.LittleEndian, data); err != nil {
			return err
		}
	}
	return nil
}

func (ih InnerHeader) String() string {
	return fmt.Sprintf(
		"1) InnerRandomStreamID: %d\n"+
			"2) InnerRandomStreamKey: %x\n"+
			"3) Binaries: %s\n",
		ih.InnerRandomStreamID,
		ih.InnerRandomStreamKey,
		ih.Binaries,
	)
}

// ErrEndOfInnerHeaders is the error returned when the end of inner header is read
var ErrEndOfInnerHeaders = errors.New("gokeepasslib: inner header id was 0, end of inner headers")

// ErrUnknownInnerHeaderID is the error returned if an unknown inner header is read
type ErrUnknownInnerHeaderID byte

func (i ErrUnknownInnerHeaderID) Error() string {
	return fmt.Sprintf("gokeepasslib: unknown inner header ID of %x", i)
}
<|endoftext|>


<commit_before>// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "ui.h"
// extern int doOnClosing(uiWindow *, void *);
// static inline void realuiWindowOnClosing(uiWindow *w)
// {
// 	uiWindowOnClosing(w, doOnClosing, NULL);
// }
import "C"

// no need to lock this; only the GUI thread can access it
var windows = make(map[*C.uiWindow]*Window)

// Window is a Control that represents a top-level window.
// A Window contains one child Control that occupies the
// entirety of the window. Though a Window is a Control,
// a Window cannot be the child of another Control.
type Window struct {
	c	*C.uiControl
	w	*C.uiWindow

	child		Control

	onClosing		func(w *Window) bool
}

// NewWindow creates a new Window.
func NewWindow(title string, width int, height int, hasMenubar bool) *Window {
	w := new(Window)

	ctitle := C.CString(title)
	// TODO wait why did I make these ints and not intmax_ts?
	w.w = C.uiNewWindow(ctitle, C.int(width), C.int(height), frombool(hasMenubar))
	w.c = (*C.uiControl)(unsafe.Pointer(w.w))
	freestr(ctitle)

	C.realuiWindowOnClosing(w.w)
	windows[w.w] = w

	return w
}

// Destroy destroys the Window. If the Window has a child,
// Destroy calls Destroy on that as well.
func (w *Window) Destroy() {
	// first hide ourselves
	w.Hide()
	// get rid of the child
	if w.child != nil {
		c := w.child
		w.SetChild(nil)
		c.Destroy()
	}
	// unregister events
	delete(windows, w.w)
	// and finally destroy ourselves
	C.uiControlDestroy(w.c)
}

// LibuiControl returns the libui uiControl pointer that backs
// the Window. This is only used by package ui itself and should
// not be called by programs.
func (w *Window) LibuiControl() uintptr {
	return uintptr(unsafe.Pointer(w.c))
}

// Handle returns the OS-level handle associated with this Window.
// On Windows this is an HWND of a libui-internal class.
// On GTK+ this is a pointer to a GtkWindow.
// On OS X this is a pointer to a NSWindow.
func (w *Window) Handle() uintptr {
	return uintptr(C.uiControlHandle(w.c))
}

// Show shows the Window. It uses the OS conception of "presenting"
// the Window, whatever that may be on a given OS.
func (w *Window) Show() {
	C.uiControlShow(w.c)
}

// Hide hides the Window.
func (w *Window) Hide() {
	C.uiControlHide(w.c)
}

// Enable enables the Window.
func (w *Window) Enable() {
	C.uiControlEnable(w.c)
}

// Disable disables the Window.
func (w *Window) Disable() {
	C.uiControlDisable(w.c)
}

// Title returns the Window's title.
func (w *Window) Title() string {
	ctitle := C.uiWindowTitle(w.w)
	title := C.GoString(ctitle)
	C.uiFreeText(ctitle)
	return title
}

// SetTitle sets the Window's title to title.
func (w *Window) SetTitle(title string) {
	ctitle := C.CString(title)
	C.uiWindowSetTitle(w.w, ctitle)
	freestr(ctitle)
}

// OnClosing registers f to be run when the user clicks the Window's
// close button. Only one function can be registered at a time.
// If f returns true, the window is destroyed with the Destroy method.
// If f returns false, or if OnClosing is never called, the window is not
// destroyed and is kept visible.
func (w *Window) OnClosing(f func(*Window) bool) {
	w.onClosing = f
}

//export doOnClosing
func doOnClosing(ww *C.uiWindow, data unsafe.Pointer) C.int {
	w := windows[ww]
	if w.onClosing == nil {
		return 0
	}
	if w.onClosing(w) {
		w.Destroy()
	}
	return 0
}

// SetChild sets the Window's child to child. If child is nil, the Window
// will not have a child.
func (w *Window) SetChild(child Control) {
	w.child = child
	c := (*C.uiControl)(nil)
	if w.child != nil {
		c = touiControl(w.child.LibuiControl())
	}
	C.uiWindowSetChild(w.w, c)
}

// Margined returns whether the Window has margins around its child.
func (w *Window) Margined() bool {
	return tobool(C.uiWindowMargined(w.w))
}

// SetMargined controls whether the Window has margins around its
// child. The size of the margins are determined by the OS and its
// best practices.
func (w *Window) SetMargined(margined bool) {
	C.uiWindowSetMargined(w.w, frombool(margined))
}
<commit_msg>add get set content size function<commit_after>// 12 december 2015

package ui

import (
	"unsafe"
)

// #include "ui.h"
// extern int doOnClosing(uiWindow *, void *);
// static inline void realuiWindowOnClosing(uiWindow *w)
// {
// 	uiWindowOnClosing(w, doOnClosing, NULL);
// }
import "C"

// no need to lock this; only the GUI thread can access it
var windows = make(map[*C.uiWindow]*Window)

// Window is a Control that represents a top-level window.
// A Window contains one child Control that occupies the
// entirety of the window. Though a Window is a Control,
// a Window cannot be the child of another Control.
type Window struct {
	c *C.uiControl
	w *C.uiWindow

	child Control

	onClosing func(w *Window) bool
}

// NewWindow creates a new Window.
func NewWindow(title string, width int, height int, hasMenubar bool) *Window {
	w := new(Window)

	ctitle := C.CString(title)
	// TODO wait why did I make these ints and not intmax_ts?
	w.w = C.uiNewWindow(ctitle, C.int(width), C.int(height), frombool(hasMenubar))
	w.c = (*C.uiControl)(unsafe.Pointer(w.w))
	freestr(ctitle)

	C.realuiWindowOnClosing(w.w)
	windows[w.w] = w

	return w
}

// Destroy destroys the Window. If the Window has a child,
// Destroy calls Destroy on that as well.
func (w *Window) Destroy() {
	// first hide ourselves
	w.Hide()
	// get rid of the child
	if w.child != nil {
		c := w.child
		w.SetChild(nil)
		c.Destroy()
	}
	// unregister events
	delete(windows, w.w)
	// and finally destroy ourselves
	C.uiControlDestroy(w.c)
}

// LibuiControl returns the libui uiControl pointer that backs
// the Window. This is only used by package ui itself and should
// not be called by programs.
func (w *Window) LibuiControl() uintptr {
	return uintptr(unsafe.Pointer(w.c))
}

// Handle returns the OS-level handle associated with this Window.
// On Windows this is an HWND of a libui-internal class.
// On GTK+ this is a pointer to a GtkWindow.
// On OS X this is a pointer to a NSWindow.
func (w *Window) Handle() uintptr {
	return uintptr(C.uiControlHandle(w.c))
}

// Show shows the Window. It uses the OS conception of "presenting"
// the Window, whatever that may be on a given OS.
func (w *Window) Show() {
	C.uiControlShow(w.c)
}

// Hide hides the Window.
func (w *Window) Hide() {
	C.uiControlHide(w.c)
}

// Enable enables the Window.
func (w *Window) Enable() {
	C.uiControlEnable(w.c)
}

// Disable disables the Window.
func (w *Window) Disable() {
	C.uiControlDisable(w.c)
}

// Title returns the Window's title.
func (w *Window) Title() string {
	ctitle := C.uiWindowTitle(w.w)
	title := C.GoString(ctitle)
	C.uiFreeText(ctitle)
	return title
}

// SetTitle sets the Window's title to title.
func (w *Window) SetTitle(title string) {
	ctitle := C.CString(title)
	C.uiWindowSetTitle(w.w, ctitle)
	freestr(ctitle)
}

// OnClosing registers f to be run when the user clicks the Window's
// close button. Only one function can be registered at a time.
// If f returns true, the window is destroyed with the Destroy method.
// If f returns false, or if OnClosing is never called, the window is not
// destroyed and is kept visible.
func (w *Window) OnClosing(f func(*Window) bool) {
	w.onClosing = f
}

//export doOnClosing
func doOnClosing(ww *C.uiWindow, data unsafe.Pointer) C.int {
	w := windows[ww]
	if w.onClosing == nil {
		return 0
	}
	if w.onClosing(w) {
		w.Destroy()
	}
	return 0
}

// SetChild sets the Window's child to child. If child is nil, the Window
// will not have a child.
func (w *Window) SetChild(child Control) {
	w.child = child
	c := (*C.uiControl)(nil)
	if w.child != nil {
		c = touiControl(w.child.LibuiControl())
	}
	C.uiWindowSetChild(w.w, c)
}

// Margined returns whether the Window has margins around its child.
func (w *Window) Margined() bool {
	return tobool(C.uiWindowMargined(w.w))
}

// SetMargined controls whether the Window has margins around its
// child. The size of the margins are determined by the OS and its
// best practices.
func (w *Window) SetMargined(margined bool) {
	C.uiWindowSetMargined(w.w, frombool(margined))
}

// SetContentSize change the window content size.
func (w *Window) SetContentSize(width, height int) {
	C.uiWindowSetContentSize(w.w, C.int(width), C.int(height))
}

// GetContentSize change the window content size.
func (w *Window) GetContentSize() (width, height int) {
	cWidth, cHeight := C.int(0), C.int(0)
	C.uiWindowContentSize(w.w, &cWidth, &cHeight)
	return int(cWidth), int(cHeight)
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative Authors.

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

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

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

package testing

import (
	"context"
	"path"
	"reflect"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
	"k8s.io/apimachinery/pkg/api/resource"
	"k8s.io/apimachinery/pkg/runtime"
	clientgotesting "k8s.io/client-go/testing"
	"k8s.io/client-go/tools/cache"
	"knative.dev/pkg/controller"
	"knative.dev/pkg/kmeta"
	_ "knative.dev/pkg/system/testing" // Setup system.Namespace()
)

// TableRow holds a single row of our table test.
type TableRow struct {
	// Name is a descriptive name for this test suitable as a first argument to t.Run()
	Name string

	// Ctx is the context to pass to Reconcile. Defaults to context.Background()
	Ctx context.Context

	// Objects holds the state of the world at the onset of reconciliation.
	Objects []runtime.Object

	// Key is the parameter to reconciliation.
	// This has the form "namespace/name".
	Key string

	// WantErr holds whether we should expect the reconciliation to result in an error.
	WantErr bool

	// WantCreates holds the ordered list of Create calls we expect during reconciliation.
	WantCreates []runtime.Object

	// WantUpdates holds the ordered list of Update calls we expect during reconciliation.
	WantUpdates []clientgotesting.UpdateActionImpl

	// WantStatusUpdates holds the ordered list of Update calls, with `status` subresource set,
	// that we expect during reconciliation.
	WantStatusUpdates []clientgotesting.UpdateActionImpl

	// WantDeletes holds the ordered list of Delete calls we expect during reconciliation.
	WantDeletes []clientgotesting.DeleteActionImpl

	// WantDeleteCollections holds the ordered list of DeleteCollection calls we expect during reconciliation.
	WantDeleteCollections []clientgotesting.DeleteCollectionActionImpl

	// WantPatches holds the ordered list of Patch calls we expect during reconciliation.
	WantPatches []clientgotesting.PatchActionImpl

	// WantEvents holds the ordered list of events we expect during reconciliation.
	WantEvents []string

	// WantServiceReadyStats holds the ServiceReady stats we exepect during reconciliation.
	WantServiceReadyStats map[string]int

	// WithReactors is a set of functions that are installed as Reactors for the execution
	// of this row of the table-driven-test.
	WithReactors []clientgotesting.ReactionFunc

	// For cluster-scoped resources like ClusterIngress, it does not have to be
	// in the same namespace with its child resources.
	SkipNamespaceValidation bool
}

func objKey(o runtime.Object) string {
	on := o.(kmeta.Accessor)
	// namespace + name is not unique, and the tests don't populate k8s kind
	// information, so use GoLang's type name as part of the key.
	return path.Join(reflect.TypeOf(o).String(), on.GetNamespace(), on.GetName())
}

// Factory returns a Reconciler.Interface to perform reconciliation in table test,
// ActionRecorderList/EventList to capture k8s actions/events produced during reconciliation
// and FakeStatsReporter to capture stats.
type Factory func(*testing.T, *TableRow) (controller.Reconciler, ActionRecorderList, EventList, *FakeStatsReporter)

// Test executes the single table test.
func (r *TableRow) Test(t *testing.T, factory Factory) {
	t.Helper()
	c, recorderList, eventList, statsReporter := factory(t, r)

	// Set context to not be nil.
	ctx := r.Ctx
	if ctx == nil {
		ctx = context.Background()
	}

	// Run the Reconcile we're testing.
	if err := c.Reconcile(ctx, r.Key); (err != nil) != r.WantErr {
		t.Errorf("Reconcile() error = %v, WantErr %v", err, r.WantErr)
	}

	expectedNamespace, _, _ := cache.SplitMetaNamespaceKey(r.Key)

	actions, err := recorderList.ActionsByVerb()
	if err != nil {
		t.Errorf("Error capturing actions by verb: %q", err)
	}

	// Previous state is used to diff resource expected state for update requests that were missed.
	objPrevState := map[string]runtime.Object{}
	for _, o := range r.Objects {
		objPrevState[objKey(o)] = o
	}

	for i, want := range r.WantCreates {
		if i >= len(actions.Creates) {
			t.Errorf("Missing create: %#v", want)
			continue
		}
		got := actions.Creates[i]
		obj := got.GetObject()
		objPrevState[objKey(obj)] = obj

		if !r.SkipNamespaceValidation && got.GetNamespace() != expectedNamespace {
			t.Errorf("Unexpected action[%d]: %#v", i, got)
		}

		if diff := cmp.Diff(want, obj, ignoreLastTransitionTime, safeDeployDiff, cmpopts.EquateEmpty()); diff != "" {
			t.Errorf("Unexpected create (-want, +got): %s", diff)
		}
	}
	if got, want := len(actions.Creates), len(r.WantCreates); got > want {
		for _, extra := range actions.Creates[want:] {
			t.Errorf("Extra create: %#v", extra.GetObject())
		}
	}

	updates := filterUpdatesWithSubresource("", actions.Updates)
	for i, want := range r.WantUpdates {
		if i >= len(updates) {
			wo := want.GetObject()
			key := objKey(wo)
			oldObj, ok := objPrevState[key]
			if !ok {
				t.Errorf("Object %s was never created: want: %#v", key, wo)
				continue
			}
			t.Errorf("Missing update for %s (-want, +prevState): %s", key,
				cmp.Diff(wo, oldObj, ignoreLastTransitionTime, safeDeployDiff, cmpopts.EquateEmpty()))
			continue
		}

		if want.GetSubresource() != "" {
			t.Errorf("Expectation was invalid - it should not include a subresource: %#v", want)
		}

		got := updates[i].GetObject()

		// Update the object state.
		objPrevState[objKey(got)] = got

		if diff := cmp.Diff(want.GetObject(), got, ignoreLastTransitionTime, safeDeployDiff, cmpopts.EquateEmpty()); diff != "" {
			t.Errorf("Unexpected update (-want, +got): %s", diff)
		}
	}
	if got, want := len(updates), len(r.WantUpdates); got > want {
		for _, extra := range updates[want:] {
			t.Errorf("Extra update: %#v", extra.GetObject())
		}
	}

	// TODO(#2843): refactor.
	statusUpdates := filterUpdatesWithSubresource("status", actions.Updates)
	for i, want := range r.WantStatusUpdates {
		if i >= len(statusUpdates) {
			wo := want.GetObject()
			key := objKey(wo)
			oldObj, ok := objPrevState[key]
			if !ok {
				t.Errorf("Object %s was never created: want: %#v", key, wo)
				continue
			}
			t.Errorf("Missing status update for %s (-want, +prevState): %s", key,
				cmp.Diff(wo, oldObj, ignoreLastTransitionTime, safeDeployDiff, cmpopts.EquateEmpty()))
			continue
		}

		got := statusUpdates[i].GetObject()

		// Update the object state.
		objPrevState[objKey(got)] = got

		if diff := cmp.Diff(want.GetObject(), got, ignoreLastTransitionTime, safeDeployDiff, cmpopts.EquateEmpty()); diff != "" {
			t.Errorf("Unexpected status update (-want, +got): %s\nFull: %v", diff, got)
		}
	}
	if got, want := len(statusUpdates), len(r.WantStatusUpdates); got > want {
		for _, extra := range statusUpdates[want:] {
			wo := extra.GetObject()
			key := objKey(wo)
			oldObj, ok := objPrevState[key]
			if !ok {
				t.Errorf("Object %s was never created: want: %#v", key, wo)
				continue
			}
			t.Errorf("Extra status update for %s (-extra, +prevState): %s", key,
				cmp.Diff(wo, oldObj, ignoreLastTransitionTime, safeDeployDiff, cmpopts.EquateEmpty()))
		}
	}

	if len(statusUpdates)+len(updates) != len(actions.Updates) {
		var unexpected []runtime.Object

		for _, update := range actions.Updates {
			if update.GetSubresource() != "status" && update.GetSubresource() != "" {
				unexpected = append(unexpected, update.GetObject())
			}
		}

		t.Errorf("Unexpected subresource updates occurred %#v", unexpected)
	}

	for i, want := range r.WantDeletes {
		if i >= len(actions.Deletes) {
			t.Errorf("Missing delete: %#v", want)
			continue
		}
		got := actions.Deletes[i]
		if got.GetName() != want.GetName() {
			t.Errorf("Unexpected delete[%d]: %#v", i, got)
		}
		if !r.SkipNamespaceValidation && got.GetNamespace() != expectedNamespace {
			t.Errorf("Unexpected delete[%d]: %#v", i, got)
		}
	}
	if got, want := len(actions.Deletes), len(r.WantDeletes); got > want {
		for _, extra := range actions.Deletes[want:] {
			t.Errorf("Extra delete: %s/%s", extra.GetNamespace(), extra.GetName())
		}
	}

	for i, want := range r.WantDeleteCollections {
		if i >= len(actions.DeleteCollections) {
			t.Errorf("Missing delete-collection: %#v", want)
			continue
		}
		got := actions.DeleteCollections[i]
		if got, want := got.GetListRestrictions().Labels, want.GetListRestrictions().Labels; (got != nil) != (want != nil) || got.String() != want.String() {
			t.Errorf("Unexpected delete-collection[%d].Labels = %v, wanted %v", i, got, want)
		}
		if got, want := got.GetListRestrictions().Fields, want.GetListRestrictions().Fields; (got != nil) != (want != nil) || got.String() != want.String() {
			t.Errorf("Unexpected delete-collection[%d].Fields = %v, wanted %v", i, got, want)
		}
		if !r.SkipNamespaceValidation && got.GetNamespace() != expectedNamespace {
			t.Errorf("Unexpected delete-collection[%d]: %#v, wanted %s", i, got, expectedNamespace)
		}
	}
	if got, want := len(actions.DeleteCollections), len(r.WantDeleteCollections); got > want {
		for _, extra := range actions.DeleteCollections[want:] {
			t.Errorf("Extra delete-collection: %#v", extra)
		}
	}

	for i, want := range r.WantPatches {
		if i >= len(actions.Patches) {
			t.Errorf("Missing patch: %#v; raw: %s", want, string(want.GetPatch()))
			continue
		}

		got := actions.Patches[i]
		if got.GetName() != want.GetName() {
			t.Errorf("Unexpected patch[%d]: %#v", i, got)
		}
		if !r.SkipNamespaceValidation && got.GetNamespace() != expectedNamespace {
			t.Errorf("Unexpected patch[%d]: %#v", i, got)
		}
		if diff := cmp.Diff(string(want.GetPatch()), string(got.GetPatch())); diff != "" {
			t.Errorf("Unexpected patch(-want, +got): %s", diff)
		}
	}
	if got, want := len(actions.Patches), len(r.WantPatches); got > want {
		for _, extra := range actions.Patches[want:] {
			t.Errorf("Extra patch: %#v; raw: %s", extra, string(extra.GetPatch()))
		}
	}

	gotEvents := eventList.Events()
	for i, want := range r.WantEvents {
		if i >= len(gotEvents) {
			t.Errorf("Missing event: %s", want)
			continue
		}

		if diff := cmp.Diff(want, gotEvents[i]); diff != "" {
			t.Errorf("unexpected event(-want, +got): %s", diff)
		}
	}
	if got, want := len(gotEvents), len(r.WantEvents); got > want {
		for _, extra := range gotEvents[want:] {
			t.Errorf("Extra event: %s", extra)
		}
	}

	gotStats := statsReporter.GetServiceReadyStats()
	if diff := cmp.Diff(r.WantServiceReadyStats, gotStats); diff != "" {
		t.Errorf("Unexpected service ready stats (-want, +got): %s", diff)
	}
}

func filterUpdatesWithSubresource(
	subresource string,
	actions []clientgotesting.UpdateAction) (result []clientgotesting.UpdateAction) {
	for _, action := range actions {
		if action.GetSubresource() == subresource {
			result = append(result, action)
		}
	}
	return
}

// TableTest represents a list of TableRow tests instances.
type TableTest []TableRow

// Test executes the whole suite of the table tests.
func (tt TableTest) Test(t *testing.T, factory Factory) {
	t.Helper()
	for _, test := range tt {
		// Record the original objects in table.
		originObjects := []runtime.Object{}
		for _, obj := range test.Objects {
			originObjects = append(originObjects, obj.DeepCopyObject())
		}
		t.Run(test.Name, func(t *testing.T) {
			t.Helper()
			test.Test(t, factory)
		})
		// Validate cached objects do not get soiled after controller loops
		if diff := cmp.Diff(originObjects, test.Objects, safeDeployDiff, cmpopts.EquateEmpty()); diff != "" {
			t.Errorf("Unexpected objects in test %s (-want, +got): %v", test.Name, diff)
		}
	}
}

var (
	ignoreLastTransitionTime = cmp.FilterPath(func(p cmp.Path) bool {
		return strings.HasSuffix(p.String(), "LastTransitionTime.Inner.Time")
	}, cmp.Ignore())

	safeDeployDiff = cmpopts.IgnoreUnexported(resource.Quantity{})
)
<commit_msg>Improve the loggig situation in table tests (#624)<commit_after>/*
Copyright 2019 The Knative Authors.

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

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

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

package testing

import (
	"context"
	"path"
	"reflect"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
	"go.uber.org/zap"

	"k8s.io/apimachinery/pkg/api/resource"
	"k8s.io/apimachinery/pkg/runtime"
	clientgotesting "k8s.io/client-go/testing"
	"k8s.io/client-go/tools/cache"

	"knative.dev/pkg/controller"
	"knative.dev/pkg/kmeta"
	"knative.dev/pkg/logging"
	"knative.dev/pkg/logging/logkey"
	_ "knative.dev/pkg/system/testing" // Setup system.Namespace()
)

// TableRow holds a single row of our table test.
type TableRow struct {
	// Name is a descriptive name for this test suitable as a first argument to t.Run()
	Name string

	// Ctx is the context to pass to Reconcile. Defaults to context.Background()
	Ctx context.Context

	// Objects holds the state of the world at the onset of reconciliation.
	Objects []runtime.Object

	// Key is the parameter to reconciliation.
	// This has the form "namespace/name".
	Key string

	// WantErr holds whether we should expect the reconciliation to result in an error.
	WantErr bool

	// WantCreates holds the ordered list of Create calls we expect during reconciliation.
	WantCreates []runtime.Object

	// WantUpdates holds the ordered list of Update calls we expect during reconciliation.
	WantUpdates []clientgotesting.UpdateActionImpl

	// WantStatusUpdates holds the ordered list of Update calls, with `status` subresource set,
	// that we expect during reconciliation.
	WantStatusUpdates []clientgotesting.UpdateActionImpl

	// WantDeletes holds the ordered list of Delete calls we expect during reconciliation.
	WantDeletes []clientgotesting.DeleteActionImpl

	// WantDeleteCollections holds the ordered list of DeleteCollection calls we expect during reconciliation.
	WantDeleteCollections []clientgotesting.DeleteCollectionActionImpl

	// WantPatches holds the ordered list of Patch calls we expect during reconciliation.
	WantPatches []clientgotesting.PatchActionImpl

	// WantEvents holds the ordered list of events we expect during reconciliation.
	WantEvents []string

	// WantServiceReadyStats holds the ServiceReady stats we exepect during reconciliation.
	WantServiceReadyStats map[string]int

	// WithReactors is a set of functions that are installed as Reactors for the execution
	// of this row of the table-driven-test.
	WithReactors []clientgotesting.ReactionFunc

	// For cluster-scoped resources like ClusterIngress, it does not have to be
	// in the same namespace with its child resources.
	SkipNamespaceValidation bool
}

func objKey(o runtime.Object) string {
	on := o.(kmeta.Accessor)
	// namespace + name is not unique, and the tests don't populate k8s kind
	// information, so use GoLang's type name as part of the key.
	return path.Join(reflect.TypeOf(o).String(), on.GetNamespace(), on.GetName())
}

// Factory returns a Reconciler.Interface to perform reconciliation in table test,
// ActionRecorderList/EventList to capture k8s actions/events produced during reconciliation
// and FakeStatsReporter to capture stats.
type Factory func(*testing.T, *TableRow) (controller.Reconciler, ActionRecorderList, EventList, *FakeStatsReporter)

// Test executes the single table test.
func (r *TableRow) Test(t *testing.T, factory Factory) {
	t.Helper()
	c, recorderList, eventList, statsReporter := factory(t, r)

	// Set context to not be nil.
	ctx := r.Ctx
	if ctx == nil {
		ctx = context.Background()
	} else {
		// If we have logger setup on the context, decorate it with the key, so that the logs
		// look like in prod.
		l := logging.FromContext(ctx)
		l = l.With(zap.String(logkey.Key, r.Key))
		ctx = logging.WithLogger(ctx, l)
	}

	// Run the Reconcile we're testing.
	if err := c.Reconcile(ctx, r.Key); (err != nil) != r.WantErr {
		t.Errorf("Reconcile() error = %v, WantErr %v", err, r.WantErr)
	}

	expectedNamespace, _, _ := cache.SplitMetaNamespaceKey(r.Key)

	actions, err := recorderList.ActionsByVerb()
	if err != nil {
		t.Errorf("Error capturing actions by verb: %q", err)
	}

	// Previous state is used to diff resource expected state for update requests that were missed.
	objPrevState := make(map[string]runtime.Object, len(r.Objects))
	for _, o := range r.Objects {
		objPrevState[objKey(o)] = o
	}

	for i, want := range r.WantCreates {
		if i >= len(actions.Creates) {
			t.Errorf("Missing create: %#v", want)
			continue
		}
		got := actions.Creates[i]
		obj := got.GetObject()
		objPrevState[objKey(obj)] = obj

		if !r.SkipNamespaceValidation && got.GetNamespace() != expectedNamespace {
			t.Errorf("Unexpected action[%d]: %#v", i, got)
		}

		if diff := cmp.Diff(want, obj, ignoreLastTransitionTime, safeDeployDiff, cmpopts.EquateEmpty()); diff != "" {
			t.Errorf("Unexpected create (-want, +got): %s", diff)
		}
	}
	if got, want := len(actions.Creates), len(r.WantCreates); got > want {
		for _, extra := range actions.Creates[want:] {
			t.Errorf("Extra create: %#v", extra.GetObject())
		}
	}

	updates := filterUpdatesWithSubresource("", actions.Updates)
	for i, want := range r.WantUpdates {
		if i >= len(updates) {
			wo := want.GetObject()
			key := objKey(wo)
			oldObj, ok := objPrevState[key]
			if !ok {
				t.Errorf("Object %s was never created: want: %#v", key, wo)
				continue
			}
			t.Errorf("Missing update for %s (-want, +prevState): %s", key,
				cmp.Diff(wo, oldObj, ignoreLastTransitionTime, safeDeployDiff, cmpopts.EquateEmpty()))
			continue
		}

		if want.GetSubresource() != "" {
			t.Errorf("Expectation was invalid - it should not include a subresource: %#v", want)
		}

		got := updates[i].GetObject()

		// Update the object state.
		objPrevState[objKey(got)] = got

		if diff := cmp.Diff(want.GetObject(), got, ignoreLastTransitionTime, safeDeployDiff, cmpopts.EquateEmpty()); diff != "" {
			t.Errorf("Unexpected update (-want, +got): %s", diff)
		}
	}
	if got, want := len(updates), len(r.WantUpdates); got > want {
		for _, extra := range updates[want:] {
			t.Errorf("Extra update: %#v", extra.GetObject())
		}
	}

	// TODO(#2843): refactor.
	statusUpdates := filterUpdatesWithSubresource("status", actions.Updates)
	for i, want := range r.WantStatusUpdates {
		if i >= len(statusUpdates) {
			wo := want.GetObject()
			key := objKey(wo)
			oldObj, ok := objPrevState[key]
			if !ok {
				t.Errorf("Object %s was never created: want: %#v", key, wo)
				continue
			}
			t.Errorf("Missing status update for %s (-want, +prevState): %s", key,
				cmp.Diff(wo, oldObj, ignoreLastTransitionTime, safeDeployDiff, cmpopts.EquateEmpty()))
			continue
		}

		got := statusUpdates[i].GetObject()

		// Update the object state.
		objPrevState[objKey(got)] = got

		if diff := cmp.Diff(want.GetObject(), got, ignoreLastTransitionTime, safeDeployDiff, cmpopts.EquateEmpty()); diff != "" {
			t.Errorf("Unexpected status update (-want, +got): %s\nFull: %v", diff, got)
		}
	}
	if got, want := len(statusUpdates), len(r.WantStatusUpdates); got > want {
		for _, extra := range statusUpdates[want:] {
			wo := extra.GetObject()
			key := objKey(wo)
			oldObj, ok := objPrevState[key]
			if !ok {
				t.Errorf("Object %s was never created: want: %#v", key, wo)
				continue
			}
			t.Errorf("Extra status update for %s (-extra, +prevState): %s", key,
				cmp.Diff(wo, oldObj, ignoreLastTransitionTime, safeDeployDiff, cmpopts.EquateEmpty()))
		}
	}

	if len(statusUpdates)+len(updates) != len(actions.Updates) {
		var unexpected []runtime.Object

		for _, update := range actions.Updates {
			if update.GetSubresource() != "status" && update.GetSubresource() != "" {
				unexpected = append(unexpected, update.GetObject())
			}
		}

		t.Errorf("Unexpected subresource updates occurred %#v", unexpected)
	}

	for i, want := range r.WantDeletes {
		if i >= len(actions.Deletes) {
			t.Errorf("Missing delete: %#v", want)
			continue
		}
		got := actions.Deletes[i]
		if got.GetName() != want.GetName() {
			t.Errorf("Unexpected delete[%d]: %#v", i, got)
		}
		if !r.SkipNamespaceValidation && got.GetNamespace() != expectedNamespace {
			t.Errorf("Unexpected delete[%d]: %#v", i, got)
		}
	}
	if got, want := len(actions.Deletes), len(r.WantDeletes); got > want {
		for _, extra := range actions.Deletes[want:] {
			t.Errorf("Extra delete: %s/%s", extra.GetNamespace(), extra.GetName())
		}
	}

	for i, want := range r.WantDeleteCollections {
		if i >= len(actions.DeleteCollections) {
			t.Errorf("Missing delete-collection: %#v", want)
			continue
		}
		got := actions.DeleteCollections[i]
		if got, want := got.GetListRestrictions().Labels, want.GetListRestrictions().Labels; (got != nil) != (want != nil) || got.String() != want.String() {
			t.Errorf("Unexpected delete-collection[%d].Labels = %v, wanted %v", i, got, want)
		}
		if got, want := got.GetListRestrictions().Fields, want.GetListRestrictions().Fields; (got != nil) != (want != nil) || got.String() != want.String() {
			t.Errorf("Unexpected delete-collection[%d].Fields = %v, wanted %v", i, got, want)
		}
		if !r.SkipNamespaceValidation && got.GetNamespace() != expectedNamespace {
			t.Errorf("Unexpected delete-collection[%d]: %#v, wanted %s", i, got, expectedNamespace)
		}
	}
	if got, want := len(actions.DeleteCollections), len(r.WantDeleteCollections); got > want {
		for _, extra := range actions.DeleteCollections[want:] {
			t.Errorf("Extra delete-collection: %#v", extra)
		}
	}

	for i, want := range r.WantPatches {
		if i >= len(actions.Patches) {
			t.Errorf("Missing patch: %#v; raw: %s", want, string(want.GetPatch()))
			continue
		}

		got := actions.Patches[i]
		if got.GetName() != want.GetName() {
			t.Errorf("Unexpected patch[%d]: %#v", i, got)
		}
		if !r.SkipNamespaceValidation && got.GetNamespace() != expectedNamespace {
			t.Errorf("Unexpected patch[%d]: %#v", i, got)
		}
		if diff := cmp.Diff(string(want.GetPatch()), string(got.GetPatch())); diff != "" {
			t.Errorf("Unexpected patch(-want, +got): %s", diff)
		}
	}
	if got, want := len(actions.Patches), len(r.WantPatches); got > want {
		for _, extra := range actions.Patches[want:] {
			t.Errorf("Extra patch: %#v; raw: %s", extra, string(extra.GetPatch()))
		}
	}

	gotEvents := eventList.Events()
	for i, want := range r.WantEvents {
		if i >= len(gotEvents) {
			t.Errorf("Missing event: %s", want)
			continue
		}

		if diff := cmp.Diff(want, gotEvents[i]); diff != "" {
			t.Errorf("unexpected event(-want, +got): %s", diff)
		}
	}
	if got, want := len(gotEvents), len(r.WantEvents); got > want {
		for _, extra := range gotEvents[want:] {
			t.Errorf("Extra event: %s", extra)
		}
	}

	gotStats := statsReporter.GetServiceReadyStats()
	if diff := cmp.Diff(r.WantServiceReadyStats, gotStats); diff != "" {
		t.Errorf("Unexpected service ready stats (-want, +got): %s", diff)
	}
}

func filterUpdatesWithSubresource(
	subresource string,
	actions []clientgotesting.UpdateAction) (result []clientgotesting.UpdateAction) {
	for _, action := range actions {
		if action.GetSubresource() == subresource {
			result = append(result, action)
		}
	}
	return
}

// TableTest represents a list of TableRow tests instances.
type TableTest []TableRow

// Test executes the whole suite of the table tests.
func (tt TableTest) Test(t *testing.T, factory Factory) {
	t.Helper()
	for _, test := range tt {
		// Record the original objects in table.
		originObjects := make([]runtime.Object, 0, len(test.Objects))
		for _, obj := range test.Objects {
			originObjects = append(originObjects, obj.DeepCopyObject())
		}
		t.Run(test.Name, func(t *testing.T) {
			t.Helper()
			test.Test(t, factory)
		})
		// Validate cached objects do not get soiled after controller loops
		if diff := cmp.Diff(originObjects, test.Objects, safeDeployDiff, cmpopts.EquateEmpty()); diff != "" {
			t.Errorf("Unexpected objects in test %s (-want, +got): %v", test.Name, diff)
		}
	}
}

var (
	ignoreLastTransitionTime = cmp.FilterPath(func(p cmp.Path) bool {
		return strings.HasSuffix(p.String(), "LastTransitionTime.Inner.Time")
	}, cmp.Ignore())

	safeDeployDiff = cmpopts.IgnoreUnexported(resource.Quantity{})
)
<|endoftext|>


<commit_before>package registry

import (
	"crypto/tls"
	"errors"
	"fmt"
	"net"
	"net/http"
	"runtime"
	"sync"
	"time"

	consul "github.com/hashicorp/consul/api"
	hash "github.com/mitchellh/hashstructure"
)

type consulRegistry struct {
	Address string
	Client  *consul.Client
	Options Options

	sync.Mutex
	register map[string]uint64
}

func newTransport(config *tls.Config) *http.Transport {
	if config == nil {
		config = &tls.Config{
			InsecureSkipVerify: true,
		}
	}

	t := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig:     config,
	}
	runtime.SetFinalizer(&t, func(tr **http.Transport) {
		(*tr).CloseIdleConnections()
	})
	return t
}

func newConsulRegistry(opts ...Option) Registry {
	var options Options
	for _, o := range opts {
		o(&options)
	}

	// use default config
	config := consul.DefaultConfig()
	if options.Context != nil {
		// Use the consul config passed in the options, if available
		if c, ok := options.Context.Value("consul_config").(*consul.Config); ok {
			config = c
		}
	}

	// set timeout
	if options.Timeout > 0 {
		config.HttpClient.Timeout = options.Timeout
	}

	// check if there are any addrs
	if len(options.Addrs) > 0 {
		addr, port, err := net.SplitHostPort(options.Addrs[0])
		if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" {
			port = "8500"
			addr = options.Addrs[0]
			config.Address = fmt.Sprintf("%s:%s", addr, port)
		} else if err == nil {
			config.Address = fmt.Sprintf("%s:%s", addr, port)
		}
	}

	// requires secure connection?
	if options.Secure || options.TLSConfig != nil {
		config.Scheme = "https"
		// We're going to support InsecureSkipVerify
		config.HttpClient.Transport = newTransport(options.TLSConfig)
	}

	// create the client
	client, _ := consul.NewClient(config)

	cr := &consulRegistry{
		Address:  config.Address,
		Client:   client,
		Options:  options,
		register: make(map[string]uint64),
	}

	return cr
}

func (c *consulRegistry) Deregister(s *Service) error {
	if len(s.Nodes) == 0 {
		return errors.New("Require at least one node")
	}

	// delete our hash of the service
	c.Lock()
	delete(c.register, s.Name)
	c.Unlock()

	node := s.Nodes[0]
	return c.Client.Agent().ServiceDeregister(node.Id)
}

func (c *consulRegistry) Register(s *Service, opts ...RegisterOption) error {
	if len(s.Nodes) == 0 {
		return errors.New("Require at least one node")
	}

	var options RegisterOptions
	for _, o := range opts {
		o(&options)
	}

	// create hash of service; uint64
	h, err := hash.Hash(s, nil)
	if err != nil {
		return err
	}

	// use first node
	node := s.Nodes[0]

	// get existing hash
	c.Lock()
	v, ok := c.register[s.Name]
	c.Unlock()

	// if it's already registered and matches then just pass the check
	if ok && v == h {
		// if the err is nil we're all good, bail out
		// if not, we don't know what the state is, so full re-register
		if err := c.Client.Agent().PassTTL("service:"+node.Id, ""); err == nil {
			return nil
		}
	}

	// encode the tags
	tags := encodeMetadata(node.Metadata)
	tags = append(tags, encodeEndpoints(s.Endpoints)...)
	tags = append(tags, encodeVersion(s.Version)...)

	var check *consul.AgentServiceCheck

	// if the TTL is greater than 0 create an associated check
	if options.TTL > time.Duration(0) {
		check = &consul.AgentServiceCheck{
			TTL: fmt.Sprintf("%v", options.TTL),
		}
	}

	// register the service
	if err := c.Client.Agent().ServiceRegister(&consul.AgentServiceRegistration{
		ID:      node.Id,
		Name:    s.Name,
		Tags:    tags,
		Port:    node.Port,
		Address: node.Address,
		Check:   check,
	}); err != nil {
		return err
	}

	// save our hash of the service
	c.Lock()
	c.register[s.Name] = h
	c.Unlock()

	// if the TTL is 0 we don't mess with the checks
	if options.TTL == time.Duration(0) {
		return nil
	}

	// pass the healthcheck
	return c.Client.Agent().PassTTL("service:"+node.Id, "")
}

func (c *consulRegistry) GetService(name string) ([]*Service, error) {
	rsp, _, err := c.Client.Health().Service(name, "", false, nil)
	if err != nil {
		return nil, err
	}

	serviceMap := map[string]*Service{}

	for _, s := range rsp {
		if s.Service.Service != name {
			continue
		}

		// version is now a tag
		version, found := decodeVersion(s.Service.Tags)
		// service ID is now the node id
		id := s.Service.ID
		// key is always the version
		key := version
		// address is service address
		address := s.Service.Address

		// if we can't get the version we bail
		// use old the old ways
		if !found {
			continue
		}

		svc, ok := serviceMap[key]
		if !ok {
			svc = &Service{
				Endpoints: decodeEndpoints(s.Service.Tags),
				Name:      s.Service.Service,
				Version:   version,
			}
			serviceMap[key] = svc
		}

		var del bool
		for _, check := range s.Checks {
			// delete the node if the status is critical
			if check.Status == "critical" {
				del = true
				break
			}
		}

		// if delete then skip the node
		if del {
			continue
		}

		svc.Nodes = append(svc.Nodes, &Node{
			Id:       id,
			Address:  address,
			Port:     s.Service.Port,
			Metadata: decodeMetadata(s.Service.Tags),
		})
	}

	var services []*Service
	for _, service := range serviceMap {
		services = append(services, service)
	}
	return services, nil
}

func (c *consulRegistry) ListServices() ([]*Service, error) {
	rsp, _, err := c.Client.Catalog().Services(nil)
	if err != nil {
		return nil, err
	}

	var services []*Service

	for service := range rsp {
		services = append(services, &Service{Name: service})
	}

	return services, nil
}

func (c *consulRegistry) Watch() (Watcher, error) {
	return newConsulWatcher(c)
}

func (c *consulRegistry) String() string {
	return "consul"
}
<commit_msg>Make use of consul 0.7 deregister field. Now auto reaps dead services<commit_after>package registry

import (
	"crypto/tls"
	"errors"
	"fmt"
	"net"
	"net/http"
	"runtime"
	"sync"
	"time"

	consul "github.com/hashicorp/consul/api"
	hash "github.com/mitchellh/hashstructure"
)

type consulRegistry struct {
	Address string
	Client  *consul.Client
	Options Options

	sync.Mutex
	register map[string]uint64
}

func newTransport(config *tls.Config) *http.Transport {
	if config == nil {
		config = &tls.Config{
			InsecureSkipVerify: true,
		}
	}

	t := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig:     config,
	}
	runtime.SetFinalizer(&t, func(tr **http.Transport) {
		(*tr).CloseIdleConnections()
	})
	return t
}

func newConsulRegistry(opts ...Option) Registry {
	var options Options
	for _, o := range opts {
		o(&options)
	}

	// use default config
	config := consul.DefaultConfig()
	if options.Context != nil {
		// Use the consul config passed in the options, if available
		if c, ok := options.Context.Value("consul_config").(*consul.Config); ok {
			config = c
		}
	}

	// set timeout
	if options.Timeout > 0 {
		config.HttpClient.Timeout = options.Timeout
	}

	// check if there are any addrs
	if len(options.Addrs) > 0 {
		addr, port, err := net.SplitHostPort(options.Addrs[0])
		if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" {
			port = "8500"
			addr = options.Addrs[0]
			config.Address = fmt.Sprintf("%s:%s", addr, port)
		} else if err == nil {
			config.Address = fmt.Sprintf("%s:%s", addr, port)
		}
	}

	// requires secure connection?
	if options.Secure || options.TLSConfig != nil {
		config.Scheme = "https"
		// We're going to support InsecureSkipVerify
		config.HttpClient.Transport = newTransport(options.TLSConfig)
	}

	// create the client
	client, _ := consul.NewClient(config)

	cr := &consulRegistry{
		Address:  config.Address,
		Client:   client,
		Options:  options,
		register: make(map[string]uint64),
	}

	return cr
}

func (c *consulRegistry) Deregister(s *Service) error {
	if len(s.Nodes) == 0 {
		return errors.New("Require at least one node")
	}

	// delete our hash of the service
	c.Lock()
	delete(c.register, s.Name)
	c.Unlock()

	node := s.Nodes[0]
	return c.Client.Agent().ServiceDeregister(node.Id)
}

func (c *consulRegistry) Register(s *Service, opts ...RegisterOption) error {
	if len(s.Nodes) == 0 {
		return errors.New("Require at least one node")
	}

	var options RegisterOptions
	for _, o := range opts {
		o(&options)
	}

	// create hash of service; uint64
	h, err := hash.Hash(s, nil)
	if err != nil {
		return err
	}

	// use first node
	node := s.Nodes[0]

	// get existing hash
	c.Lock()
	v, ok := c.register[s.Name]
	c.Unlock()

	// if it's already registered and matches then just pass the check
	if ok && v == h {
		// if the err is nil we're all good, bail out
		// if not, we don't know what the state is, so full re-register
		if err := c.Client.Agent().PassTTL("service:"+node.Id, ""); err == nil {
			return nil
		}
	}

	// encode the tags
	tags := encodeMetadata(node.Metadata)
	tags = append(tags, encodeEndpoints(s.Endpoints)...)
	tags = append(tags, encodeVersion(s.Version)...)

	var check *consul.AgentServiceCheck

	// if the TTL is greater than 0 create an associated check
	if options.TTL > time.Duration(0) {
		// splay slightly for the watcher?
		splay := time.Second * 5
		deregTTL := options.TTL + splay
		// consul has a minimum timeout on deregistration of 1 minute.
		if options.TTL < time.Minute {
			deregTTL = time.Minute + splay
		}

		check = &consul.AgentServiceCheck{
			TTL: fmt.Sprintf("%v", options.TTL),
			DeregisterCriticalServiceAfter: fmt.Sprintf("%v", deregTTL),
		}
	}

	// register the service
	if err := c.Client.Agent().ServiceRegister(&consul.AgentServiceRegistration{
		ID:      node.Id,
		Name:    s.Name,
		Tags:    tags,
		Port:    node.Port,
		Address: node.Address,
		Check:   check,
	}); err != nil {
		return err
	}

	// save our hash of the service
	c.Lock()
	c.register[s.Name] = h
	c.Unlock()

	// if the TTL is 0 we don't mess with the checks
	if options.TTL == time.Duration(0) {
		return nil
	}

	// pass the healthcheck
	return c.Client.Agent().PassTTL("service:"+node.Id, "")
}

func (c *consulRegistry) GetService(name string) ([]*Service, error) {
	rsp, _, err := c.Client.Health().Service(name, "", false, nil)
	if err != nil {
		return nil, err
	}

	serviceMap := map[string]*Service{}

	for _, s := range rsp {
		if s.Service.Service != name {
			continue
		}

		// version is now a tag
		version, found := decodeVersion(s.Service.Tags)
		// service ID is now the node id
		id := s.Service.ID
		// key is always the version
		key := version
		// address is service address
		address := s.Service.Address

		// if we can't get the version we bail
		// use old the old ways
		if !found {
			continue
		}

		svc, ok := serviceMap[key]
		if !ok {
			svc = &Service{
				Endpoints: decodeEndpoints(s.Service.Tags),
				Name:      s.Service.Service,
				Version:   version,
			}
			serviceMap[key] = svc
		}

		var del bool
		for _, check := range s.Checks {
			// delete the node if the status is critical
			if check.Status == "critical" {
				del = true
				break
			}
		}

		// if delete then skip the node
		if del {
			continue
		}

		svc.Nodes = append(svc.Nodes, &Node{
			Id:       id,
			Address:  address,
			Port:     s.Service.Port,
			Metadata: decodeMetadata(s.Service.Tags),
		})
	}

	var services []*Service
	for _, service := range serviceMap {
		services = append(services, service)
	}
	return services, nil
}

func (c *consulRegistry) ListServices() ([]*Service, error) {
	rsp, _, err := c.Client.Catalog().Services(nil)
	if err != nil {
		return nil, err
	}

	var services []*Service

	for service := range rsp {
		services = append(services, &Service{Name: service})
	}

	return services, nil
}

func (c *consulRegistry) Watch() (Watcher, error) {
	return newConsulWatcher(c)
}

func (c *consulRegistry) String() string {
	return "consul"
}
<|endoftext|>


<commit_before>package index

import (
	"math/rand"
	"restic"
	"restic/checker"
	"restic/repository"
	"restic/test"
	"testing"
	"time"
)

var (
	snapshotTime = time.Unix(1470492820, 207401672)
	depth        = 3
)

func createFilledRepo(t testing.TB, snapshots int, dup float32) (restic.Repository, func()) {
	repo, cleanup := repository.TestRepository(t)

	for i := 0; i < 3; i++ {
		restic.TestCreateSnapshot(t, repo, snapshotTime.Add(time.Duration(i)*time.Second), depth, dup)
	}

	return repo, cleanup
}

func validateIndex(t testing.TB, repo restic.Repository, idx *Index) {
	for id := range repo.List(restic.DataFile, nil) {
		if _, ok := idx.Packs[id]; !ok {
			t.Errorf("pack %v missing from index", id.Str())
		}
	}
}

func TestIndexNew(t *testing.T) {
	repo, cleanup := createFilledRepo(t, 3, 0)
	defer cleanup()

	idx, err := New(repo, nil)
	if err != nil {
		t.Fatalf("New() returned error %v", err)
	}

	if idx == nil {
		t.Fatalf("New() returned nil index")
	}

	validateIndex(t, repo, idx)
}

func TestIndexLoad(t *testing.T) {
	repo, cleanup := createFilledRepo(t, 3, 0)
	defer cleanup()

	loadIdx, err := Load(repo, nil)
	if err != nil {
		t.Fatalf("Load() returned error %v", err)
	}

	if loadIdx == nil {
		t.Fatalf("Load() returned nil index")
	}

	validateIndex(t, repo, loadIdx)

	newIdx, err := New(repo, nil)
	if err != nil {
		t.Fatalf("New() returned error %v", err)
	}

	if len(loadIdx.Packs) != len(newIdx.Packs) {
		t.Errorf("number of packs does not match: want %v, got %v",
			len(loadIdx.Packs), len(newIdx.Packs))
	}

	validateIndex(t, repo, newIdx)

	for packID, packNew := range newIdx.Packs {
		packLoad, ok := loadIdx.Packs[packID]

		if !ok {
			t.Errorf("loaded index does not list pack %v", packID.Str())
			continue
		}

		if len(packNew.Entries) != len(packLoad.Entries) {
			t.Errorf("  number of entries in pack %v does not match: %d != %d\n  %v\n  %v",
				packID.Str(), len(packNew.Entries), len(packLoad.Entries),
				packNew.Entries, packLoad.Entries)
			continue
		}

		for _, entryNew := range packNew.Entries {
			found := false
			for _, entryLoad := range packLoad.Entries {
				if !entryLoad.ID.Equal(entryNew.ID) {
					continue
				}

				if entryLoad.Type != entryNew.Type {
					continue
				}

				if entryLoad.Offset != entryNew.Offset {
					continue
				}

				if entryLoad.Length != entryNew.Length {
					continue
				}

				found = true
				break
			}

			if !found {
				t.Errorf("blob not found in loaded index: %v", entryNew)
			}
		}
	}
}

func BenchmarkIndexNew(b *testing.B) {
	repo, cleanup := createFilledRepo(b, 3, 0)
	defer cleanup()

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		idx, err := New(repo, nil)

		if err != nil {
			b.Fatalf("New() returned error %v", err)
		}

		if idx == nil {
			b.Fatalf("New() returned nil index")
		}
		b.Logf("idx %v packs", len(idx.Packs))
	}
}

func BenchmarkIndexSave(b *testing.B) {
	repo, cleanup := repository.TestRepository(b)
	defer cleanup()

	idx, err := New(repo, nil)
	test.OK(b, err)

	for i := 0; i < 8000; i++ {
		entries := make([]restic.Blob, 0, 200)
		for j := 0; j < cap(entries); j++ {
			entries = append(entries, restic.Blob{
				ID:     restic.NewRandomID(),
				Length: 1000,
				Offset: 5,
				Type:   restic.DataBlob,
			})
		}

		idx.AddPack(restic.NewRandomID(), 10000, entries)
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		id, err := idx.Save(repo, nil)
		if err != nil {
			b.Fatalf("New() returned error %v", err)
		}

		b.Logf("saved as %v", id.Str())
	}
}

func TestIndexDuplicateBlobs(t *testing.T) {
	repo, cleanup := createFilledRepo(t, 3, 0.01)
	defer cleanup()

	idx, err := New(repo, nil)
	if err != nil {
		t.Fatal(err)
	}

	dups := idx.DuplicateBlobs()
	if len(dups) == 0 {
		t.Errorf("no duplicate blobs found")
	}
	t.Logf("%d packs, %d duplicate blobs", len(idx.Packs), len(dups))

	packs := idx.PacksForBlobs(dups)
	if len(packs) == 0 {
		t.Errorf("no packs with duplicate blobs found")
	}
	t.Logf("%d packs with duplicate blobs", len(packs))
}

func loadIndex(t testing.TB, repo restic.Repository) *Index {
	idx, err := Load(repo, nil)
	if err != nil {
		t.Fatalf("Load() returned error %v", err)
	}

	return idx
}

func TestSave(t *testing.T) {
	repo, cleanup := createFilledRepo(t, 3, 0)
	defer cleanup()

	idx := loadIndex(t, repo)

	packs := make(map[restic.ID][]restic.Blob)
	for id := range idx.Packs {
		if rand.Float32() < 0.5 {
			packs[id] = idx.Packs[id].Entries
		}
	}

	t.Logf("save %d/%d packs in a new index\n", len(packs), len(idx.Packs))

	id, err := Save(repo, packs, idx.IndexIDs.List())
	if err != nil {
		t.Fatalf("unable to save new index: %v", err)
	}

	t.Logf("new index saved as %v", id.Str())

	for id := range idx.IndexIDs {
		t.Logf("remove index %v", id.Str())
		err = repo.Backend().Remove(restic.IndexFile, id.String())
		if err != nil {
			t.Errorf("error removing index %v: %v", id, err)
		}
	}

	idx2 := loadIndex(t, repo)
	t.Logf("load new index with %d packs", len(idx2.Packs))

	if len(idx2.Packs) != len(packs) {
		t.Errorf("wrong number of packs in new index, want %d, got %d", len(packs), len(idx2.Packs))
	}

	for id := range packs {
		if _, ok := idx2.Packs[id]; !ok {
			t.Errorf("pack %v is not contained in new index", id.Str())
		}
	}

	for id := range idx2.Packs {
		if _, ok := packs[id]; !ok {
			t.Errorf("pack %v is not contained in new index", id.Str())
		}
	}
}

func TestIndexSave(t *testing.T) {
	repo, cleanup := createFilledRepo(t, 3, 0)
	defer cleanup()

	idx := loadIndex(t, repo)

	id, err := idx.Save(repo, idx.IndexIDs.List())
	if err != nil {
		t.Fatalf("unable to save new index: %v", err)
	}

	t.Logf("new index saved as %v", id.Str())

	for id := range idx.IndexIDs {
		t.Logf("remove index %v", id.Str())
		err = repo.Backend().Remove(restic.IndexFile, id.String())
		if err != nil {
			t.Errorf("error removing index %v: %v", id, err)
		}
	}

	idx2 := loadIndex(t, repo)
	t.Logf("load new index with %d packs", len(idx2.Packs))

	checker := checker.New(repo)
	hints, errs := checker.LoadIndex()
	for _, h := range hints {
		t.Logf("hint: %v\n", h)
	}

	for _, err := range errs {
		t.Errorf("checker found error: %v", err)
	}
}

func TestIndexAddRemovePack(t *testing.T) {
	repo, cleanup := createFilledRepo(t, 3, 0)
	defer cleanup()

	idx, err := Load(repo, nil)
	if err != nil {
		t.Fatalf("Load() returned error %v", err)
	}

	done := make(chan struct{})
	defer close(done)

	packID := <-repo.List(restic.DataFile, done)

	t.Logf("selected pack %v", packID.Str())

	blobs := idx.Packs[packID].Entries

	idx.RemovePack(packID)

	if _, ok := idx.Packs[packID]; ok {
		t.Errorf("removed pack %v found in index.Packs", packID.Str())
	}

	for _, blob := range blobs {
		h := restic.BlobHandle{ID: blob.ID, Type: blob.Type}
		_, err := idx.FindBlob(h)
		if err == nil {
			t.Errorf("removed blob %v found in index", h)
		}
	}
}

// example index serialization from doc/Design.md
var docExample = []byte(`
{
  "supersedes": [
	"ed54ae36197f4745ebc4b54d10e0f623eaaaedd03013eb7ae90df881b7781452"
  ],
  "packs": [
	{
	  "id": "73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c",
	  "blobs": [
		{
		  "id": "3ec79977ef0cf5de7b08cd12b874cd0f62bbaf7f07f3497a5b1bbcc8cb39b1ce",
		  "type": "data",
		  "offset": 0,
		  "length": 25
		},{
		  "id": "9ccb846e60d90d4eb915848add7aa7ea1e4bbabfc60e573db9f7bfb2789afbae",
		  "type": "tree",
		  "offset": 38,
		  "length": 100
		},
		{
		  "id": "d3dc577b4ffd38cc4b32122cabf8655a0223ed22edfd93b353dc0c3f2b0fdf66",
		  "type": "data",
		  "offset": 150,
		  "length": 123
		}
	  ]
	}
  ]
}
`)

func TestIndexLoadDocReference(t *testing.T) {
	repo, cleanup := repository.TestRepository(t)
	defer cleanup()

	id, err := repo.SaveUnpacked(restic.IndexFile, docExample)
	if err != nil {
		t.Fatalf("SaveUnpacked() returned error %v", err)
	}

	t.Logf("index saved as %v", id.Str())

	idx := loadIndex(t, repo)

	blobID := restic.TestParseID("d3dc577b4ffd38cc4b32122cabf8655a0223ed22edfd93b353dc0c3f2b0fdf66")
	locs, err := idx.FindBlob(restic.BlobHandle{ID: blobID, Type: restic.DataBlob})
	if err != nil {
		t.Errorf("FindBlob() returned error %v", err)
	}

	if len(locs) != 1 {
		t.Errorf("blob found %d times, expected just one", len(locs))
	}

	l := locs[0]
	if !l.ID.Equal(blobID) {
		t.Errorf("blob IDs are not equal: %v != %v", l.ID, blobID)
	}

	if l.Type != restic.DataBlob {
		t.Errorf("want type %v, got %v", restic.DataBlob, l.Type)
	}

	if l.Offset != 150 {
		t.Errorf("wrong offset, want %d, got %v", 150, l.Offset)
	}

	if l.Length != 123 {
		t.Errorf("wrong length, want %d, got %v", 123, l.Length)
	}
}
<commit_msg>Index: Test pack ID<commit_after>package index

import (
	"math/rand"
	"restic"
	"restic/checker"
	"restic/repository"
	"restic/test"
	"testing"
	"time"
)

var (
	snapshotTime = time.Unix(1470492820, 207401672)
	depth        = 3
)

func createFilledRepo(t testing.TB, snapshots int, dup float32) (restic.Repository, func()) {
	repo, cleanup := repository.TestRepository(t)

	for i := 0; i < 3; i++ {
		restic.TestCreateSnapshot(t, repo, snapshotTime.Add(time.Duration(i)*time.Second), depth, dup)
	}

	return repo, cleanup
}

func validateIndex(t testing.TB, repo restic.Repository, idx *Index) {
	for id := range repo.List(restic.DataFile, nil) {
		p, ok := idx.Packs[id]
		if !ok {
			t.Errorf("pack %v missing from index", id.Str())
		}

		if !p.ID.Equal(id) {
			t.Errorf("pack %v has invalid ID: want %v, got %v", id.Str(), id, p.ID)
		}
	}
}

func TestIndexNew(t *testing.T) {
	repo, cleanup := createFilledRepo(t, 3, 0)
	defer cleanup()

	idx, err := New(repo, nil)
	if err != nil {
		t.Fatalf("New() returned error %v", err)
	}

	if idx == nil {
		t.Fatalf("New() returned nil index")
	}

	validateIndex(t, repo, idx)
}

func TestIndexLoad(t *testing.T) {
	repo, cleanup := createFilledRepo(t, 3, 0)
	defer cleanup()

	loadIdx, err := Load(repo, nil)
	if err != nil {
		t.Fatalf("Load() returned error %v", err)
	}

	if loadIdx == nil {
		t.Fatalf("Load() returned nil index")
	}

	validateIndex(t, repo, loadIdx)

	newIdx, err := New(repo, nil)
	if err != nil {
		t.Fatalf("New() returned error %v", err)
	}

	if len(loadIdx.Packs) != len(newIdx.Packs) {
		t.Errorf("number of packs does not match: want %v, got %v",
			len(loadIdx.Packs), len(newIdx.Packs))
	}

	validateIndex(t, repo, newIdx)

	for packID, packNew := range newIdx.Packs {
		packLoad, ok := loadIdx.Packs[packID]

		if !ok {
			t.Errorf("loaded index does not list pack %v", packID.Str())
			continue
		}

		if len(packNew.Entries) != len(packLoad.Entries) {
			t.Errorf("  number of entries in pack %v does not match: %d != %d\n  %v\n  %v",
				packID.Str(), len(packNew.Entries), len(packLoad.Entries),
				packNew.Entries, packLoad.Entries)
			continue
		}

		for _, entryNew := range packNew.Entries {
			found := false
			for _, entryLoad := range packLoad.Entries {
				if !entryLoad.ID.Equal(entryNew.ID) {
					continue
				}

				if entryLoad.Type != entryNew.Type {
					continue
				}

				if entryLoad.Offset != entryNew.Offset {
					continue
				}

				if entryLoad.Length != entryNew.Length {
					continue
				}

				found = true
				break
			}

			if !found {
				t.Errorf("blob not found in loaded index: %v", entryNew)
			}
		}
	}
}

func BenchmarkIndexNew(b *testing.B) {
	repo, cleanup := createFilledRepo(b, 3, 0)
	defer cleanup()

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		idx, err := New(repo, nil)

		if err != nil {
			b.Fatalf("New() returned error %v", err)
		}

		if idx == nil {
			b.Fatalf("New() returned nil index")
		}
		b.Logf("idx %v packs", len(idx.Packs))
	}
}

func BenchmarkIndexSave(b *testing.B) {
	repo, cleanup := repository.TestRepository(b)
	defer cleanup()

	idx, err := New(repo, nil)
	test.OK(b, err)

	for i := 0; i < 8000; i++ {
		entries := make([]restic.Blob, 0, 200)
		for j := 0; j < cap(entries); j++ {
			entries = append(entries, restic.Blob{
				ID:     restic.NewRandomID(),
				Length: 1000,
				Offset: 5,
				Type:   restic.DataBlob,
			})
		}

		idx.AddPack(restic.NewRandomID(), 10000, entries)
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		id, err := idx.Save(repo, nil)
		if err != nil {
			b.Fatalf("New() returned error %v", err)
		}

		b.Logf("saved as %v", id.Str())
	}
}

func TestIndexDuplicateBlobs(t *testing.T) {
	repo, cleanup := createFilledRepo(t, 3, 0.01)
	defer cleanup()

	idx, err := New(repo, nil)
	if err != nil {
		t.Fatal(err)
	}

	dups := idx.DuplicateBlobs()
	if len(dups) == 0 {
		t.Errorf("no duplicate blobs found")
	}
	t.Logf("%d packs, %d duplicate blobs", len(idx.Packs), len(dups))

	packs := idx.PacksForBlobs(dups)
	if len(packs) == 0 {
		t.Errorf("no packs with duplicate blobs found")
	}
	t.Logf("%d packs with duplicate blobs", len(packs))
}

func loadIndex(t testing.TB, repo restic.Repository) *Index {
	idx, err := Load(repo, nil)
	if err != nil {
		t.Fatalf("Load() returned error %v", err)
	}

	return idx
}

func TestSave(t *testing.T) {
	repo, cleanup := createFilledRepo(t, 3, 0)
	defer cleanup()

	idx := loadIndex(t, repo)

	packs := make(map[restic.ID][]restic.Blob)
	for id := range idx.Packs {
		if rand.Float32() < 0.5 {
			packs[id] = idx.Packs[id].Entries
		}
	}

	t.Logf("save %d/%d packs in a new index\n", len(packs), len(idx.Packs))

	id, err := Save(repo, packs, idx.IndexIDs.List())
	if err != nil {
		t.Fatalf("unable to save new index: %v", err)
	}

	t.Logf("new index saved as %v", id.Str())

	for id := range idx.IndexIDs {
		t.Logf("remove index %v", id.Str())
		err = repo.Backend().Remove(restic.IndexFile, id.String())
		if err != nil {
			t.Errorf("error removing index %v: %v", id, err)
		}
	}

	idx2 := loadIndex(t, repo)
	t.Logf("load new index with %d packs", len(idx2.Packs))

	if len(idx2.Packs) != len(packs) {
		t.Errorf("wrong number of packs in new index, want %d, got %d", len(packs), len(idx2.Packs))
	}

	for id := range packs {
		if _, ok := idx2.Packs[id]; !ok {
			t.Errorf("pack %v is not contained in new index", id.Str())
		}
	}

	for id := range idx2.Packs {
		if _, ok := packs[id]; !ok {
			t.Errorf("pack %v is not contained in new index", id.Str())
		}
	}
}

func TestIndexSave(t *testing.T) {
	repo, cleanup := createFilledRepo(t, 3, 0)
	defer cleanup()

	idx := loadIndex(t, repo)

	id, err := idx.Save(repo, idx.IndexIDs.List())
	if err != nil {
		t.Fatalf("unable to save new index: %v", err)
	}

	t.Logf("new index saved as %v", id.Str())

	for id := range idx.IndexIDs {
		t.Logf("remove index %v", id.Str())
		err = repo.Backend().Remove(restic.IndexFile, id.String())
		if err != nil {
			t.Errorf("error removing index %v: %v", id, err)
		}
	}

	idx2 := loadIndex(t, repo)
	t.Logf("load new index with %d packs", len(idx2.Packs))

	checker := checker.New(repo)
	hints, errs := checker.LoadIndex()
	for _, h := range hints {
		t.Logf("hint: %v\n", h)
	}

	for _, err := range errs {
		t.Errorf("checker found error: %v", err)
	}
}

func TestIndexAddRemovePack(t *testing.T) {
	repo, cleanup := createFilledRepo(t, 3, 0)
	defer cleanup()

	idx, err := Load(repo, nil)
	if err != nil {
		t.Fatalf("Load() returned error %v", err)
	}

	done := make(chan struct{})
	defer close(done)

	packID := <-repo.List(restic.DataFile, done)

	t.Logf("selected pack %v", packID.Str())

	blobs := idx.Packs[packID].Entries

	idx.RemovePack(packID)

	if _, ok := idx.Packs[packID]; ok {
		t.Errorf("removed pack %v found in index.Packs", packID.Str())
	}

	for _, blob := range blobs {
		h := restic.BlobHandle{ID: blob.ID, Type: blob.Type}
		_, err := idx.FindBlob(h)
		if err == nil {
			t.Errorf("removed blob %v found in index", h)
		}
	}
}

// example index serialization from doc/Design.md
var docExample = []byte(`
{
  "supersedes": [
	"ed54ae36197f4745ebc4b54d10e0f623eaaaedd03013eb7ae90df881b7781452"
  ],
  "packs": [
	{
	  "id": "73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c",
	  "blobs": [
		{
		  "id": "3ec79977ef0cf5de7b08cd12b874cd0f62bbaf7f07f3497a5b1bbcc8cb39b1ce",
		  "type": "data",
		  "offset": 0,
		  "length": 25
		},{
		  "id": "9ccb846e60d90d4eb915848add7aa7ea1e4bbabfc60e573db9f7bfb2789afbae",
		  "type": "tree",
		  "offset": 38,
		  "length": 100
		},
		{
		  "id": "d3dc577b4ffd38cc4b32122cabf8655a0223ed22edfd93b353dc0c3f2b0fdf66",
		  "type": "data",
		  "offset": 150,
		  "length": 123
		}
	  ]
	}
  ]
}
`)

func TestIndexLoadDocReference(t *testing.T) {
	repo, cleanup := repository.TestRepository(t)
	defer cleanup()

	id, err := repo.SaveUnpacked(restic.IndexFile, docExample)
	if err != nil {
		t.Fatalf("SaveUnpacked() returned error %v", err)
	}

	t.Logf("index saved as %v", id.Str())

	idx := loadIndex(t, repo)

	blobID := restic.TestParseID("d3dc577b4ffd38cc4b32122cabf8655a0223ed22edfd93b353dc0c3f2b0fdf66")
	locs, err := idx.FindBlob(restic.BlobHandle{ID: blobID, Type: restic.DataBlob})
	if err != nil {
		t.Errorf("FindBlob() returned error %v", err)
	}

	if len(locs) != 1 {
		t.Errorf("blob found %d times, expected just one", len(locs))
	}

	l := locs[0]
	if !l.ID.Equal(blobID) {
		t.Errorf("blob IDs are not equal: %v != %v", l.ID, blobID)
	}

	if l.Type != restic.DataBlob {
		t.Errorf("want type %v, got %v", restic.DataBlob, l.Type)
	}

	if l.Offset != 150 {
		t.Errorf("wrong offset, want %d, got %v", 150, l.Offset)
	}

	if l.Length != 123 {
		t.Errorf("wrong length, want %d, got %v", 123, l.Length)
	}
}
<|endoftext|>