<commit_before>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package channelconfig

import (
	"math"

	"github.com/hyperledger/fabric/bccsp"
	cb "github.com/hyperledger/fabric/protos/common"
	mspprotos "github.com/hyperledger/fabric/protos/msp"
	ab "github.com/hyperledger/fabric/protos/orderer"
	pb "github.com/hyperledger/fabric/protos/peer"

	"github.com/golang/protobuf/proto"
)

const (
	// ReadersPolicyKey is the key used for the read policy
	ReadersPolicyKey = "Readers"

	// WritersPolicyKey is the key used for the read policy
	WritersPolicyKey = "Writers"

	// AdminsPolicyKey is the key used for the read policy
	AdminsPolicyKey = "Admins"

	defaultHashingAlgorithm = bccsp.SHA256

	defaultBlockDataHashingStructureWidth = math.MaxUint32
)

// ConfigValue defines a common representation for different *cb.ConfigValue values.
type ConfigValue interface {
	// Key is the key this value should be stored in the *cb.ConfigGroup.Values map.
	Key() string

	// Value is the message which should be marshaled to opaque bytes for the *cb.ConfigValue.value.
	Value() proto.Message
}

// StandardConfigValue implements the ConfigValue interface.
type StandardConfigValue struct {
	key   string
	value proto.Message
}

// Key is the key this value should be stored in the *cb.ConfigGroup.Values map.
func (scv *StandardConfigValue) Key() string {
	return scv.key
}

// Value is the message which should be marshaled to opaque bytes for the *cb.ConfigValue.value.
func (scv *StandardConfigValue) Value() proto.Message {
	return scv.value
}

// ConsortiumValue returns the config definition for the consortium name.
// It is a value for the channel group.
func ConsortiumValue(name string) *StandardConfigValue {
	return &StandardConfigValue{
		key: ConsortiumKey,
		value: &cb.Consortium{
			Name: name,
		},
	}
}

// HashingAlgorithm returns the only currently valid hashing algorithm.
// It is a value for the /Channel group.
func HashingAlgorithmValue() *StandardConfigValue {
	return &StandardConfigValue{
		key: HashingAlgorithmKey,
		value: &cb.HashingAlgorithm{
			Name: defaultHashingAlgorithm,
		},
	}
}

// BlockDataHashingStructureValue returns the only currently valid block data hashing structure.
// It is a value for the /Channel group.
func BlockDataHashingStructureValue() *StandardConfigValue {
	return &StandardConfigValue{
		key: BlockDataHashingStructureKey,
		value: &cb.BlockDataHashingStructure{
			Width: defaultBlockDataHashingStructureWidth,
		},
	}
}

// OrdererAddressesValue returns the a config definition for the orderer addresses.
// It is a value for the /Channel group.
func OrdererAddressesValue(addresses []string) *StandardConfigValue {
	return &StandardConfigValue{
		key: OrdererAddressesKey,
		value: &cb.OrdererAddresses{
			Addresses: addresses,
		},
	}
}

// ConsensusTypeValue returns the config definition for the orderer consensus type.
// It is a value for the /Channel/Orderer group.
func ConsensusTypeValue(consensusType string) *StandardConfigValue {
	return &StandardConfigValue{
		key: ConsensusTypeKey,
		value: &ab.ConsensusType{
			Type: consensusType,
		},
	}
}

// BatchSizeValue returns the config definition for the orderer batch size.
// It is a value for the /Channel/Orderer group.
func BatchSizeValue(maxMessages, absoluteMaxBytes, preferredMaxBytes uint32) *StandardConfigValue {
	return &StandardConfigValue{
		key: BatchSizeKey,
		value: &ab.BatchSize{
			MaxMessageCount:   maxMessages,
			AbsoluteMaxBytes:  absoluteMaxBytes,
			PreferredMaxBytes: preferredMaxBytes,
		},
	}
}

// BatchTimeoutValue returns the config definition for the orderer batch timeout.
// It is a value for the /Channel/Orderer group.
func BatchTimeoutValue(timeout string) *StandardConfigValue {
	return &StandardConfigValue{
		key: BatchTimeoutKey,
		value: &ab.BatchTimeout{
			Timeout: timeout,
		},
	}
}

// ChannelRestrictionsValue returns the config definition for the orderer channel restrictions.
// It is a value for the /Channel/Orderer group.
func ChannelRestrictionsValue(maxChannelCount uint64) *StandardConfigValue {
	return &StandardConfigValue{
		key: ChannelRestrictionsKey,
		value: &ab.ChannelRestrictions{
			MaxCount: maxChannelCount,
		},
	}
}

// ChannelRestrictionsValue returns the config definition for the orderer channel restrictions.
// It is a value for the /Channel/Orderer group.
func KafkaBrokersValue(brokers []string) *StandardConfigValue {
	return &StandardConfigValue{
		key: KafkaBrokersKey,
		value: &ab.KafkaBrokers{
			Brokers: brokers,
		},
	}
}

// MSPValue returns the config definition for an MSP.
// It is a value for the /Channel/Orderer/*, /Channel/Application/*, and /Channel/Consortiums/*/*/* groups.
func MSPValue(mspDef *mspprotos.MSPConfig) *StandardConfigValue {
	return &StandardConfigValue{
		key:   MSPKey,
		value: mspDef,
	}
}

// CapabilitiesValue returns the config definition for a a set of capabilities.
// It is a value for the /Channel/Orderer, Channel/Application/, and /Channel groups.
func CapabilitiesValue(capabilities map[string]bool) *StandardConfigValue {
	c := &cb.Capabilities{
		Capabilities: make(map[string]*cb.Capability),
	}

	for capability, required := range capabilities {
		if !required {
			continue
		}
		c.Capabilities[capability] = &cb.Capability{}
	}

	return &StandardConfigValue{
		key:   CapabilitiesKey,
		value: c,
	}
}

// AnchorPeersValue returns the config definition for an org's anchor peers.
// It is a value for the /Channel/Application/*.
func AnchorPeersValue(anchorPeers []*pb.AnchorPeer) *StandardConfigValue {
	return &StandardConfigValue{
		key:   AnchorPeersKey,
		value: &pb.AnchorPeers{AnchorPeers: anchorPeers},
	}
}

// ChannelCreationPolicyValue returns the config definition for a consortium's channel creation policy
// It is a value for the /Channel/Consortiums/*/*.
func ChannelCreationPolicyValue(policy *cb.Policy) *StandardConfigValue {
	return &StandardConfigValue{
		key:   ChannelCreationPolicyKey,
		value: policy,
	}
}
<commit_msg>[FAB-6800] modify comment<commit_after>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package channelconfig

import (
	"math"

	"github.com/hyperledger/fabric/bccsp"
	cb "github.com/hyperledger/fabric/protos/common"
	mspprotos "github.com/hyperledger/fabric/protos/msp"
	ab "github.com/hyperledger/fabric/protos/orderer"
	pb "github.com/hyperledger/fabric/protos/peer"

	"github.com/golang/protobuf/proto"
)

const (
	// ReadersPolicyKey is the key used for the read policy
	ReadersPolicyKey = "Readers"

	// WritersPolicyKey is the key used for the read policy
	WritersPolicyKey = "Writers"

	// AdminsPolicyKey is the key used for the read policy
	AdminsPolicyKey = "Admins"

	defaultHashingAlgorithm = bccsp.SHA256

	defaultBlockDataHashingStructureWidth = math.MaxUint32
)

// ConfigValue defines a common representation for different *cb.ConfigValue values.
type ConfigValue interface {
	// Key is the key this value should be stored in the *cb.ConfigGroup.Values map.
	Key() string

	// Value is the message which should be marshaled to opaque bytes for the *cb.ConfigValue.value.
	Value() proto.Message
}

// StandardConfigValue implements the ConfigValue interface.
type StandardConfigValue struct {
	key   string
	value proto.Message
}

// Key is the key this value should be stored in the *cb.ConfigGroup.Values map.
func (scv *StandardConfigValue) Key() string {
	return scv.key
}

// Value is the message which should be marshaled to opaque bytes for the *cb.ConfigValue.value.
func (scv *StandardConfigValue) Value() proto.Message {
	return scv.value
}

// ConsortiumValue returns the config definition for the consortium name.
// It is a value for the channel group.
func ConsortiumValue(name string) *StandardConfigValue {
	return &StandardConfigValue{
		key: ConsortiumKey,
		value: &cb.Consortium{
			Name: name,
		},
	}
}

// HashingAlgorithm returns the only currently valid hashing algorithm.
// It is a value for the /Channel group.
func HashingAlgorithmValue() *StandardConfigValue {
	return &StandardConfigValue{
		key: HashingAlgorithmKey,
		value: &cb.HashingAlgorithm{
			Name: defaultHashingAlgorithm,
		},
	}
}

// BlockDataHashingStructureValue returns the only currently valid block data hashing structure.
// It is a value for the /Channel group.
func BlockDataHashingStructureValue() *StandardConfigValue {
	return &StandardConfigValue{
		key: BlockDataHashingStructureKey,
		value: &cb.BlockDataHashingStructure{
			Width: defaultBlockDataHashingStructureWidth,
		},
	}
}

// OrdererAddressesValue returns the a config definition for the orderer addresses.
// It is a value for the /Channel group.
func OrdererAddressesValue(addresses []string) *StandardConfigValue {
	return &StandardConfigValue{
		key: OrdererAddressesKey,
		value: &cb.OrdererAddresses{
			Addresses: addresses,
		},
	}
}

// ConsensusTypeValue returns the config definition for the orderer consensus type.
// It is a value for the /Channel/Orderer group.
func ConsensusTypeValue(consensusType string) *StandardConfigValue {
	return &StandardConfigValue{
		key: ConsensusTypeKey,
		value: &ab.ConsensusType{
			Type: consensusType,
		},
	}
}

// BatchSizeValue returns the config definition for the orderer batch size.
// It is a value for the /Channel/Orderer group.
func BatchSizeValue(maxMessages, absoluteMaxBytes, preferredMaxBytes uint32) *StandardConfigValue {
	return &StandardConfigValue{
		key: BatchSizeKey,
		value: &ab.BatchSize{
			MaxMessageCount:   maxMessages,
			AbsoluteMaxBytes:  absoluteMaxBytes,
			PreferredMaxBytes: preferredMaxBytes,
		},
	}
}

// BatchTimeoutValue returns the config definition for the orderer batch timeout.
// It is a value for the /Channel/Orderer group.
func BatchTimeoutValue(timeout string) *StandardConfigValue {
	return &StandardConfigValue{
		key: BatchTimeoutKey,
		value: &ab.BatchTimeout{
			Timeout: timeout,
		},
	}
}

// ChannelRestrictionsValue returns the config definition for the orderer channel restrictions.
// It is a value for the /Channel/Orderer group.
func ChannelRestrictionsValue(maxChannelCount uint64) *StandardConfigValue {
	return &StandardConfigValue{
		key: ChannelRestrictionsKey,
		value: &ab.ChannelRestrictions{
			MaxCount: maxChannelCount,
		},
	}
}

// KafkaBrokersValue returns the config definition for the addresses of the ordering service's Kafka brokers.
// It is a value for the /Channel/Orderer group.
func KafkaBrokersValue(brokers []string) *StandardConfigValue {
	return &StandardConfigValue{
		key: KafkaBrokersKey,
		value: &ab.KafkaBrokers{
			Brokers: brokers,
		},
	}
}

// MSPValue returns the config definition for an MSP.
// It is a value for the /Channel/Orderer/*, /Channel/Application/*, and /Channel/Consortiums/*/*/* groups.
func MSPValue(mspDef *mspprotos.MSPConfig) *StandardConfigValue {
	return &StandardConfigValue{
		key:   MSPKey,
		value: mspDef,
	}
}

// CapabilitiesValue returns the config definition for a a set of capabilities.
// It is a value for the /Channel/Orderer, Channel/Application/, and /Channel groups.
func CapabilitiesValue(capabilities map[string]bool) *StandardConfigValue {
	c := &cb.Capabilities{
		Capabilities: make(map[string]*cb.Capability),
	}

	for capability, required := range capabilities {
		if !required {
			continue
		}
		c.Capabilities[capability] = &cb.Capability{}
	}

	return &StandardConfigValue{
		key:   CapabilitiesKey,
		value: c,
	}
}

// AnchorPeersValue returns the config definition for an org's anchor peers.
// It is a value for the /Channel/Application/*.
func AnchorPeersValue(anchorPeers []*pb.AnchorPeer) *StandardConfigValue {
	return &StandardConfigValue{
		key:   AnchorPeersKey,
		value: &pb.AnchorPeers{AnchorPeers: anchorPeers},
	}
}

// ChannelCreationPolicyValue returns the config definition for a consortium's channel creation policy
// It is a value for the /Channel/Consortiums/*/*.
func ChannelCreationPolicyValue(policy *cb.Policy) *StandardConfigValue {
	return &StandardConfigValue{
		key:   ChannelCreationPolicyKey,
		value: policy,
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Pani Networks
// All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package client

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"reflect"
	"testing"

	"github.com/romana/core/common/api"
)

type testcase struct {
	name string
	ipam *IPAM
	want interface{}
}

func loadTestFiles(name string, inFile string, outFile string) (testcase, error) {
	input, err := ioutil.ReadFile(inFile)
	if err != nil {
		return testcase{}, fmt.Errorf("error reading test input file: %s", err)
	}
	output, err := ioutil.ReadFile(outFile)
	if err != nil {
		return testcase{}, fmt.Errorf("error reading test output file: %s", err)
	}

	ipamState := &IPAM{}
	err = json.Unmarshal(input, ipamState)
	if err != nil {
		return testcase{}, fmt.Errorf("failed to unmarshal ipam information: %s", err)
	}
	topologyState := &api.TopologyUpdateRequest{}
	err = json.Unmarshal(output, topologyState)
	if err != nil {
		return testcase{}, fmt.Errorf("failed to unmarshal topology information: %s", err)
	}

	return testcase{name, ipamState, topologyState}, nil
}

func Test_getTopologyFromIPAMState(t *testing.T) {
	var testcases []testcase

	testfiles := map[string][]string{
		"multinetwork": {
			"testdata/TestTopologyGetInputMultiNetworks.json",
			"testdata/TestTopologyGetOutputMultiNetworks.json",
		},
		"kubeadm": {
			"testdata/TestTopologyGetInputKubeadm.json",
			"testdata/TestTopologyGetOutputKubeadm.json",
		},
	}

	for name, file := range testfiles {
		tc, err := loadTestFiles(name, file[0], file[1])
		if err != nil {
			t.Errorf("error loading test files: %s", err)
			continue
		}
		testcases = append(testcases, tc)
	}

	for _, tt := range testcases {
		t.Run(tt.name, func(t *testing.T) {
			// TODO: got and tt.want below are not sorted, so there is a fair chance the
			// testcases here may fail, in which case this needs to be fixed by sorting
			// it first.
			if got := getTopologyFromIPAMState(tt.ipam); !reflect.DeepEqual(got, tt.want) {
				bodyGot, errGot := json.MarshalIndent(got, "", "\t")
				bodyWant, errWant := json.MarshalIndent(tt.want, "", "\t")
				if errGot == nil && errWant == nil {
					t.Errorf("getTopology() = \ngot(%s)\nwant(%s)",
						string(bodyGot), string(bodyWant))
				} else {
					t.Errorf("getTopology() = \ngot(%#v)\nwant(%#v)", got, tt.want)
				}
			}
		})
	}
}
<commit_msg>common: restore commented testcase as requested.<commit_after>// Copyright (c) 2017 Pani Networks
// All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package client

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"reflect"
	"testing"
	"time"

	"github.com/romana/core/common"
	"github.com/romana/core/common/api"
)

var (
	client *Client
	// Keep track of state of some tests
	state int
)

func init() {
	rand.Seed(time.Now().UnixNano())
	testSaver = &TestSaver{}
}

func tearDown(t *testing.T) {
	var err error
	err = client.Store.DeleteTree(client.config.EtcdPrefix)
	if err != nil {
		t.Errorf("Error tearing down: %s", err)
	}
	t.Logf("Tore down %s", client.config.EtcdPrefix)
}

func initClient(t *testing.T, topoConf string) *Client {
	var err error
	cfg := &common.Config{EtcdEndpoints: []string{"localhost:2379"},
		EtcdPrefix: fmt.Sprintf("/romanaTest%d", rand.Int63n(100000)),
	}
	client, err := NewClient(cfg)
	if err != nil {
		t.Fatal(err)
	}
	if topoConf != "" {
		topoReq := api.TopologyUpdateRequest{}
		err = json.Unmarshal([]byte(topoConf), &topoReq)
		if err != nil {
			t.Fatalf("Cannot parse %s: %v", topoConf, err)
		}
		err = client.IPAM.UpdateTopology(topoReq, false)
		if err != nil {
			t.Fatal(err)
		}
	}
	return client
}

// TestWatchHostsWithCallback tests WatchHostsWithCallback -- and since it
// uses WatchHosts internally, implicitly also WatchHosts
/*
func TestWatchHostsWithCallback(t *testing.T) {
	client := initClient(t, "")
	defer tearDown(t)
	errCh := make(chan string)
	okCh := make(chan string)
	err := client.WatchHostsWithCallback(func(hl api.HostList) {
		state++

		var msg string
		fmt.Printf("HostListCallback: Got host list of length %d and revision %d in state %d\n", len(hl.Hosts), hl.Revision, state)
		if state == 1 {
			if len(hl.Hosts) != 0 {
				msg = fmt.Sprintf("HostListCallback: Expected host length at this point to be 0, got %d", len(hl.Hosts))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != 0 {
				msg = fmt.Sprintf("HostListCallback: Expected host list revision at this point to be 0, got %d", hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}
		} else if state == 2 {
			if len(hl.Hosts) != 2 {
				msg = fmt.Sprintf("HostListCallback: Expected host length at this point to be 2, got %d", len(hl.Hosts))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != 1 {
				msg = fmt.Sprintf("HostListCallback: Expected host list revision at this point to be 1, got %d", hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}
			// Here everything is ok!
			okCh <- "OK"
		} else {
			msg = fmt.Sprintf("HostListCallback: Did not expect HostListCallback to be called in state %d", state)
			fmt.Println(state)
			errCh <- msg

		}

	})
	if err != nil {
		t.Fatal(err)
	}

	topoConf := `{
	"networks": [{
		"name": "net1",
		"cidr": "10.0.0.0/8",
		"block_mask": 30
	}],

	"topologies": [{
		"networks": ["net1"],
		"map": [{
			"routing": "bla",
			"groups": [{
					"name": "host1",
					"ip": "192.168.99.10"
				},
				{
					"name": "host2",
					"ip": "192.168.99.11"
				}
			]
		}]
	}]
}`
	topoReq := api.TopologyUpdateRequest{}
	err = json.Unmarshal([]byte(topoConf), &topoReq)
	if err != nil {
		t.Fatalf("Cannot parse %s: %v", topoConf, err)
	}
	err = client.IPAM.UpdateTopology(topoReq)
	if err != nil {
		t.Fatal(err)
	}
	for {
		select {
		case msg := <-errCh:
			t.Fatal(msg)
			break
		case <-okCh:
			return
		}
	}

}
*/

// TestWatchBlocksWithCallback tests WatchBlocksWithCallback -- and since it
// uses WatchBlocks internally, implicitly also WatchBlocks
/*
func TestWatchBlocksWithCallback(t *testing.T) {
	defer tearDown(t)
	errCh := make(chan string)
	okCh := make(chan string)
	topoConf := `{
	"networks": [{
		"name": "net1",
		"cidr": "10.0.0.0/8",
		"block_mask": 31
	}],

	"topologies": [{
		"networks": ["net1"],
		"map": [{
			"routing": "bla",
			"groups": [{
					"name": "host1",
					"ip": "192.168.99.10"
				},
				{
					"name": "host2",
					"ip": "192.168.99.11"
				}
			]
		}]
	}]
}`
	client = initClient(t, topoConf)
	err := client.WatchBlocksWithCallback(func(hl api.IPAMBlocksResponse) {
		state++

		var msg string
		fmt.Printf("BlocksListCallback: Got block list of length %d and revision %d in state %d\n", len(hl.Blocks), hl.Revision, state)
		switch state {
		case 1:
			if len(hl.Blocks) != 0 {
				msg = fmt.Sprintf("BlocksListCallback: Expected block length at this point to be 0, got %d", len(hl.Blocks))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != 0 {
				msg = fmt.Sprintf("BlocksListCallback: Expected block list revision at this point to be 0, got %d", hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}
		case 2, 3:
			if len(hl.Blocks) != 1 {
				msg = fmt.Sprintf("BlocksListCallback: Expected block length at this point to be 1, got %d", len(hl.Blocks))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != state-1 {
				msg = fmt.Sprintf("HostListCallback: Expected block list revision at this point to be %d, got %d", state-1, hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}

		case 4, 5:
			if len(hl.Blocks) != 2 {
				msg = fmt.Sprintf("BlocksListCallback: Expected block length at this point to be 2, got %d", len(hl.Blocks))
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if hl.Revision != state-1 {
				msg = fmt.Sprintf("HostListCallback: Expected block list revision at this point to be %d, got %d", state-1, hl.Revision)
				fmt.Println(msg)
				errCh <- msg
				return
			}
			if state == 5 {
				// Here everything is ok!
				okCh <- "OK"
			}
		default:
			msg = fmt.Sprintf("HostListCallback: Did not expect HostListCallback to be called in state %d", state)
			errCh <- msg

		}

	})
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.IPAM.AllocateIP("addr1", "host1", "t1", "s1")
	if err != nil {
		t.Fatal(err)
	}
	_, err = client.IPAM.AllocateIP("addr2", "host1", "t1", "s1")
	if err != nil {
		t.Fatal(err)
	}
	_, err = client.IPAM.AllocateIP("addr3", "host1", "t1", "s1")
	if err != nil {
		t.Fatal(err)
	}
	_, err = client.IPAM.AllocateIP("addr4", "host1", "t1", "s1")
	if err != nil {
		t.Fatal(err)
	}
	for {
		select {
		case msg := <-errCh:
			t.Fatal(msg)
			break
		case <-okCh:
			return
		}
	}
}
*/

/*
func TestConcurrency(t *testing.T) {
	//	defer tearDown(t)
	client = initClient(t, "")

	barrier := make(chan int)
	cnt := 8
	locker, err := client.Store.NewLocker("/lock")
	if err != nil {
		t.Fatal(err)
	}
	for i := 0; i < cnt; i++ {
		go func(i int) {
			fmt.Printf("%d %d Entered\n", i, getGID())
			defer func(i int) {
				fmt.Printf("%d %d Unlocking\n", i, getGID())
				locker.Unlock()
				fmt.Printf("%d %d Unlocked\n", i, getGID())
			}(i)
			fmt.Printf("%d %d Waiting for lock\n", i, getGID())
			locker.Lock()
			fmt.Printf("%d %d Got lock\n", i, getGID())
			val := fmt.Sprintf("Hello from %d %d", i, getGID())
			err := client.Store.Put(fmt.Sprintf("/test%d", i), []byte(val), nil)
			if err != nil {
				fmt.Println(err)
			}
			barrier <- 1
		}(i)
	}
	finishedCnt := 0

WAIT_FOR_FINISH:
	for {
		select {
		case <-barrier:
			finishedCnt++
			fmt.Printf("%d routines finished\n", finishedCnt)
			if finishedCnt == cnt {
				break WAIT_FOR_FINISH
			}
		}
	}
}
*/

type testcase struct {
	name string
	ipam *IPAM
	want interface{}
}

func loadTestFiles(name string, inFile string, outFile string) (testcase, error) {
	input, err := ioutil.ReadFile(inFile)
	if err != nil {
		return testcase{}, fmt.Errorf("error reading test input file: %s", err)
	}
	output, err := ioutil.ReadFile(outFile)
	if err != nil {
		return testcase{}, fmt.Errorf("error reading test output file: %s", err)
	}

	ipamState := &IPAM{}
	err = json.Unmarshal(input, ipamState)
	if err != nil {
		return testcase{}, fmt.Errorf("failed to unmarshal ipam information: %s", err)
	}
	topologyState := &api.TopologyUpdateRequest{}
	err = json.Unmarshal(output, topologyState)
	if err != nil {
		return testcase{}, fmt.Errorf("failed to unmarshal topology information: %s", err)
	}

	return testcase{name, ipamState, topologyState}, nil
}

func Test_getTopologyFromIPAMState(t *testing.T) {
	var testcases []testcase

	testfiles := map[string][]string{
		"multinetwork": {
			"testdata/TestTopologyGetInputMultiNetworks.json",
			"testdata/TestTopologyGetOutputMultiNetworks.json",
		},
		"kubeadm": {
			"testdata/TestTopologyGetInputKubeadm.json",
			"testdata/TestTopologyGetOutputKubeadm.json",
		},
	}

	for name, file := range testfiles {
		tc, err := loadTestFiles(name, file[0], file[1])
		if err != nil {
			t.Errorf("error loading test files: %s", err)
			continue
		}
		testcases = append(testcases, tc)
	}

	for _, tt := range testcases {
		t.Run(tt.name, func(t *testing.T) {
			// TODO: got and tt.want below are not sorted, so there is a fair chance the
			// testcases here may fail, in which case this needs to be fixed by sorting
			// it first.
			if got := getTopologyFromIPAMState(tt.ipam); !reflect.DeepEqual(got, tt.want) {
				bodyGot, errGot := json.MarshalIndent(got, "", "\t")
				bodyWant, errWant := json.MarshalIndent(tt.want, "", "\t")
				if errGot == nil && errWant == nil {
					t.Errorf("getTopology() = \ngot(%s)\nwant(%s)",
						string(bodyGot), string(bodyWant))
				} else {
					t.Errorf("getTopology() = \ngot(%#v)\nwant(%#v)", got, tt.want)
				}
			}
		})
	}
}
<|endoftext|>


<commit_before><commit_msg>Problem: FacilityTextToFacility routine was ugly<commit_after><|endoftext|>


<commit_before><commit_msg>fix #89: remove mime/multipart temp file<commit_after><|endoftext|>


<commit_before>package fileutil

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
)

func CopyDirectory(dst, src string) error {
	fi, err := os.Stat(src)
	if err != nil {
		return err
	}

	err = os.MkdirAll(dst, fi.Mode())
	if err != nil {
		return err
	}

	subfiles, err := ioutil.ReadDir(src)
	if err != nil {
		return err
	}

	for _, file := range subfiles {
		source_file, err := filepath.EvalSymlinks(filepath.Join(src, file.Name()))
		if err != nil {
			continue
		}
		destination_file := filepath.Join(dst, file.Name())

		if file.IsDir() {
			err = CopyDirectory(destination_file, source_file)
			if err != nil {
				return err
			}
		} else {
			err = CopyFile(destination_file, source_file)
			if err != nil {
				log.Println(err)
				continue
			}
		}
	}
	return nil
}

func CopyFile(dst, src string) error {
	source_file, err := os.Open(src)
	if err != nil {
		return err
	}
	source_stat, err := os.Stat(src)
	if err != nil {
		return err
	}
	destination_file, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR, source_stat.Mode())
	if err != nil {
		return err
	}
	defer destination_file.Close()
	_, err = io.Copy(destination_file, source_file)
	return err
}
<commit_msg>Defer the close on the output file.<commit_after>package fileutil

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
)

func CopyDirectory(dst, src string) error {
	fi, err := os.Stat(src)
	if err != nil {
		return err
	}

	err = os.MkdirAll(dst, fi.Mode())
	if err != nil {
		return err
	}

	subfiles, err := ioutil.ReadDir(src)
	if err != nil {
		return err
	}

	for _, file := range subfiles {
		source_file, err := filepath.EvalSymlinks(filepath.Join(src, file.Name()))
		if err != nil {
			continue
		}
		destination_file := filepath.Join(dst, file.Name())

		if file.IsDir() {
			err = CopyDirectory(destination_file, source_file)
			if err != nil {
				return err
			}
		} else {
			err = CopyFile(destination_file, source_file)
			if err != nil {
				log.Println(err)
				continue
			}
		}
	}
	return nil
}

func CopyFile(dst, src string) error {
	source_file, err := os.Open(src)
	if err != nil {
		return err
	}
	defer source_file.Close()
	source_stat, err := os.Stat(src)
	if err != nil {
		return err
	}
	destination_file, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR, source_stat.Mode())
	if err != nil {
		return err
	}
	defer destination_file.Close()
	_, err = io.Copy(destination_file, source_file)
	return err
}
<|endoftext|>


<commit_before>package testing

import (
	"reflect"

	"v2ray.com/core/common/net"
	"v2ray.com/ext/assert"
)

var IsIPv4 = assert.CreateOperator(reflect.TypeOf(net.Address(nil)), reflect.ValueOf(func(a net.Address) bool {
	return a.Family().IsIPv4()
}), 1, "is IPv4")

var IsIPv6 = assert.CreateOperator(reflect.TypeOf(net.Address(nil)), reflect.ValueOf(func(a net.Address) bool {
	return a.Family().IsIPv6()
}), 1, "is IPv6")

var IsIP = assert.CreateOperator(reflect.TypeOf(net.Address(nil)), reflect.ValueOf(func(a net.Address) bool {
	return a.Family().IsIPv4() || a.Family().IsIPv6()
}), 1, "is IP")

var IsTCP = assert.CreateOperator(reflect.TypeOf(net.Destination{}), reflect.ValueOf(func(a net.Destination) bool {
	return a.Network == net.Network_TCP
}), 1, "is TCP")

var IsUDP = assert.CreateOperator(reflect.TypeOf(net.Destination{}), reflect.ValueOf(func(a net.Destination) bool {
	return a.Network == net.Network_UDP
}), 1, "is UDP")

var IsDomain = assert.CreateOperator(reflect.TypeOf(net.Address(nil)), reflect.ValueOf(func(a net.Address) bool {
	return a.Family().IsDomain()
}), 1, "is Domain")

func init() {
	assert.RegisterEqualsOperator(reflect.TypeOf((*net.Address)(nil)).Elem(), reflect.ValueOf(func(a, b net.Address) bool {
		return a == b
	}))

	assert.RegisterEqualsOperator(reflect.TypeOf(net.Destination{}), reflect.ValueOf(func(a, b net.Destination) bool {
		return a == b
	}))

	assert.RegisterEqualsOperator(reflect.TypeOf(net.Port(0)), reflect.ValueOf(func(a, b net.Port) bool {
		return a == b
	}))
}
<commit_msg>update assertion api<commit_after>package testing

import (
	"reflect"

	"v2ray.com/core/common/net"
	"v2ray.com/ext/assert"
)

var IsIPv4 = assert.CreateMatcher(reflect.TypeOf(net.Address(nil)), reflect.ValueOf(func(a net.Address) bool {
	return a.Family().IsIPv4()
}), 1, "is IPv4")

var IsIPv6 = assert.CreateMatcher(reflect.TypeOf(net.Address(nil)), reflect.ValueOf(func(a net.Address) bool {
	return a.Family().IsIPv6()
}), 1, "is IPv6")

var IsIP = assert.CreateMatcher(reflect.TypeOf(net.Address(nil)), reflect.ValueOf(func(a net.Address) bool {
	return a.Family().IsIPv4() || a.Family().IsIPv6()
}), 1, "is IP")

var IsTCP = assert.CreateMatcher(reflect.TypeOf(net.Destination{}), reflect.ValueOf(func(a net.Destination) bool {
	return a.Network == net.Network_TCP
}), 1, "is TCP")

var IsUDP = assert.CreateMatcher(reflect.TypeOf(net.Destination{}), reflect.ValueOf(func(a net.Destination) bool {
	return a.Network == net.Network_UDP
}), 1, "is UDP")

var IsDomain = assert.CreateMatcher(reflect.TypeOf(net.Address(nil)), reflect.ValueOf(func(a net.Address) bool {
	return a.Family().IsDomain()
}), 1, "is Domain")

func init() {
	assert.RegisterEqualsMatcher(reflect.TypeOf((*net.Address)(nil)).Elem(), reflect.ValueOf(func(a, b net.Address) bool {
		return a == b
	}))

	assert.RegisterEqualsMatcher(reflect.TypeOf(net.Destination{}), reflect.ValueOf(func(a, b net.Destination) bool {
		return a == b
	}))

	assert.RegisterEqualsMatcher(reflect.TypeOf(net.Port(0)), reflect.ValueOf(func(a, b net.Port) bool {
		return a == b
	}))
}
<|endoftext|>


<commit_before>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package serial

import (
	"fmt"
	"io"
	"os"
	"sync"
	"syscall"
	"unsafe"
)

type serialPort struct {
	f  *os.File
	fd syscall.Handle
	rl sync.Mutex
	wl sync.Mutex
	ro *syscall.Overlapped
	wo *syscall.Overlapped
}

type structDCB struct {
	DCBlength, BaudRate                            uint32
	flags                                          [4]byte
	wReserved, XonLim, XoffLim                     uint16
	ByteSize, Parity, StopBits                     byte
	XonChar, XoffChar, ErrorChar, EofChar, EvtChar byte
	wReserved1                                     uint16
}

type structTimeouts struct {
	ReadIntervalTimeout         uint32
	ReadTotalTimeoutMultiplier  uint32
	ReadTotalTimeoutConstant    uint32
	WriteTotalTimeoutMultiplier uint32
	WriteTotalTimeoutConstant   uint32
}

func openInternal(options OpenOptions) (io.ReadWriteCloser, error) {
	if len(options.PortName) > 0 && options.PortName[0] != '\\' {
		options.PortName = "\\\\.\\" + options.PortName
	}

	h, err := syscall.CreateFile(syscall.StringToUTF16Ptr(options.PortName),
		syscall.GENERIC_READ|syscall.GENERIC_WRITE,
		0,
		nil,
		syscall.OPEN_EXISTING,
		syscall.FILE_ATTRIBUTE_NORMAL|syscall.FILE_FLAG_OVERLAPPED,
		0)
	if err != nil {
		return nil, err
	}
	f := os.NewFile(uintptr(h), options.PortName)
	defer func() {
		if err != nil {
			f.Close()
		}
	}()

	if err = setCommState(h, options); err != nil {
		return nil, err
	}
	if err = setupComm(h, 64, 64); err != nil {
		return nil, err
	}
	if err = setCommTimeouts(h, options); err != nil {
		return nil, err
	}
	if err = setCommMask(h); err != nil {
		return nil, err
	}

	ro, err := newOverlapped()
	if err != nil {
		return nil, err
	}
	wo, err := newOverlapped()
	if err != nil {
		return nil, err
	}
	port := new(serialPort)
	port.f = f
	port.fd = h
	port.ro = ro
	port.wo = wo

	return port, nil
}

func (p *serialPort) Close() error {
	return p.f.Close()
}

func (p *serialPort) Write(buf []byte) (int, error) {
	p.wl.Lock()
	defer p.wl.Unlock()

	if err := resetEvent(p.wo.HEvent); err != nil {
		return 0, err
	}
	var n uint32
	err := syscall.WriteFile(p.fd, buf, &n, p.wo)
	if err != nil && err != syscall.ERROR_IO_PENDING {
		return int(n), err
	}
	return getOverlappedResult(p.fd, p.wo)
}

func (p *serialPort) Read(buf []byte) (int, error) {
	if p == nil || p.f == nil {
		return 0, fmt.Errorf("Invalid port on read %v %v", p, p.f)
	}

	p.rl.Lock()
	defer p.rl.Unlock()

	if err := resetEvent(p.ro.HEvent); err != nil {
		return 0, err
	}
	var done uint32
	err := syscall.ReadFile(p.fd, buf, &done, p.ro)
	if err != nil && err != syscall.ERROR_IO_PENDING {
		return int(done), err
	}
	return getOverlappedResult(p.fd, p.ro)
}

var (
	nSetCommState,
	nSetCommTimeouts,
	nSetCommMask,
	nSetupComm,
	nGetOverlappedResult,
	nCreateEvent,
	nResetEvent uintptr
)

func init() {
	k32, err := syscall.LoadLibrary("kernel32.dll")
	if err != nil {
		panic("LoadLibrary " + err.Error())
	}
	defer syscall.FreeLibrary(k32)

	nSetCommState = getProcAddr(k32, "SetCommState")
	nSetCommTimeouts = getProcAddr(k32, "SetCommTimeouts")
	nSetCommMask = getProcAddr(k32, "SetCommMask")
	nSetupComm = getProcAddr(k32, "SetupComm")
	nGetOverlappedResult = getProcAddr(k32, "GetOverlappedResult")
	nCreateEvent = getProcAddr(k32, "CreateEventW")
	nResetEvent = getProcAddr(k32, "ResetEvent")
}

func getProcAddr(lib syscall.Handle, name string) uintptr {
	addr, err := syscall.GetProcAddress(lib, name)
	if err != nil {
		panic(name + " " + err.Error())
	}
	return addr
}

func setCommState(h syscall.Handle, options OpenOptions) error {
	var params structDCB
	params.DCBlength = uint32(unsafe.Sizeof(params))

	params.flags[0] = 0x01  // fBinary
	params.flags[0] |= 0x10 // Assert DSR

	if options.ParityMode != PARITY_NONE {
		params.flags[0] |= 0x03 // fParity
		params.Parity = byte(options.ParityMode)
	}

	if options.StopBits == 1 {
		params.StopBits = 0
	} else if options.StopBits == 2 {
		params.StopBits = 2
	}

	params.BaudRate = uint32(options.BaudRate)
	params.ByteSize = byte(options.DataBits)

	r, _, err := syscall.Syscall(nSetCommState, 2, uintptr(h), uintptr(unsafe.Pointer(&params)), 0)
	if r == 0 {
		return err
	}
	return nil
}

func setCommTimeouts(h syscall.Handle, options OpenOptions) error {
	var timeouts structTimeouts
	const MAXDWORD = 1<<32 - 1
	fmt.Printf("\n options: %+v \n", options)
	timeoutConstant := uint32(round(float64(options.InterCharacterTimeout) / 100.0))
	readIntervalTimeout := uint32(options.MinimumReadSize)
	fmt.Printf("\n timeoutConstant: %d ----  readintervalTimeout: %d\n",
		timeoutConstant, readIntervalTimeout)
	if timeoutConstant > 0 && readIntervalTimeout == 0 {
		//Assume we're setting for non blocking IO.
		timeouts.ReadIntervalTimeout = MAXDWORD
		timeouts.ReadTotalTimeoutMultiplier = MAXDWORD
		timeouts.ReadTotalTimeoutConstant = timeoutConstant
	} else if readIntervalTimeout > 0 {
		// Assume we want to block and wait for input.
		timeouts.ReadIntervalTimeout = readIntervalTimeout
		timeouts.ReadTotalTimeoutMultiplier = 1
		timeouts.ReadTotalTimeoutConstant = 1
	} else {
		// No idea what we intended, use defaults
		// default config does what it did before.
		timeouts.ReadIntervalTimeout = MAXDWORD
		timeouts.ReadTotalTimeoutMultiplier = MAXDWORD
		timeouts.ReadTotalTimeoutConstant = MAXDWORD - 1
	}

	/*
			Empirical testing has shown that to have non-blocking IO we need to set:
				ReadTotalTimeoutConstant > 0 and
				ReadTotalTimeoutMultiplier = MAXDWORD and
				ReadIntervalTimeout = MAXDWORD

				The documentation states that ReadIntervalTimeout is set in MS but
				empirical investigation determines that it seems to interpret in units
				of 100ms.

				If InterCharacterTimeout is set at all it seems that the port will block
				indefinitly until a character is received.  Not all circumstances have been
				tested. The input of an expert would be appreciated.

			From http://msdn.microsoft.com/en-us/library/aa363190(v=VS.85).aspx

			 For blocking I/O see below:

			 Remarks:

			 If an application sets ReadIntervalTimeout and
			 ReadTotalTimeoutMultiplier to MAXDWORD and sets
			 ReadTotalTimeoutConstant to a value greater than zero and
			 less than MAXDWORD, one of the following occurs when the
			 ReadFile function is called:

			 If there are any bytes in the input buffer, ReadFile returns
			       immediately with the bytes in the buffer.

			 If there are no bytes in the input buffer, ReadFile waits
		               until a byte arrives and then returns immediately.

			 If no bytes arrive within the time specified by
			       ReadTotalTimeoutConstant, ReadFile times out.
	*/

	r, _, err := syscall.Syscall(nSetCommTimeouts, 2, uintptr(h), uintptr(unsafe.Pointer(&timeouts)), 0)
	if r == 0 {
		return err
	}
	return nil
}

func setupComm(h syscall.Handle, in, out int) error {
	r, _, err := syscall.Syscall(nSetupComm, 3, uintptr(h), uintptr(in), uintptr(out))
	if r == 0 {
		return err
	}
	return nil
}

func setCommMask(h syscall.Handle) error {
	const EV_RXCHAR = 0x0001
	r, _, err := syscall.Syscall(nSetCommMask, 2, uintptr(h), EV_RXCHAR, 0)
	if r == 0 {
		return err
	}
	return nil
}

func resetEvent(h syscall.Handle) error {
	r, _, err := syscall.Syscall(nResetEvent, 1, uintptr(h), 0, 0)
	if r == 0 {
		return err
	}
	return nil
}

func newOverlapped() (*syscall.Overlapped, error) {
	var overlapped syscall.Overlapped
	r, _, err := syscall.Syscall6(nCreateEvent, 4, 0, 1, 0, 0, 0, 0)
	if r == 0 {
		return nil, err
	}
	overlapped.HEvent = syscall.Handle(r)
	return &overlapped, nil
}

func getOverlappedResult(h syscall.Handle, overlapped *syscall.Overlapped) (int, error) {
	var n int
	r, _, err := syscall.Syscall6(nGetOverlappedResult, 4,
		uintptr(h),
		uintptr(unsafe.Pointer(overlapped)),
		uintptr(unsafe.Pointer(&n)), 1, 0, 0)
	if r == 0 {
		return n, err
	}

	return n, nil
}
<commit_msg>Removed some debugging code<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package serial

import (
	"fmt"
	"io"
	"os"
	"sync"
	"syscall"
	"unsafe"
)

type serialPort struct {
	f  *os.File
	fd syscall.Handle
	rl sync.Mutex
	wl sync.Mutex
	ro *syscall.Overlapped
	wo *syscall.Overlapped
}

type structDCB struct {
	DCBlength, BaudRate                            uint32
	flags                                          [4]byte
	wReserved, XonLim, XoffLim                     uint16
	ByteSize, Parity, StopBits                     byte
	XonChar, XoffChar, ErrorChar, EofChar, EvtChar byte
	wReserved1                                     uint16
}

type structTimeouts struct {
	ReadIntervalTimeout         uint32
	ReadTotalTimeoutMultiplier  uint32
	ReadTotalTimeoutConstant    uint32
	WriteTotalTimeoutMultiplier uint32
	WriteTotalTimeoutConstant   uint32
}

func openInternal(options OpenOptions) (io.ReadWriteCloser, error) {
	if len(options.PortName) > 0 && options.PortName[0] != '\\' {
		options.PortName = "\\\\.\\" + options.PortName
	}

	h, err := syscall.CreateFile(syscall.StringToUTF16Ptr(options.PortName),
		syscall.GENERIC_READ|syscall.GENERIC_WRITE,
		0,
		nil,
		syscall.OPEN_EXISTING,
		syscall.FILE_ATTRIBUTE_NORMAL|syscall.FILE_FLAG_OVERLAPPED,
		0)
	if err != nil {
		return nil, err
	}
	f := os.NewFile(uintptr(h), options.PortName)
	defer func() {
		if err != nil {
			f.Close()
		}
	}()

	if err = setCommState(h, options); err != nil {
		return nil, err
	}
	if err = setupComm(h, 64, 64); err != nil {
		return nil, err
	}
	if err = setCommTimeouts(h, options); err != nil {
		return nil, err
	}
	if err = setCommMask(h); err != nil {
		return nil, err
	}

	ro, err := newOverlapped()
	if err != nil {
		return nil, err
	}
	wo, err := newOverlapped()
	if err != nil {
		return nil, err
	}
	port := new(serialPort)
	port.f = f
	port.fd = h
	port.ro = ro
	port.wo = wo

	return port, nil
}

func (p *serialPort) Close() error {
	return p.f.Close()
}

func (p *serialPort) Write(buf []byte) (int, error) {
	p.wl.Lock()
	defer p.wl.Unlock()

	if err := resetEvent(p.wo.HEvent); err != nil {
		return 0, err
	}
	var n uint32
	err := syscall.WriteFile(p.fd, buf, &n, p.wo)
	if err != nil && err != syscall.ERROR_IO_PENDING {
		return int(n), err
	}
	return getOverlappedResult(p.fd, p.wo)
}

func (p *serialPort) Read(buf []byte) (int, error) {
	if p == nil || p.f == nil {
		return 0, fmt.Errorf("Invalid port on read %v %v", p, p.f)
	}

	p.rl.Lock()
	defer p.rl.Unlock()

	if err := resetEvent(p.ro.HEvent); err != nil {
		return 0, err
	}
	var done uint32
	err := syscall.ReadFile(p.fd, buf, &done, p.ro)
	if err != nil && err != syscall.ERROR_IO_PENDING {
		return int(done), err
	}
	return getOverlappedResult(p.fd, p.ro)
}

var (
	nSetCommState,
	nSetCommTimeouts,
	nSetCommMask,
	nSetupComm,
	nGetOverlappedResult,
	nCreateEvent,
	nResetEvent uintptr
)

func init() {
	k32, err := syscall.LoadLibrary("kernel32.dll")
	if err != nil {
		panic("LoadLibrary " + err.Error())
	}
	defer syscall.FreeLibrary(k32)

	nSetCommState = getProcAddr(k32, "SetCommState")
	nSetCommTimeouts = getProcAddr(k32, "SetCommTimeouts")
	nSetCommMask = getProcAddr(k32, "SetCommMask")
	nSetupComm = getProcAddr(k32, "SetupComm")
	nGetOverlappedResult = getProcAddr(k32, "GetOverlappedResult")
	nCreateEvent = getProcAddr(k32, "CreateEventW")
	nResetEvent = getProcAddr(k32, "ResetEvent")
}

func getProcAddr(lib syscall.Handle, name string) uintptr {
	addr, err := syscall.GetProcAddress(lib, name)
	if err != nil {
		panic(name + " " + err.Error())
	}
	return addr
}

func setCommState(h syscall.Handle, options OpenOptions) error {
	var params structDCB
	params.DCBlength = uint32(unsafe.Sizeof(params))

	params.flags[0] = 0x01  // fBinary
	params.flags[0] |= 0x10 // Assert DSR

	if options.ParityMode != PARITY_NONE {
		params.flags[0] |= 0x03 // fParity
		params.Parity = byte(options.ParityMode)
	}

	if options.StopBits == 1 {
		params.StopBits = 0
	} else if options.StopBits == 2 {
		params.StopBits = 2
	}

	params.BaudRate = uint32(options.BaudRate)
	params.ByteSize = byte(options.DataBits)

	r, _, err := syscall.Syscall(nSetCommState, 2, uintptr(h), uintptr(unsafe.Pointer(&params)), 0)
	if r == 0 {
		return err
	}
	return nil
}

func setCommTimeouts(h syscall.Handle, options OpenOptions) error {
	var timeouts structTimeouts
	const MAXDWORD = 1<<32 - 1
	timeoutConstant := uint32(round(float64(options.InterCharacterTimeout) / 100.0))
	readIntervalTimeout := uint32(options.MinimumReadSize)

	if timeoutConstant > 0 && readIntervalTimeout == 0 {
		//Assume we're setting for non blocking IO.
		timeouts.ReadIntervalTimeout = MAXDWORD
		timeouts.ReadTotalTimeoutMultiplier = MAXDWORD
		timeouts.ReadTotalTimeoutConstant = timeoutConstant
	} else if readIntervalTimeout > 0 {
		// Assume we want to block and wait for input.
		timeouts.ReadIntervalTimeout = readIntervalTimeout
		timeouts.ReadTotalTimeoutMultiplier = 1
		timeouts.ReadTotalTimeoutConstant = 1
	} else {
		// No idea what we intended, use defaults
		// default config does what it did before.
		timeouts.ReadIntervalTimeout = MAXDWORD
		timeouts.ReadTotalTimeoutMultiplier = MAXDWORD
		timeouts.ReadTotalTimeoutConstant = MAXDWORD - 1
	}

	/*
			Empirical testing has shown that to have non-blocking IO we need to set:
				ReadTotalTimeoutConstant > 0 and
				ReadTotalTimeoutMultiplier = MAXDWORD and
				ReadIntervalTimeout = MAXDWORD

				The documentation states that ReadIntervalTimeout is set in MS but
				empirical investigation determines that it seems to interpret in units
				of 100ms.

				If InterCharacterTimeout is set at all it seems that the port will block
				indefinitly until a character is received.  Not all circumstances have been
				tested. The input of an expert would be appreciated.

			From http://msdn.microsoft.com/en-us/library/aa363190(v=VS.85).aspx

			 For blocking I/O see below:

			 Remarks:

			 If an application sets ReadIntervalTimeout and
			 ReadTotalTimeoutMultiplier to MAXDWORD and sets
			 ReadTotalTimeoutConstant to a value greater than zero and
			 less than MAXDWORD, one of the following occurs when the
			 ReadFile function is called:

			 If there are any bytes in the input buffer, ReadFile returns
			       immediately with the bytes in the buffer.

			 If there are no bytes in the input buffer, ReadFile waits
		               until a byte arrives and then returns immediately.

			 If no bytes arrive within the time specified by
			       ReadTotalTimeoutConstant, ReadFile times out.
	*/

	r, _, err := syscall.Syscall(nSetCommTimeouts, 2, uintptr(h), uintptr(unsafe.Pointer(&timeouts)), 0)
	if r == 0 {
		return err
	}
	return nil
}

func setupComm(h syscall.Handle, in, out int) error {
	r, _, err := syscall.Syscall(nSetupComm, 3, uintptr(h), uintptr(in), uintptr(out))
	if r == 0 {
		return err
	}
	return nil
}

func setCommMask(h syscall.Handle) error {
	const EV_RXCHAR = 0x0001
	r, _, err := syscall.Syscall(nSetCommMask, 2, uintptr(h), EV_RXCHAR, 0)
	if r == 0 {
		return err
	}
	return nil
}

func resetEvent(h syscall.Handle) error {
	r, _, err := syscall.Syscall(nResetEvent, 1, uintptr(h), 0, 0)
	if r == 0 {
		return err
	}
	return nil
}

func newOverlapped() (*syscall.Overlapped, error) {
	var overlapped syscall.Overlapped
	r, _, err := syscall.Syscall6(nCreateEvent, 4, 0, 1, 0, 0, 0, 0)
	if r == 0 {
		return nil, err
	}
	overlapped.HEvent = syscall.Handle(r)
	return &overlapped, nil
}

func getOverlappedResult(h syscall.Handle, overlapped *syscall.Overlapped) (int, error) {
	var n int
	r, _, err := syscall.Syscall6(nGetOverlappedResult, 4,
		uintptr(h),
		uintptr(unsafe.Pointer(overlapped)),
		uintptr(unsafe.Pointer(&n)), 1, 0, 0)
	if r == 0 {
		return n, err
	}

	return n, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"code.google.com/p/go-uuid/uuid"
	"fmt"
	"github.com/stealthly/go-avro"
	"github.com/stealthly/go-kafka/producer"
	"github.com/stealthly/go_kafka_client"
	"io/ioutil"
	"math/big"
	"os"
	"os/signal"
	"time"
)

type PingPong struct {
	Counter int64
	Name    string
	Uuid    string
}

//custom string representation to match Scala version. just to simplify reading the console output
func (p *PingPong) String() string {
	return fmt.Sprintf("{\"counter\": %d, \"name\": \"%s\", \"uuid\": \"%s\"}", p.Counter, p.Name, p.Uuid)
}

var schemaRegistry = map[int64]string{
	int64(0): "./scalago.avsc",
}

var readTopic string
var writeTopic string
var group = "ping-pong-go-group"

var broker = "localhost:9092"
var zookeeper = "localhost:2181"

var kafkaProducer *producer.KafkaProducer = nil
var kafkaConsumer *go_kafka_client.Consumer = nil

func main() {
	parseArgs()

	kafkaProducer = producer.NewKafkaProducer(writeTopic, []string{broker})

	//Coordinator settings
	zookeeperConfig := go_kafka_client.NewZookeeperConfig()
	zookeeperConfig.ZookeeperConnect = []string{zookeeper}

	//Actual consumer settings
	consumerConfig := go_kafka_client.DefaultConsumerConfig()
    consumerConfig.AutoOffsetReset = go_kafka_client.SmallestOffset
	consumerConfig.Coordinator = go_kafka_client.NewZookeeperCoordinator(zookeeperConfig)
	consumerConfig.Groupid = group
	consumerConfig.NumWorkers = 1
	consumerConfig.NumConsumerFetchers = 1

	p := &PingPong{}

	consumerConfig.Strategy = func(worker *go_kafka_client.Worker, message *go_kafka_client.Message, taskId go_kafka_client.TaskId) go_kafka_client.WorkerResult {
		time.Sleep(2 * time.Second)
		camus := decode(p, message.Value)
		fmt.Printf("golang > received %v\n", p)
		modify(p)
		if err := kafkaProducer.SendBytesSync(encode(p, camus.schemaId)); err != nil {
			panic(err)
		}

		return go_kafka_client.NewSuccessfulResult(taskId)
	}

    consumerConfig.WorkerFailureCallback = func(_ *go_kafka_client.WorkerManager) go_kafka_client.FailedDecision {
        return go_kafka_client.CommitOffsetAndContinue
    }
    consumerConfig.WorkerFailedAttemptCallback = func(_ *go_kafka_client.Task, _ go_kafka_client.WorkerResult) go_kafka_client.FailedDecision {
        return go_kafka_client.CommitOffsetAndContinue
    }

	kafkaConsumer = go_kafka_client.NewConsumer(consumerConfig)

	pingPongLoop(p)
}

func parseArgs() {
	if len(os.Args) < 3 {
		panic("Usage: go run scala_go_kafka.go $READ_TOPIC $WRITE_TOPIC")
	}

	readTopic = os.Args[1]
	writeTopic = os.Args[2]
}

func pingPongLoop(p *PingPong) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		<-c
		fmt.Println("\ngolang > Closing consumer")
		kafkaConsumer.Close()
	}()

	fmt.Println("golang > Started!")
	kafkaConsumer.StartStatic(map[string]int{
		readTopic: 1,
	})
}

func modify(obj *PingPong) {
	obj.Counter++
	obj.Uuid = uuid.New()
}

func encode(obj *PingPong, schemaId []byte) []byte {
	buffer := &bytes.Buffer{}
	buffer.Write([]byte{CAMUS_MAGIC})
	buffer.Write(schemaId)

	enc := avro.NewBinaryEncoder(buffer)
	writer := avro.NewSpecificDatumWriter()
	writer.SetSchema(schemaById(schemaId))

	writer.Write(obj, enc)

	return buffer.Bytes()
}

func decode(obj interface{}, bytes []byte) *CamusData {
	camus := NewCamusData(bytes)
	camus.Read(obj)
	return camus
}

func schemaById(bytes []byte) avro.Schema {
	id := new(big.Int)
	id.SetBytes(bytes)
	schemaFile := schemaRegistry[id.Int64()]
	if schemaBytes, err := ioutil.ReadFile(schemaFile); err != nil {
		panic(err)
	} else {
		schema, err := avro.ParseSchema(string(schemaBytes))
		if err != nil {
			panic(err)
		}
		return schema
	}
}

var CAMUS_MAGIC byte = byte(0)

type CamusData struct {
	schemaId    []byte
	dec         *avro.BinaryDecoder
	datumReader avro.DatumReader
}

func NewCamusData(data []byte) *CamusData {
	dec := avro.NewBinaryDecoder(data)
	if magic, err := dec.ReadInt(); err != nil {
		panic(err)
	} else {
		if byte(magic) != CAMUS_MAGIC {
			panic("Wrong Camus magic byte")
		}

		schemaIdArray := make([]byte, 4)
		dec.ReadFixed(schemaIdArray)
		schema := schemaById(schemaIdArray)
		datumReader := avro.NewSpecificDatumReader()
		datumReader.SetSchema(schema)

		return &CamusData{schemaIdArray, dec, datumReader}
	}
}

func (cd *CamusData) Read(obj interface{}) {
	cd.datumReader.Read(obj, cd.dec)
}
<commit_msg>integrating with kafka avro encoder/decoder. re #15<commit_after>package main

import (
	"code.google.com/p/go-uuid/uuid"
	"fmt"
	"github.com/stealthly/go-avro"
	"github.com/stealthly/go-kafka/producer"
	"github.com/stealthly/go_kafka_client"
	"os"
	"os/signal"
	"time"
)

var readTopic string
var writeTopic string
var group = "ping-pong-go-group"

var broker = "localhost:9092"
var zookeeper = "localhost:2181"
var schemaRepo = "http://localhost:8081"

var kafkaProducer *producer.KafkaProducer = nil
var kafkaConsumer *go_kafka_client.Consumer = nil

var decoder = go_kafka_client.NewKafkaAvroDecoder(schemaRepo)
var encoder = go_kafka_client.NewKafkaAvroEncoder(schemaRepo)

func main() {
	parseArgs()

	go_kafka_client.Logger = go_kafka_client.NewDefaultLogger(go_kafka_client.ErrorLevel)
	kafkaProducer = producer.NewKafkaProducer(writeTopic, []string{broker})

	//Coordinator settings
	zookeeperConfig := go_kafka_client.NewZookeeperConfig()
	zookeeperConfig.ZookeeperConnect = []string{zookeeper}

	//Actual consumer settings
	consumerConfig := go_kafka_client.DefaultConsumerConfig()
	consumerConfig.AutoOffsetReset = go_kafka_client.SmallestOffset
	consumerConfig.Coordinator = go_kafka_client.NewZookeeperCoordinator(zookeeperConfig)
	consumerConfig.Groupid = group
	consumerConfig.NumWorkers = 1
	consumerConfig.NumConsumerFetchers = 1

	consumerConfig.Strategy = func(worker *go_kafka_client.Worker, message *go_kafka_client.Message, taskId go_kafka_client.TaskId) go_kafka_client.WorkerResult {
		time.Sleep(2 * time.Second)
		recInterface, err := decoder.Decode(message.Value)
		if err != nil {
			panic(err)
		}
		record, ok := recInterface.(*avro.GenericRecord)
		if !ok {
			panic("Not a *GenericError, but expected one")
		}

		fmt.Printf("golang > received %s\n", fmt.Sprintf("{\"counter\": %d, \"name\": \"%s\", \"uuid\": \"%s\"}", record.Get("counter"), record.Get("name"), record.Get("uuid")))
		modify(record)
		encoded, err := encoder.Encode(record)
		if err != nil {
			panic(err)
		}

		if err := kafkaProducer.SendBytesSync(encoded); err != nil {
			panic(err)
		}

		return go_kafka_client.NewSuccessfulResult(taskId)
	}

	consumerConfig.WorkerFailureCallback = func(_ *go_kafka_client.WorkerManager) go_kafka_client.FailedDecision {
		return go_kafka_client.CommitOffsetAndContinue
	}
	consumerConfig.WorkerFailedAttemptCallback = func(_ *go_kafka_client.Task, _ go_kafka_client.WorkerResult) go_kafka_client.FailedDecision {
		return go_kafka_client.CommitOffsetAndContinue
	}

	kafkaConsumer = go_kafka_client.NewConsumer(consumerConfig)

	pingPongLoop()
}

func parseArgs() {
	if len(os.Args) < 3 {
		panic("Usage: go run scala_go_kafka.go $READ_TOPIC $WRITE_TOPIC")
	}

	readTopic = os.Args[1]
	writeTopic = os.Args[2]
}

func pingPongLoop() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		<-c
		fmt.Println("\ngolang > Closing consumer")
		kafkaConsumer.Close()
	}()

	fmt.Println("golang > Started!")
	kafkaConsumer.StartStatic(map[string]int{
		readTopic: 1,
	})
}

func modify(obj *avro.GenericRecord) {
	obj.Set("counter", obj.Get("counter").(int64)+1)
	obj.Set("uuid", uuid.New())
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"

	"github.com/docopt/docopt.go"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/render"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

// Note contains a title and content.
type note struct {
	ID      bson.ObjectId `json:"id" bson:"_id"`
	Subject string        `json:"subject" bson:"subject" binding:"required"`
	Title   string        `json:"title" bson:"title" binding:"required"`
	Content string        `json:"content" bson:"content"`
	Image   []image       `json:"img" bson:"img"`
}

type image struct {
	ID      bson.ObjectId `json:"imgid" bson:"img_id"`
	Type    string        `json:"imgType" bson:"img_type" binding:"required"`
	Content string        `json:"imgContent" bson:"img_content" binding:"required"`
}

type subject struct {
	Subject string `json:"subject" bson:"subject"`
}

type query struct {
	Query   string   `json:"query" bson:"query"`
	Subject []string `json:"subject" bson:"subject"`
	Show    int      `json:"show" bson:"show"`
}

// Return object for title query
type titlelist struct {
	ID    bson.ObjectId `json:"id" bson:"_id"`
	Title string        `json:"title" bson:"title"`
}

func (n *note) getImage(id string) string {
	for _, img := range n.Image {
		if bson.ObjectIdHex(id) == img.ID {
			return img.Content
		}
	}
	return ""
}

func (n *note) getIMGlist() []string {
	list := []string{}
	for _, img := range n.Image {
		list = append(list, img.ID.Hex())
	}
	return list
}

// App returns the ClassicMartini application.
func App() *martini.ClassicMartini {
	m := martini.Classic()
	m.Use(DB())
	m.Use(render.Renderer())
	m.Use(martini.Static("app"))

	m.Post("/search", binding.Bind(query{}), func(q query, r render.Render, log *log.Logger, db *mgo.Database) {
		if q.Query == "" {
			r.JSON(400, map[string]interface{}{"error": "query required"})
			return
		}
		n := []note{}
		if len(q.Subject) > 0 {

			search := bson.M{
				"$and": []bson.M{
					bson.M{"subject": bson.M{"$in": q.Subject}},
					bson.M{"$or": []bson.M{
						bson.M{"title": bson.M{"$regex": q.Query, "$options": "i"}},
						bson.M{"content": bson.M{"$regex": q.Query, "$options": "i"}},
					}},
				},
			}
			err := db.C("notes").Find(search).All(&n)
			if err != nil {
				r.JSON(500, nil)
			}
		} else {
			search := []bson.M{
				bson.M{"title": bson.M{"$regex": q.Query, "$options": "i"}},
				bson.M{"content": bson.M{"$regex": q.Query, "$options": "i"}},
			}
			err := db.C("notes").Find(bson.M{"$or": search}).All(&n)
			if err != nil {
				r.JSON(500, nil)
			}
		}

		total := len(n)
		beg := 0
		end := 10
		if q.Show > 0 {
			end += 10
		}
		if end > total {
			end = total
		}
		r.JSON(200, map[string]interface{}{"count": total, "skip": beg, "results": n[beg:end]})
	})

	m.Group("/notes", func(r martini.Router) {
		r.Post("", binding.Bind(note{}), addNote)
		r.Post("/subject", binding.Bind(subject{}), getNotesBySubject)
		r.Post("/:id", binding.Bind(image{}), postIMG)
		r.Post("/(.*)", noteNotFound)
		r.Get("/subject/:sub", getNotesByTitlelist)
		r.Get("/sublist", getSubList)
		r.Get("/:id/img", getIMGList)
		r.Get("/:id/:imgid", getIMG)
		r.Get("/:id", getNote)
		r.Get("(.*)", noteNotFound)
		r.Put("/:id", binding.Bind(note{}), updateNote)
		r.Put("(.*)", noteNotFound)
		r.Delete("/:id", deleteNote)
		r.Delete("/:id/:imgid", deleteIMG)
		r.Delete("(.*)", noteNotFound)
	})

	m.NotFound(func(r render.Render) {
		r.Redirect("/", 302)
	})

	return m
}

// DB clones a mongodb session and maps it to the current context.
func DB() martini.Handler {
	session, err := mgo.Dial(os.Getenv("PAM_MONGO_URL"))
	if err != nil {
		log.Fatal(err)
	}

	return func(c martini.Context) {
		s := session.Clone()
		c.Map(s.DB("pam"))
		defer s.Close()
		c.Next()
	}
}

func main() {
	arguments, err := docopt.Parse(usage, nil, true, "pam 2.1.0", false)
	if err != nil {
		log.Fatal("Error parsing usage. Error: ", err.Error())
	}

	err = os.Setenv("HOST", arguments["--bind_ip"].(string))
	if err != nil {
		log.Fatal(err.Error())
	}
	err = os.Setenv("PORT", arguments["--bind_port"].(string))
	if err != nil {
		log.Fatal(err.Error())
	}

	App().Run()
}
<commit_msg>Version Update<commit_after>package main

import (
	"log"
	"os"

	"github.com/docopt/docopt.go"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/render"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

// Note contains a title and content.
type note struct {
	ID      bson.ObjectId `json:"id" bson:"_id"`
	Subject string        `json:"subject" bson:"subject" binding:"required"`
	Title   string        `json:"title" bson:"title" binding:"required"`
	Content string        `json:"content" bson:"content"`
	Image   []image       `json:"img" bson:"img"`
}

type image struct {
	ID      bson.ObjectId `json:"imgid" bson:"img_id"`
	Type    string        `json:"imgType" bson:"img_type" binding:"required"`
	Content string        `json:"imgContent" bson:"img_content" binding:"required"`
}

type subject struct {
	Subject string `json:"subject" bson:"subject"`
}

type query struct {
	Query   string   `json:"query" bson:"query"`
	Subject []string `json:"subject" bson:"subject"`
	Show    int      `json:"show" bson:"show"`
}

// Return object for title query
type titlelist struct {
	ID    bson.ObjectId `json:"id" bson:"_id"`
	Title string        `json:"title" bson:"title"`
}

func (n *note) getImage(id string) string {
	for _, img := range n.Image {
		if bson.ObjectIdHex(id) == img.ID {
			return img.Content
		}
	}
	return ""
}

func (n *note) getIMGlist() []string {
	list := []string{}
	for _, img := range n.Image {
		list = append(list, img.ID.Hex())
	}
	return list
}

// App returns the ClassicMartini application.
func App() *martini.ClassicMartini {
	m := martini.Classic()
	m.Use(DB())
	m.Use(render.Renderer())
	m.Use(martini.Static("app"))

	m.Post("/search", binding.Bind(query{}), func(q query, r render.Render, log *log.Logger, db *mgo.Database) {
		if q.Query == "" {
			r.JSON(400, map[string]interface{}{"error": "query required"})
			return
		}
		n := []note{}
		if len(q.Subject) > 0 {

			search := bson.M{
				"$and": []bson.M{
					bson.M{"subject": bson.M{"$in": q.Subject}},
					bson.M{"$or": []bson.M{
						bson.M{"title": bson.M{"$regex": q.Query, "$options": "i"}},
						bson.M{"content": bson.M{"$regex": q.Query, "$options": "i"}},
					}},
				},
			}
			err := db.C("notes").Find(search).All(&n)
			if err != nil {
				r.JSON(500, nil)
			}
		} else {
			search := []bson.M{
				bson.M{"title": bson.M{"$regex": q.Query, "$options": "i"}},
				bson.M{"content": bson.M{"$regex": q.Query, "$options": "i"}},
			}
			err := db.C("notes").Find(bson.M{"$or": search}).All(&n)
			if err != nil {
				r.JSON(500, nil)
			}
		}

		total := len(n)
		beg := 0
		end := 10
		if q.Show > 0 {
			end += 10
		}
		if end > total {
			end = total
		}
		r.JSON(200, map[string]interface{}{"count": total, "skip": beg, "results": n[beg:end]})
	})

	m.Group("/notes", func(r martini.Router) {
		r.Post("", binding.Bind(note{}), addNote)
		r.Post("/subject", binding.Bind(subject{}), getNotesBySubject)
		r.Post("/:id", binding.Bind(image{}), postIMG)
		r.Post("/(.*)", noteNotFound)
		r.Get("/subject/:sub", getNotesByTitlelist)
		r.Get("/sublist", getSubList)
		r.Get("/:id/img", getIMGList)
		r.Get("/:id/:imgid", getIMG)
		r.Get("/:id", getNote)
		r.Get("(.*)", noteNotFound)
		r.Put("/:id", binding.Bind(note{}), updateNote)
		r.Put("(.*)", noteNotFound)
		r.Delete("/:id", deleteNote)
		r.Delete("/:id/:imgid", deleteIMG)
		r.Delete("(.*)", noteNotFound)
	})

	m.NotFound(func(r render.Render) {
		r.Redirect("/", 302)
	})

	return m
}

// DB clones a mongodb session and maps it to the current context.
func DB() martini.Handler {
	session, err := mgo.Dial(os.Getenv("PAM_MONGO_URL"))
	if err != nil {
		log.Fatal(err)
	}

	return func(c martini.Context) {
		s := session.Clone()
		c.Map(s.DB("pam"))
		defer s.Close()
		c.Next()
	}
}

func main() {
	arguments, err := docopt.Parse(usage, nil, true, "pam 2.1.1", false)
	if err != nil {
		log.Fatal("Error parsing usage. Error: ", err.Error())
	}

	err = os.Setenv("HOST", arguments["--bind_ip"].(string))
	if err != nil {
		log.Fatal(err.Error())
	}
	err = os.Setenv("PORT", arguments["--bind_port"].(string))
	if err != nil {
		log.Fatal(err.Error())
	}

	App().Run()
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Kubernetes Authors.

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

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

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

// This suite tests volumes under stress conditions

package testsuites

import (
	"context"
	"sync"

	"github.com/onsi/ginkgo"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	errors "k8s.io/apimachinery/pkg/util/errors"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/kubernetes/test/e2e/framework"
	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
	e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
	"k8s.io/kubernetes/test/e2e/storage/testpatterns"
)

type stressTestSuite struct {
	tsInfo TestSuiteInfo
}

type stressTest struct {
	config        *PerTestConfig
	driverCleanup func()

	intreeOps   opCounts
	migratedOps opCounts

	resources []*VolumeResource
	pods      []*v1.Pod
	// stop and wait for any async routines
	wg      sync.WaitGroup
	stopChs []chan struct{}

	testOptions StressTestOptions
}

var _ TestSuite = &stressTestSuite{}

// InitStressTestSuite returns stressTestSuite that implements TestSuite interface
func InitStressTestSuite() TestSuite {
	return &stressTestSuite{
		tsInfo: TestSuiteInfo{
			Name: "stress",
			TestPatterns: []testpatterns.TestPattern{
				testpatterns.DefaultFsDynamicPV,
				testpatterns.BlockVolModeDynamicPV,
			},
		},
	}
}

func (t *stressTestSuite) GetTestSuiteInfo() TestSuiteInfo {
	return t.tsInfo
}

func (t *stressTestSuite) SkipRedundantSuite(driver TestDriver, pattern testpatterns.TestPattern) {
}

func (t *stressTestSuite) DefineTests(driver TestDriver, pattern testpatterns.TestPattern) {
	var (
		dInfo = driver.GetDriverInfo()
		cs    clientset.Interface
	)

	ginkgo.BeforeEach(func() {
		// Check preconditions.
		if dInfo.StressTestOptions == nil {
			e2eskipper.Skipf("Driver %s doesn't specify stress test options -- skipping", dInfo.Name)
		}

		if _, ok := driver.(DynamicPVTestDriver); !ok {
			e2eskipper.Skipf("Driver %s doesn't implement DynamicPVTestDriver -- skipping", dInfo.Name)
		}

		if !driver.GetDriverInfo().Capabilities[CapBlock] && pattern.VolMode == v1.PersistentVolumeBlock {
			e2eskipper.Skipf("Driver %q does not support block volume mode - skipping", dInfo.Name)
		}
	})

	// This intentionally comes after checking the preconditions because it
	// registers its own BeforeEach which creates the namespace. Beware that it
	// also registers an AfterEach which renders f unusable. Any code using
	// f must run inside an It or Context callback.
	f := framework.NewDefaultFramework("stress")

	init := func() *stressTest {
		cs = f.ClientSet
		l := &stressTest{}

		// Now do the more expensive test initialization.
		l.config, l.driverCleanup = driver.PrepareTest(f)
		l.intreeOps, l.migratedOps = getMigrationVolumeOpCounts(f.ClientSet, dInfo.InTreePluginName)
		l.resources = []*VolumeResource{}
		l.pods = []*v1.Pod{}
		l.stopChs = []chan struct{}{}
		l.testOptions = *dInfo.StressTestOptions

		return l
	}

	cleanup := func(l *stressTest) {
		var errs []error

		framework.Logf("Stopping and waiting for all test routines to finish")
		for _, stopCh := range l.stopChs {
			close(stopCh)
		}
		l.wg.Wait()

		for _, pod := range l.pods {
			framework.Logf("Deleting pod %v", pod.Name)
			err := e2epod.DeletePodWithWait(cs, pod)
			errs = append(errs, err)
		}

		for _, resource := range l.resources {
			errs = append(errs, resource.CleanupResource())
		}

		errs = append(errs, tryFunc(l.driverCleanup))
		framework.ExpectNoError(errors.NewAggregate(errs), "while cleaning up resource")
		validateMigrationVolumeOpCounts(f.ClientSet, dInfo.InTreePluginName, l.intreeOps, l.migratedOps)
	}

	ginkgo.It("multiple pods should access different volumes repeatedly [Slow] [Serial]", func() {
		var err error

		l := init()
		defer func() {
			cleanup(l)
		}()

		for i := 0; i < l.testOptions.NumPods; i++ {
			framework.Logf("Creating resources for pod %v/%v", i, l.testOptions.NumPods-1)
			r := CreateVolumeResource(driver, l.config, pattern, t.GetTestSuiteInfo().SupportedSizeRange)
			l.resources = append(l.resources, r)
			podConfig := e2epod.Config{
				NS:           f.Namespace.Name,
				PVCs:         []*v1.PersistentVolumeClaim{r.Pvc},
				SeLinuxLabel: e2epv.SELinuxLabel,
			}
			pod, err := e2epod.MakeSecPod(&podConfig)
			framework.ExpectNoError(err)

			l.pods = append(l.pods, pod)
			l.stopChs = append(l.stopChs, make(chan struct{}))
		}

		// Restart pod repeatedly
		for i := 0; i < l.testOptions.NumPods; i++ {
			podIndex := i
			l.wg.Add(1)
			go func() {
				defer ginkgo.GinkgoRecover()
				defer l.wg.Done()
				for j := 0; j < l.testOptions.NumRestarts; j++ {
					select {
					case <-l.stopChs[podIndex]:
						return
					default:
						pod := l.pods[podIndex]
						framework.Logf("Pod %v, Iteration %v/%v", podIndex, j, l.testOptions.NumRestarts-1)
						_, err = cs.CoreV1().Pods(pod.Namespace).Create(context.TODO(), pod, metav1.CreateOptions{})
						framework.ExpectNoError(err)

						err = e2epod.WaitForPodRunningInNamespace(cs, pod)
						framework.ExpectNoError(err)

						// TODO: write data per pod and validate it everytime

						err = e2epod.DeletePodWithWait(f.ClientSet, pod)
						framework.ExpectNoError(err)
					}
				}
			}()
		}

		l.wg.Wait()
	})
}
<commit_msg>Fix date race in storage<commit_after>/*
Copyright 2020 The Kubernetes Authors.

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

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

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

// This suite tests volumes under stress conditions

package testsuites

import (
	"context"
	"sync"

	"github.com/onsi/ginkgo"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	errors "k8s.io/apimachinery/pkg/util/errors"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/kubernetes/test/e2e/framework"
	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
	e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
	"k8s.io/kubernetes/test/e2e/storage/testpatterns"
)

type stressTestSuite struct {
	tsInfo TestSuiteInfo
}

type stressTest struct {
	config        *PerTestConfig
	driverCleanup func()

	intreeOps   opCounts
	migratedOps opCounts

	resources []*VolumeResource
	pods      []*v1.Pod
	// stop and wait for any async routines
	wg      sync.WaitGroup
	stopChs []chan struct{}

	testOptions StressTestOptions
}

var _ TestSuite = &stressTestSuite{}

// InitStressTestSuite returns stressTestSuite that implements TestSuite interface
func InitStressTestSuite() TestSuite {
	return &stressTestSuite{
		tsInfo: TestSuiteInfo{
			Name: "stress",
			TestPatterns: []testpatterns.TestPattern{
				testpatterns.DefaultFsDynamicPV,
				testpatterns.BlockVolModeDynamicPV,
			},
		},
	}
}

func (t *stressTestSuite) GetTestSuiteInfo() TestSuiteInfo {
	return t.tsInfo
}

func (t *stressTestSuite) SkipRedundantSuite(driver TestDriver, pattern testpatterns.TestPattern) {
}

func (t *stressTestSuite) DefineTests(driver TestDriver, pattern testpatterns.TestPattern) {
	var (
		dInfo = driver.GetDriverInfo()
		cs    clientset.Interface
	)

	ginkgo.BeforeEach(func() {
		// Check preconditions.
		if dInfo.StressTestOptions == nil {
			e2eskipper.Skipf("Driver %s doesn't specify stress test options -- skipping", dInfo.Name)
		}

		if _, ok := driver.(DynamicPVTestDriver); !ok {
			e2eskipper.Skipf("Driver %s doesn't implement DynamicPVTestDriver -- skipping", dInfo.Name)
		}

		if !driver.GetDriverInfo().Capabilities[CapBlock] && pattern.VolMode == v1.PersistentVolumeBlock {
			e2eskipper.Skipf("Driver %q does not support block volume mode - skipping", dInfo.Name)
		}
	})

	// This intentionally comes after checking the preconditions because it
	// registers its own BeforeEach which creates the namespace. Beware that it
	// also registers an AfterEach which renders f unusable. Any code using
	// f must run inside an It or Context callback.
	f := framework.NewDefaultFramework("stress")

	init := func() *stressTest {
		cs = f.ClientSet
		l := &stressTest{}

		// Now do the more expensive test initialization.
		l.config, l.driverCleanup = driver.PrepareTest(f)
		l.intreeOps, l.migratedOps = getMigrationVolumeOpCounts(f.ClientSet, dInfo.InTreePluginName)
		l.resources = []*VolumeResource{}
		l.pods = []*v1.Pod{}
		l.stopChs = []chan struct{}{}
		l.testOptions = *dInfo.StressTestOptions

		return l
	}

	cleanup := func(l *stressTest) {
		var errs []error

		framework.Logf("Stopping and waiting for all test routines to finish")
		for _, stopCh := range l.stopChs {
			close(stopCh)
		}
		l.wg.Wait()

		for _, pod := range l.pods {
			framework.Logf("Deleting pod %v", pod.Name)
			err := e2epod.DeletePodWithWait(cs, pod)
			errs = append(errs, err)
		}

		for _, resource := range l.resources {
			errs = append(errs, resource.CleanupResource())
		}

		errs = append(errs, tryFunc(l.driverCleanup))
		framework.ExpectNoError(errors.NewAggregate(errs), "while cleaning up resource")
		validateMigrationVolumeOpCounts(f.ClientSet, dInfo.InTreePluginName, l.intreeOps, l.migratedOps)
	}

	ginkgo.It("multiple pods should access different volumes repeatedly [Slow] [Serial]", func() {
		var err error

		l := init()
		defer func() {
			cleanup(l)
		}()

		for i := 0; i < l.testOptions.NumPods; i++ {
			framework.Logf("Creating resources for pod %v/%v", i, l.testOptions.NumPods-1)
			r := CreateVolumeResource(driver, l.config, pattern, t.GetTestSuiteInfo().SupportedSizeRange)
			l.resources = append(l.resources, r)
			podConfig := e2epod.Config{
				NS:           f.Namespace.Name,
				PVCs:         []*v1.PersistentVolumeClaim{r.Pvc},
				SeLinuxLabel: e2epv.SELinuxLabel,
			}
			pod, err := e2epod.MakeSecPod(&podConfig)
			framework.ExpectNoError(err)

			l.pods = append(l.pods, pod)
			l.stopChs = append(l.stopChs, make(chan struct{}))
		}

		// Restart pod repeatedly
		for i := 0; i < l.testOptions.NumPods; i++ {
			podIndex := i
			l.wg.Add(1)
			go func() {
				defer ginkgo.GinkgoRecover()
				defer l.wg.Done()
				for j := 0; j < l.testOptions.NumRestarts; j++ {
					select {
					case <-l.stopChs[podIndex]:
						return
					default:
						pod := l.pods[podIndex]
						framework.Logf("Pod %v, Iteration %v/%v", podIndex, j, l.testOptions.NumRestarts-1)
						_, err := cs.CoreV1().Pods(pod.Namespace).Create(context.TODO(), pod, metav1.CreateOptions{})
						framework.ExpectNoError(err)

						err = e2epod.WaitForPodRunningInNamespace(cs, pod)
						framework.ExpectNoError(err)

						// TODO: write data per pod and validate it everytime

						err = e2epod.DeletePodWithWait(f.ClientSet, pod)
						framework.ExpectNoError(err)
					}
				}
			}()
		}

		l.wg.Wait()
	})
}
<|endoftext|>


<commit_before>package main

import (
	"log"

	xp "github.com/BurntSushi/xgb/xproto"
)

type orientation int

const (
	noOrientation orientation = iota
	horizontal
	vertical
)

type traversal int

const (
	next traversal = iota
	prev
)

type listing int

const (
	listNone listing = iota
	listWindows
	listWorkspaces
)

// offscreenXY is the most negative X/Y co-ordinate.
const offscreenXY = -1 << 15

func contains(r xp.Rectangle, x, y int16) bool {
	return r.X <= x && x <= r.X+int16(r.Width) &&
		r.Y <= y && y <= r.Y+int16(r.Height)
}

func screenContaining(x, y int16) *screen {
	for _, s := range screens {
		if contains(s.rect, x, y) {
			return s
		}
	}
	return screens[0]
}

var (
	screens        []*screen
	dummyWorkspace workspace // The anchor of a doubly-linked list of workspaces.
)

func init() {
	dummyWorkspace.link[next] = &dummyWorkspace
	dummyWorkspace.link[prev] = &dummyWorkspace
}

func findWindow(predicate func(*window) bool) *window {
	for k := dummyWorkspace.link[next]; k != &dummyWorkspace; k = k.link[next] {
		for w := k.dummyWindow.link[next]; w != &k.dummyWindow; w = w.link[next] {
			if predicate(w) {
				return w
			}
		}
	}
	return nil
}

type screen struct {
	workspace *workspace
	rect      xp.Rectangle
}

type workspace struct {
	link         [2]*workspace
	screen       *screen
	focusedFrame *frame
	mainFrame    frame
	dummyWindow  window // The anchor of a doubly-linked list of windows.
	fullscreen   bool
	listing      listing
	list         []interface{}
	index        int
}

type frame struct {
	parent      *frame
	prevSibling *frame
	nextSibling *frame
	firstChild  *frame
	lastChild   *frame
	orientation orientation
	workspace   *workspace
	window      *window
	rect        xp.Rectangle
}

type window struct {
	workspace       *workspace
	frame           *frame
	link            [2]*window
	transientFor    *window
	xWin            xp.Window
	rect            xp.Rectangle
	name            string
	hasTransientFor bool
	seen            bool
	selected        bool
	wmDeleteWindow  bool
	wmTakeFocus     bool
}

func (s *screen) repaint() {
	check(xp.ClearAreaChecked(xConn, true, desktopXWin,
		s.rect.X, s.rect.Y, s.rect.Width+1, s.rect.Height+1))
}

func newWorkspace(s *screen) *workspace {
	k := &workspace{
		screen: s,
		mainFrame: frame{
			rect: s.rect,
		},
		index: -1,
	}
	k.mainFrame.workspace = k
	k.dummyWindow.link[next] = &k.dummyWindow
	k.dummyWindow.link[prev] = &k.dummyWindow
	k.focusedFrame = &k.mainFrame

	if s.workspace != nil {
		k.link[next] = s.workspace.link[next]
		k.link[prev] = s.workspace
	} else {
		k.link[next] = &dummyWorkspace
		k.link[prev] = dummyWorkspace.link[prev]
	}
	k.link[next].link[prev] = k
	k.link[prev].link[next] = k

	k.mainFrame.split(horizontal)
	return k
}

func makeLists() {
	for _, s := range screens {
		if s.workspace.listing != listNone {
			s.workspace.makeList()
		}
	}
}

func (k *workspace) makeList() {
	switch k.listing {
	case listWindows:
		k.list = k.makeWindowList()
	case listWorkspaces:
		k.list = k.makeWorkspaceList()
	default:
		k.list = nil
	}
	k.index = -1
	if len(k.list) != 0 {
		if p, err := xp.QueryPointer(xConn, rootXWin).Reply(); err != nil {
			log.Println(err)
		} else {
			k.index = k.indexForPoint(p.RootX, p.RootY)
		}
	}
	k.configure()
	k.screen.repaint()
}

func (k *workspace) makeWindowList() (list []interface{}) {
	for w := k.dummyWindow.link[next]; w != &k.dummyWindow; w = w.link[next] {
		// TODO: listen instead of poll for name changes.
		w.name = w.property(atomWMName)
		if w.name == "" {
			w.name = "?"
		}
		list = append(list, w)
	}
	return list
}

func (k *workspace) makeWorkspaceList() (list []interface{}) {
	for k := dummyWorkspace.link[next]; k != &dummyWorkspace; k = k.link[next] {
		list = append(list, k)
		list = append(list, k.makeWindowList()...)
	}
	return list
}

func (k *workspace) indexForPoint(rootX, rootY int16) int {
	r := k.focusedFrame.rect
	if k.fullscreen || k.listing == listWorkspaces {
		r = k.mainFrame.rect
	}
	x := int(rootX - r.X)
	y := int(rootY - r.Y)
	if x <= 0 || int(r.Width) <= x || y <= 0 || int(r.Height) <= y {
		return -1
	}
	i := int(y/fontHeight) - 1
	if i < 0 || len(k.list) <= i {
		return -1
	}
	if k.listing == listWorkspaces {
		for ; i >= 0; i-- {
			if _, ok := k.list[i].(*workspace); ok {
				return i
			}
		}
	}
	return i
}

func (k *workspace) configure() {
	for w := k.dummyWindow.link[next]; w != &k.dummyWindow; w = w.link[next] {
		w.configure()
	}
}

func (k *workspace) drawFrameBorders() {
	if k.fullscreen || k.listing == listWorkspaces {
		return
	}
	setForeground(colorUnfocused)
	rects := k.mainFrame.appendRectangles(nil)
	check(xp.PolyRectangleChecked(xConn, xp.Drawable(desktopXWin), desktopXGC, rects))
	setForeground(colorFocused)
	k.focusedFrame.drawBorder()
}

func (k *workspace) focusFrame(f *frame) {
	if f == nil {
		return
	}
	if k.focusedFrame != f {
		setForeground(colorUnfocused)
		k.focusedFrame.drawBorder()
		setForeground(colorFocused)
		f.drawBorder()
		k.focusedFrame = f
	}
	focus(f.window)
}

func (k *workspace) frameContaining(x, y int16) *frame {
	if contains(k.focusedFrame.rect, x, y) {
		return k.focusedFrame
	}
	return k.mainFrame.frameContaining(x, y)
}

func (k *workspace) layout() {
	if k.screen != nil {
		k.mainFrame.rect = k.screen.rect
	} else {
		k.mainFrame.rect = xp.Rectangle{X: offscreenXY, Y: offscreenXY, Width: 256, Height: 256}
	}
	k.mainFrame.layout()
}

func (f *frame) frameContaining(x, y int16) *frame {
	if contains(f.rect, x, y) {
		if f.firstChild == nil {
			return f
		}
		for c := f.firstChild; c != nil; c = c.nextSibling {
			if g := c.frameContaining(x, y); g != nil {
				return g
			}
		}
	}
	return nil
}

func (f *frame) firstDescendent() *frame {
	for f.firstChild != nil {
		f = f.firstChild
	}
	return f
}

func (f *frame) lastDescendent() *frame {
	for f.lastChild != nil {
		f = f.lastChild
	}
	return f
}

func (f *frame) firstEmptyFrame() *frame {
	if f.firstChild != nil {
		for c := f.firstChild; c != nil; c = c.nextSibling {
			if ret := c.firstEmptyFrame(); ret != nil {
				return ret
			}
		}
	} else if f.window == nil {
		return f
	}
	return nil
}

func (f *frame) numChildren() (n int) {
	for c := f.firstChild; c != nil; c = c.nextSibling {
		n++
	}
	return n
}

func (f *frame) appendRectangles(r []xp.Rectangle) []xp.Rectangle {
	if f.firstChild != nil {
		for c := f.firstChild; c != nil; c = c.nextSibling {
			r = c.appendRectangles(r)
		}
		return r
	}
	return append(r, f.rect)
}

func (f *frame) split(o orientation) {
	if f.parent != nil && f.parent.orientation == o {
		g := &frame{
			parent:      f.parent,
			workspace:   f.workspace,
			prevSibling: f,
			nextSibling: f.nextSibling,
		}
		if f.nextSibling != nil {
			f.nextSibling.prevSibling = g
		} else {
			f.parent.lastChild = g
		}
		f.nextSibling = g
		if f.window != nil {
			f.workspace.focusedFrame = g
		}
		f.parent.layout()
		return
	}

	f.orientation = o
	f.firstChild = &frame{
		parent:    f,
		workspace: f.workspace,
	}
	f.lastChild = &frame{
		parent:    f,
		workspace: f.workspace,
	}
	f.firstChild.nextSibling = f.lastChild
	f.lastChild.prevSibling = f.firstChild
	if f.workspace.focusedFrame == f {
		f.workspace.focusedFrame = f.firstChild
	}
	if w := f.window; w != nil {
		f.window = nil
		f.firstChild.window = w
		w.frame = f.firstChild
	}
	f.layout()
}

func (f *frame) layout() {
	if f.orientation == noOrientation {
		if f.window != nil {
			f.window.configure()
		}
		return
	}
	i, n := 0, f.numChildren()
	for c := f.firstChild; c != nil; i, c = i+1, c.nextSibling {
		c.rect = f.rect
		switch f.orientation {
		case horizontal:
			i0 := (i + 0) * int(f.rect.Width) / n
			i1 := (i + 1) * int(f.rect.Width) / n
			c.rect.X += int16(i0)
			c.rect.Width = uint16(i1 - i0)
		case vertical:
			i0 := (i + 0) * int(f.rect.Height) / n
			i1 := (i + 1) * int(f.rect.Height) / n
			c.rect.Y += int16(i0)
			c.rect.Height = uint16(i1 - i0)
		}
		c.layout()
	}
}

func (f *frame) traverse(t traversal) *frame {
	if f.parent == nil {
		return f
	}
	if t == next && f.nextSibling != nil {
		return f.nextSibling.firstDescendent()
	}
	if t == prev && f.prevSibling != nil {
		return f.prevSibling.lastDescendent()
	}
	f, from := f.parent, f
	for {
		switch from {
		case f.parent:
			if f.firstChild == nil {
				return f
			}
			if t == next {
				f, from = f.firstChild, f
			} else {
				f, from = f.lastChild, f
			}
		case f.firstChild:
			if f.prevSibling != nil {
				f, from = f.prevSibling, f
			} else if f.parent != nil {
				f, from = f.parent, f
			} else {
				f, from = f.lastChild, f
			}
		case f.lastChild:
			if f.nextSibling != nil {
				f, from = f.nextSibling, f
			} else if f.parent != nil {
				f, from = f.parent, f
			} else {
				f, from = f.firstChild, f
			}
		case f.prevSibling:
			return f.firstDescendent()
		case f.nextSibling:
			return f.lastDescendent()
		}
	}
	panic("unreachable")
}

func (f *frame) drawBorder() {
	check(xp.PolyRectangleChecked(xConn, xp.Drawable(desktopXWin), desktopXGC,
		[]xp.Rectangle{f.rect}))
}

func (w *window) property(a xp.Atom) string {
	p, err := xp.GetProperty(xConn, false, w.xWin, a, xp.GetPropertyTypeAny, 0, 1<<32-1).Reply()
	if err != nil {
		log.Println(err)
	}
	return string(p.Value)
}

func (w *window) configure() {
	mask, values := uint16(0), []uint32(nil)
	r := xp.Rectangle{X: offscreenXY, Y: offscreenXY, Width: w.rect.Width, Height: w.rect.Height}
	if w.frame != nil && w.frame.workspace.screen != nil {
		k := w.frame.workspace
		if k.listing == listWorkspaces ||
			(k.listing == listWindows && k.focusedFrame == w.frame) {
			// No-op; r is offscreen.
		} else if k.fullscreen {
			if k.focusedFrame == w.frame {
				r.X = k.mainFrame.rect.X
				r.Y = k.mainFrame.rect.Y
				r.Width = k.mainFrame.rect.Width + 2
				r.Height = k.mainFrame.rect.Height + 2
			}
		} else {
			r.X = w.frame.rect.X + 2
			r.Y = w.frame.rect.Y + 2
			r.Width = w.frame.rect.Width - 3
			r.Height = w.frame.rect.Height - 3
		}
	}
	if w.seen && w.rect == r {
		return
	}
	w.rect = r
	if r.X != offscreenXY {
		w.seen = true
		mask = xp.ConfigWindowX |
			xp.ConfigWindowY |
			xp.ConfigWindowWidth |
			xp.ConfigWindowHeight |
			xp.ConfigWindowBorderWidth
		values = []uint32{
			uint32(uint16(r.X)),
			uint32(uint16(r.Y)),
			uint32(r.Width),
			uint32(r.Height),
			0,
		}
	} else {
		mask = xp.ConfigWindowX | xp.ConfigWindowY
		values = []uint32{
			uint32(uint16(r.X)),
			uint32(uint16(r.Y)),
		}
	}
	check(xp.ConfigureWindowChecked(xConn, w.xWin, mask, values))
}
<commit_msg>taowm: fix fullscreen window size off-by-one.<commit_after>package main

import (
	"log"

	xp "github.com/BurntSushi/xgb/xproto"
)

type orientation int

const (
	noOrientation orientation = iota
	horizontal
	vertical
)

type traversal int

const (
	next traversal = iota
	prev
)

type listing int

const (
	listNone listing = iota
	listWindows
	listWorkspaces
)

// offscreenXY is the most negative X/Y co-ordinate.
const offscreenXY = -1 << 15

func contains(r xp.Rectangle, x, y int16) bool {
	return r.X <= x && x <= r.X+int16(r.Width) &&
		r.Y <= y && y <= r.Y+int16(r.Height)
}

func screenContaining(x, y int16) *screen {
	for _, s := range screens {
		if contains(s.rect, x, y) {
			return s
		}
	}
	return screens[0]
}

var (
	screens        []*screen
	dummyWorkspace workspace // The anchor of a doubly-linked list of workspaces.
)

func init() {
	dummyWorkspace.link[next] = &dummyWorkspace
	dummyWorkspace.link[prev] = &dummyWorkspace
}

func findWindow(predicate func(*window) bool) *window {
	for k := dummyWorkspace.link[next]; k != &dummyWorkspace; k = k.link[next] {
		for w := k.dummyWindow.link[next]; w != &k.dummyWindow; w = w.link[next] {
			if predicate(w) {
				return w
			}
		}
	}
	return nil
}

type screen struct {
	workspace *workspace
	rect      xp.Rectangle
}

type workspace struct {
	link         [2]*workspace
	screen       *screen
	focusedFrame *frame
	mainFrame    frame
	dummyWindow  window // The anchor of a doubly-linked list of windows.
	fullscreen   bool
	listing      listing
	list         []interface{}
	index        int
}

type frame struct {
	parent      *frame
	prevSibling *frame
	nextSibling *frame
	firstChild  *frame
	lastChild   *frame
	orientation orientation
	workspace   *workspace
	window      *window
	rect        xp.Rectangle
}

type window struct {
	workspace       *workspace
	frame           *frame
	link            [2]*window
	transientFor    *window
	xWin            xp.Window
	rect            xp.Rectangle
	name            string
	hasTransientFor bool
	seen            bool
	selected        bool
	wmDeleteWindow  bool
	wmTakeFocus     bool
}

func (s *screen) repaint() {
	check(xp.ClearAreaChecked(xConn, true, desktopXWin,
		s.rect.X, s.rect.Y, s.rect.Width+1, s.rect.Height+1))
}

func newWorkspace(s *screen) *workspace {
	k := &workspace{
		screen: s,
		mainFrame: frame{
			rect: s.rect,
		},
		index: -1,
	}
	k.mainFrame.workspace = k
	k.dummyWindow.link[next] = &k.dummyWindow
	k.dummyWindow.link[prev] = &k.dummyWindow
	k.focusedFrame = &k.mainFrame

	if s.workspace != nil {
		k.link[next] = s.workspace.link[next]
		k.link[prev] = s.workspace
	} else {
		k.link[next] = &dummyWorkspace
		k.link[prev] = dummyWorkspace.link[prev]
	}
	k.link[next].link[prev] = k
	k.link[prev].link[next] = k

	k.mainFrame.split(horizontal)
	return k
}

func makeLists() {
	for _, s := range screens {
		if s.workspace.listing != listNone {
			s.workspace.makeList()
		}
	}
}

func (k *workspace) makeList() {
	switch k.listing {
	case listWindows:
		k.list = k.makeWindowList()
	case listWorkspaces:
		k.list = k.makeWorkspaceList()
	default:
		k.list = nil
	}
	k.index = -1
	if len(k.list) != 0 {
		if p, err := xp.QueryPointer(xConn, rootXWin).Reply(); err != nil {
			log.Println(err)
		} else {
			k.index = k.indexForPoint(p.RootX, p.RootY)
		}
	}
	k.configure()
	k.screen.repaint()
}

func (k *workspace) makeWindowList() (list []interface{}) {
	for w := k.dummyWindow.link[next]; w != &k.dummyWindow; w = w.link[next] {
		// TODO: listen instead of poll for name changes.
		w.name = w.property(atomWMName)
		if w.name == "" {
			w.name = "?"
		}
		list = append(list, w)
	}
	return list
}

func (k *workspace) makeWorkspaceList() (list []interface{}) {
	for k := dummyWorkspace.link[next]; k != &dummyWorkspace; k = k.link[next] {
		list = append(list, k)
		list = append(list, k.makeWindowList()...)
	}
	return list
}

func (k *workspace) indexForPoint(rootX, rootY int16) int {
	r := k.focusedFrame.rect
	if k.fullscreen || k.listing == listWorkspaces {
		r = k.mainFrame.rect
	}
	x := int(rootX - r.X)
	y := int(rootY - r.Y)
	if x <= 0 || int(r.Width) <= x || y <= 0 || int(r.Height) <= y {
		return -1
	}
	i := int(y/fontHeight) - 1
	if i < 0 || len(k.list) <= i {
		return -1
	}
	if k.listing == listWorkspaces {
		for ; i >= 0; i-- {
			if _, ok := k.list[i].(*workspace); ok {
				return i
			}
		}
	}
	return i
}

func (k *workspace) configure() {
	for w := k.dummyWindow.link[next]; w != &k.dummyWindow; w = w.link[next] {
		w.configure()
	}
}

func (k *workspace) drawFrameBorders() {
	if k.fullscreen || k.listing == listWorkspaces {
		return
	}
	setForeground(colorUnfocused)
	rects := k.mainFrame.appendRectangles(nil)
	check(xp.PolyRectangleChecked(xConn, xp.Drawable(desktopXWin), desktopXGC, rects))
	setForeground(colorFocused)
	k.focusedFrame.drawBorder()
}

func (k *workspace) focusFrame(f *frame) {
	if f == nil {
		return
	}
	if k.focusedFrame != f {
		setForeground(colorUnfocused)
		k.focusedFrame.drawBorder()
		setForeground(colorFocused)
		f.drawBorder()
		k.focusedFrame = f
	}
	focus(f.window)
}

func (k *workspace) frameContaining(x, y int16) *frame {
	if contains(k.focusedFrame.rect, x, y) {
		return k.focusedFrame
	}
	return k.mainFrame.frameContaining(x, y)
}

func (k *workspace) layout() {
	if k.screen != nil {
		k.mainFrame.rect = k.screen.rect
	} else {
		k.mainFrame.rect = xp.Rectangle{X: offscreenXY, Y: offscreenXY, Width: 256, Height: 256}
	}
	k.mainFrame.layout()
}

func (f *frame) frameContaining(x, y int16) *frame {
	if contains(f.rect, x, y) {
		if f.firstChild == nil {
			return f
		}
		for c := f.firstChild; c != nil; c = c.nextSibling {
			if g := c.frameContaining(x, y); g != nil {
				return g
			}
		}
	}
	return nil
}

func (f *frame) firstDescendent() *frame {
	for f.firstChild != nil {
		f = f.firstChild
	}
	return f
}

func (f *frame) lastDescendent() *frame {
	for f.lastChild != nil {
		f = f.lastChild
	}
	return f
}

func (f *frame) firstEmptyFrame() *frame {
	if f.firstChild != nil {
		for c := f.firstChild; c != nil; c = c.nextSibling {
			if ret := c.firstEmptyFrame(); ret != nil {
				return ret
			}
		}
	} else if f.window == nil {
		return f
	}
	return nil
}

func (f *frame) numChildren() (n int) {
	for c := f.firstChild; c != nil; c = c.nextSibling {
		n++
	}
	return n
}

func (f *frame) appendRectangles(r []xp.Rectangle) []xp.Rectangle {
	if f.firstChild != nil {
		for c := f.firstChild; c != nil; c = c.nextSibling {
			r = c.appendRectangles(r)
		}
		return r
	}
	return append(r, f.rect)
}

func (f *frame) split(o orientation) {
	if f.parent != nil && f.parent.orientation == o {
		g := &frame{
			parent:      f.parent,
			workspace:   f.workspace,
			prevSibling: f,
			nextSibling: f.nextSibling,
		}
		if f.nextSibling != nil {
			f.nextSibling.prevSibling = g
		} else {
			f.parent.lastChild = g
		}
		f.nextSibling = g
		if f.window != nil {
			f.workspace.focusedFrame = g
		}
		f.parent.layout()
		return
	}

	f.orientation = o
	f.firstChild = &frame{
		parent:    f,
		workspace: f.workspace,
	}
	f.lastChild = &frame{
		parent:    f,
		workspace: f.workspace,
	}
	f.firstChild.nextSibling = f.lastChild
	f.lastChild.prevSibling = f.firstChild
	if f.workspace.focusedFrame == f {
		f.workspace.focusedFrame = f.firstChild
	}
	if w := f.window; w != nil {
		f.window = nil
		f.firstChild.window = w
		w.frame = f.firstChild
	}
	f.layout()
}

func (f *frame) layout() {
	if f.orientation == noOrientation {
		if f.window != nil {
			f.window.configure()
		}
		return
	}
	i, n := 0, f.numChildren()
	for c := f.firstChild; c != nil; i, c = i+1, c.nextSibling {
		c.rect = f.rect
		switch f.orientation {
		case horizontal:
			i0 := (i + 0) * int(f.rect.Width) / n
			i1 := (i + 1) * int(f.rect.Width) / n
			c.rect.X += int16(i0)
			c.rect.Width = uint16(i1 - i0)
		case vertical:
			i0 := (i + 0) * int(f.rect.Height) / n
			i1 := (i + 1) * int(f.rect.Height) / n
			c.rect.Y += int16(i0)
			c.rect.Height = uint16(i1 - i0)
		}
		c.layout()
	}
}

func (f *frame) traverse(t traversal) *frame {
	if f.parent == nil {
		return f
	}
	if t == next && f.nextSibling != nil {
		return f.nextSibling.firstDescendent()
	}
	if t == prev && f.prevSibling != nil {
		return f.prevSibling.lastDescendent()
	}
	f, from := f.parent, f
	for {
		switch from {
		case f.parent:
			if f.firstChild == nil {
				return f
			}
			if t == next {
				f, from = f.firstChild, f
			} else {
				f, from = f.lastChild, f
			}
		case f.firstChild:
			if f.prevSibling != nil {
				f, from = f.prevSibling, f
			} else if f.parent != nil {
				f, from = f.parent, f
			} else {
				f, from = f.lastChild, f
			}
		case f.lastChild:
			if f.nextSibling != nil {
				f, from = f.nextSibling, f
			} else if f.parent != nil {
				f, from = f.parent, f
			} else {
				f, from = f.firstChild, f
			}
		case f.prevSibling:
			return f.firstDescendent()
		case f.nextSibling:
			return f.lastDescendent()
		}
	}
	panic("unreachable")
}

func (f *frame) drawBorder() {
	check(xp.PolyRectangleChecked(xConn, xp.Drawable(desktopXWin), desktopXGC,
		[]xp.Rectangle{f.rect}))
}

func (w *window) property(a xp.Atom) string {
	p, err := xp.GetProperty(xConn, false, w.xWin, a, xp.GetPropertyTypeAny, 0, 1<<32-1).Reply()
	if err != nil {
		log.Println(err)
	}
	return string(p.Value)
}

func (w *window) configure() {
	mask, values := uint16(0), []uint32(nil)
	r := xp.Rectangle{X: offscreenXY, Y: offscreenXY, Width: w.rect.Width, Height: w.rect.Height}
	if w.frame != nil && w.frame.workspace.screen != nil {
		k := w.frame.workspace
		if k.listing == listWorkspaces ||
			(k.listing == listWindows && k.focusedFrame == w.frame) {
			// No-op; r is offscreen.
		} else if k.fullscreen {
			if k.focusedFrame == w.frame {
				r.X = k.mainFrame.rect.X
				r.Y = k.mainFrame.rect.Y
				r.Width = k.mainFrame.rect.Width + 1
				r.Height = k.mainFrame.rect.Height + 1
			}
		} else {
			r.X = w.frame.rect.X + 2
			r.Y = w.frame.rect.Y + 2
			r.Width = w.frame.rect.Width - 3
			r.Height = w.frame.rect.Height - 3
		}
	}
	if w.seen && w.rect == r {
		return
	}
	w.rect = r
	if r.X != offscreenXY {
		w.seen = true
		mask = xp.ConfigWindowX |
			xp.ConfigWindowY |
			xp.ConfigWindowWidth |
			xp.ConfigWindowHeight |
			xp.ConfigWindowBorderWidth
		values = []uint32{
			uint32(uint16(r.X)),
			uint32(uint16(r.Y)),
			uint32(r.Width),
			uint32(r.Height),
			0,
		}
	} else {
		mask = xp.ConfigWindowX | xp.ConfigWindowY
		values = []uint32{
			uint32(uint16(r.X)),
			uint32(uint16(r.Y)),
		}
	}
	check(xp.ConfigureWindowChecked(xConn, w.xWin, mask, values))
}
<|endoftext|>