<commit_before>package dtls

import (
	"bytes"
	"fmt"
)

func serverHandshakeHandler(c *Conn) error {
	c.lock.Lock()
	defer c.lock.Unlock()

	for out, fragEpoch := c.fragmentBuffer.pop(); out != nil; out, fragEpoch = c.fragmentBuffer.pop() {
		rawHandshake := &handshake{}
		if err := rawHandshake.unmarshal(out); err != nil {
			return err
		}
		c.handshakeCache.push(out, fragEpoch, rawHandshake.handshakeHeader.messageSequence /* isLocal */, false, c.currFlight.get())

		switch h := rawHandshake.handshakeMessage.(type) {
		case *handshakeMessageClientHello:
			if c.currFlight.get() == flight2 {
				if !bytes.Equal(c.cookie, h.cookie) {
					return errCookieMismatch
				}
				c.localSequenceNumber = 1
				c.currFlight.set(flight4)
				break
			}

			c.remoteRandom = h.random
			if len(h.cipherSuites) == 0 {
				return errCipherSuiteNoIntersection
			}
			c.cipherSuite = h.cipherSuites[0]
			c.currFlight.set(flight2)

		case *handshakeMessageClientKeyExchange:
			if c.currFlight.get() == flight4 {
				c.remoteKeypair = &namedCurveKeypair{namedCurveX25519, h.publicKey, nil}

				serverRandom, err := c.localRandom.marshal()
				if err != nil {
					return err
				}
				clientRandom, err := c.remoteRandom.marshal()
				if err != nil {
					return err
				}
				preMasterSecret, err := prfPreMasterSecret(c.remoteKeypair.publicKey, c.localKeypair.privateKey, c.localKeypair.curve)
				if err != nil {
					return err
				}

				c.keys = prfEncryptionKeys(prfMasterSecret(preMasterSecret, clientRandom, serverRandom), clientRandom, serverRandom)
				c.remoteGCM, err = newAESGCM(c.keys.clientWriteKey)
				if err != nil {
					return err
				}

				c.localGCM, err = newAESGCM(c.keys.serverWriteKey)
				if err != nil {
					return err
				}
			}

		case *handshakeMessageFinished:
			if c.currFlight.get() == flight4 {
				fmt.Println("Handshake finished")
				// TODO: verify
				c.localSequenceNumber = 6
				c.currFlight.set(flight6)
			}

		default:
			return fmt.Errorf("Unhandled handshake %d", h.handshakeType())
		}
	}

	return nil
}

func serverTimerThread(c *Conn) {
	for range c.workerTicker.C {
		switch c.currFlight.get() {
		case flight0:
			// Waiting for ClientHello
		case flight2:
			c.lock.RLock()
			c.internalSend(&recordLayer{
				recordLayerHeader: recordLayerHeader{
					sequenceNumber:  c.localSequenceNumber,
					protocolVersion: protocolVersion1_2,
				},
				content: &handshake{
					// sequenceNumber and messageSequence line up, may need to be re-evaluated
					handshakeHeader: handshakeHeader{
						messageSequence: uint16(c.localSequenceNumber),
					},
					handshakeMessage: &handshakeMessageHelloVerifyRequest{
						version: protocolVersion1_2,
						cookie:  c.cookie,
					},
				},
			}, false)
			c.lock.RUnlock()

		case flight4:
			c.lock.RLock()
			c.internalSend(&recordLayer{
				recordLayerHeader: recordLayerHeader{
					sequenceNumber:  c.localSequenceNumber,
					protocolVersion: protocolVersion1_2,
				},
				content: &handshake{
					// sequenceNumber and messageSequence line up, may need to be re-evaluated
					handshakeHeader: handshakeHeader{
						messageSequence: uint16(c.localSequenceNumber),
					},
					handshakeMessage: &handshakeMessageServerHello{
						version:           protocolVersion1_2,
						random:            c.localRandom,
						cipherSuite:       defaultCipherSuites[0],       // TODO: Pick correct cipher suite
						compressionMethod: defaultCompressionMethods[0], // TODO: Pick correct cipher suite
						extensions: []extension{
							&extensionSupportedGroups{
								supportedGroups: []namedCurve{namedCurveX25519, namedCurveP256},
							},
						},
					}},
			}, false)

			c.internalSend(&recordLayer{
				recordLayerHeader: recordLayerHeader{
					sequenceNumber:  c.localSequenceNumber + 1,
					protocolVersion: protocolVersion1_2,
				},
				content: &handshake{
					// sequenceNumber and messageSequence line up, may need to be re-evaluated
					handshakeHeader: handshakeHeader{
						messageSequence: uint16(c.localSequenceNumber + 1),
					},
					handshakeMessage: &handshakeMessageCertificate{
						certificate: c.localCertificate,
					}},
			}, false)

			serverRandom, err := c.localRandom.marshal()
			if err != nil {
				panic(err)
			}
			clientRandom, err := c.remoteRandom.marshal()
			if err != nil {
				panic(err)
			}

			signature, err := generateKeySignature(clientRandom, serverRandom, c.localKeypair.publicKey, namedCurveP256, c.localPrivateKey)
			if err != nil {
				panic(err)
			}

			c.internalSend(&recordLayer{
				recordLayerHeader: recordLayerHeader{
					sequenceNumber:  c.localSequenceNumber + 2,
					protocolVersion: protocolVersion1_2,
				},
				content: &handshake{
					// sequenceNumber and messageSequence line up, may need to be re-evaluated
					handshakeHeader: handshakeHeader{
						messageSequence: uint16(c.localSequenceNumber + 2),
					},
					handshakeMessage: &handshakeMessageServerKeyExchange{
						ellipticCurveType:  ellipticCurveTypeNamedCurve,
						namedCurve:         namedCurveP256,
						publicKey:          c.localKeypair.publicKey,
						hashAlgorithm:      hashAlgorithmSHA256,
						signature:          signature,
						signatureAlgorithm: signatureAlgorithmECDSA,
					}},
			}, false)

			// TODO: CertificateRequest

			c.internalSend(&recordLayer{
				recordLayerHeader: recordLayerHeader{
					sequenceNumber:  c.localSequenceNumber + 3,
					protocolVersion: protocolVersion1_2,
				},
				content: &handshake{
					// sequenceNumber and messageSequence line up, may need to be re-evaluated
					handshakeHeader: handshakeHeader{
						messageSequence: uint16(c.localSequenceNumber + 3),
					},
					handshakeMessage: &handshakeMessageServerHelloDone{},
				},
			}, false)
			c.lock.RUnlock()

		case flight6:
			c.lock.RLock()
			c.internalSend(&recordLayer{
				recordLayerHeader: recordLayerHeader{
					sequenceNumber:  c.localSequenceNumber,
					protocolVersion: protocolVersion1_2,
				},
				content: &changeCipherSpec{},
			}, false)

			if len(c.localVerifyData) == 0 {
				c.localVerifyData = prfVerifyDataClient(c.keys.masterSecret, c.handshakeCache.combinedHandshake())
			}

			c.internalSend(&recordLayer{
				recordLayerHeader: recordLayerHeader{
					epoch:           1,
					sequenceNumber:  0, // sequenceNumber restarts per epoch
					protocolVersion: protocolVersion1_2,
				},
				content: &handshake{
					// sequenceNumber and messageSequence line up, may need to be re-evaluated
					handshakeHeader: handshakeHeader{
						messageSequence: uint16(c.localSequenceNumber), // KeyExchange + 1
					},

					handshakeMessage: &handshakeMessageFinished{
						verifyData: c.localVerifyData,
					}},
			}, true)
			c.lock.RUnlock()

		default:
			panic(fmt.Errorf("Unhandled flight %s", c.currFlight.get()))
		}
	}
}
<commit_msg>Use X25519, not P256 for key signature<commit_after>package dtls

import (
	"bytes"
	"fmt"
)

func serverHandshakeHandler(c *Conn) error {
	c.lock.Lock()
	defer c.lock.Unlock()

	for out, fragEpoch := c.fragmentBuffer.pop(); out != nil; out, fragEpoch = c.fragmentBuffer.pop() {
		rawHandshake := &handshake{}
		if err := rawHandshake.unmarshal(out); err != nil {
			return err
		}
		c.handshakeCache.push(out, fragEpoch, rawHandshake.handshakeHeader.messageSequence /* isLocal */, false, c.currFlight.get())

		switch h := rawHandshake.handshakeMessage.(type) {
		case *handshakeMessageClientHello:
			if c.currFlight.get() == flight2 {
				if !bytes.Equal(c.cookie, h.cookie) {
					return errCookieMismatch
				}
				c.localSequenceNumber = 1
				c.currFlight.set(flight4)
				break
			}

			c.remoteRandom = h.random
			if len(h.cipherSuites) == 0 {
				return errCipherSuiteNoIntersection
			}
			c.cipherSuite = h.cipherSuites[0]
			c.currFlight.set(flight2)

		case *handshakeMessageClientKeyExchange:
			if c.currFlight.get() == flight4 {
				c.remoteKeypair = &namedCurveKeypair{namedCurveX25519, h.publicKey, nil}

				serverRandom, err := c.localRandom.marshal()
				if err != nil {
					return err
				}
				clientRandom, err := c.remoteRandom.marshal()
				if err != nil {
					return err
				}
				preMasterSecret, err := prfPreMasterSecret(c.remoteKeypair.publicKey, c.localKeypair.privateKey, c.localKeypair.curve)
				if err != nil {
					return err
				}

				c.keys = prfEncryptionKeys(prfMasterSecret(preMasterSecret, clientRandom, serverRandom), clientRandom, serverRandom)
				c.remoteGCM, err = newAESGCM(c.keys.clientWriteKey)
				if err != nil {
					return err
				}

				c.localGCM, err = newAESGCM(c.keys.serverWriteKey)
				if err != nil {
					return err
				}
			}

		case *handshakeMessageFinished:
			if c.currFlight.get() == flight4 {
				fmt.Println("Handshake finished")
				// TODO: verify
				c.localSequenceNumber = 6
				c.currFlight.set(flight6)
			}

		default:
			return fmt.Errorf("Unhandled handshake %d", h.handshakeType())
		}
	}

	return nil
}

func serverTimerThread(c *Conn) {
	for range c.workerTicker.C {
		switch c.currFlight.get() {
		case flight0:
			// Waiting for ClientHello
		case flight2:
			c.lock.RLock()
			c.internalSend(&recordLayer{
				recordLayerHeader: recordLayerHeader{
					sequenceNumber:  c.localSequenceNumber,
					protocolVersion: protocolVersion1_2,
				},
				content: &handshake{
					// sequenceNumber and messageSequence line up, may need to be re-evaluated
					handshakeHeader: handshakeHeader{
						messageSequence: uint16(c.localSequenceNumber),
					},
					handshakeMessage: &handshakeMessageHelloVerifyRequest{
						version: protocolVersion1_2,
						cookie:  c.cookie,
					},
				},
			}, false)
			c.lock.RUnlock()

		case flight4:
			c.lock.RLock()
			c.internalSend(&recordLayer{
				recordLayerHeader: recordLayerHeader{
					sequenceNumber:  c.localSequenceNumber,
					protocolVersion: protocolVersion1_2,
				},
				content: &handshake{
					// sequenceNumber and messageSequence line up, may need to be re-evaluated
					handshakeHeader: handshakeHeader{
						messageSequence: uint16(c.localSequenceNumber),
					},
					handshakeMessage: &handshakeMessageServerHello{
						version:           protocolVersion1_2,
						random:            c.localRandom,
						cipherSuite:       defaultCipherSuites[0],       // TODO: Pick correct cipher suite
						compressionMethod: defaultCompressionMethods[0], // TODO: Pick correct cipher suite
						extensions: []extension{
							&extensionSupportedGroups{
								supportedGroups: []namedCurve{namedCurveX25519, namedCurveP256},
							},
						},
					}},
			}, false)

			c.internalSend(&recordLayer{
				recordLayerHeader: recordLayerHeader{
					sequenceNumber:  c.localSequenceNumber + 1,
					protocolVersion: protocolVersion1_2,
				},
				content: &handshake{
					// sequenceNumber and messageSequence line up, may need to be re-evaluated
					handshakeHeader: handshakeHeader{
						messageSequence: uint16(c.localSequenceNumber + 1),
					},
					handshakeMessage: &handshakeMessageCertificate{
						certificate: c.localCertificate,
					}},
			}, false)

			serverRandom, err := c.localRandom.marshal()
			if err != nil {
				panic(err)
			}
			clientRandom, err := c.remoteRandom.marshal()
			if err != nil {
				panic(err)
			}

			signature, err := generateKeySignature(clientRandom, serverRandom, c.localKeypair.publicKey, namedCurveX25519, c.localPrivateKey)
			if err != nil {
				panic(err)
			}

			c.internalSend(&recordLayer{
				recordLayerHeader: recordLayerHeader{
					sequenceNumber:  c.localSequenceNumber + 2,
					protocolVersion: protocolVersion1_2,
				},
				content: &handshake{
					// sequenceNumber and messageSequence line up, may need to be re-evaluated
					handshakeHeader: handshakeHeader{
						messageSequence: uint16(c.localSequenceNumber + 2),
					},
					handshakeMessage: &handshakeMessageServerKeyExchange{
						ellipticCurveType:  ellipticCurveTypeNamedCurve,
						namedCurve:         namedCurveX25519,
						publicKey:          c.localKeypair.publicKey,
						hashAlgorithm:      hashAlgorithmSHA256,
						signature:          signature,
						signatureAlgorithm: signatureAlgorithmECDSA,
					}},
			}, false)

			// TODO: CertificateRequest

			c.internalSend(&recordLayer{
				recordLayerHeader: recordLayerHeader{
					sequenceNumber:  c.localSequenceNumber + 3,
					protocolVersion: protocolVersion1_2,
				},
				content: &handshake{
					// sequenceNumber and messageSequence line up, may need to be re-evaluated
					handshakeHeader: handshakeHeader{
						messageSequence: uint16(c.localSequenceNumber + 3),
					},
					handshakeMessage: &handshakeMessageServerHelloDone{},
				},
			}, false)
			c.lock.RUnlock()

		case flight6:
			c.lock.RLock()
			c.internalSend(&recordLayer{
				recordLayerHeader: recordLayerHeader{
					sequenceNumber:  c.localSequenceNumber,
					protocolVersion: protocolVersion1_2,
				},
				content: &changeCipherSpec{},
			}, false)

			if len(c.localVerifyData) == 0 {
				c.localVerifyData = prfVerifyDataClient(c.keys.masterSecret, c.handshakeCache.combinedHandshake())
			}

			c.internalSend(&recordLayer{
				recordLayerHeader: recordLayerHeader{
					epoch:           1,
					sequenceNumber:  0, // sequenceNumber restarts per epoch
					protocolVersion: protocolVersion1_2,
				},
				content: &handshake{
					// sequenceNumber and messageSequence line up, may need to be re-evaluated
					handshakeHeader: handshakeHeader{
						messageSequence: uint16(c.localSequenceNumber), // KeyExchange + 1
					},

					handshakeMessage: &handshakeMessageFinished{
						verifyData: c.localVerifyData,
					}},
			}, true)
			c.lock.RUnlock()

		default:
			panic(fmt.Errorf("Unhandled flight %s", c.currFlight.get()))
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 Authors of Cilium
//
// 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 cache

import (
	"fmt"

	"github.com/cilium/cilium/pkg/identity"
	"github.com/cilium/cilium/pkg/kvstore"
	"github.com/cilium/cilium/pkg/kvstore/allocator"
	"github.com/cilium/cilium/pkg/labels"
	"github.com/cilium/cilium/pkg/lock"
)

type localIdentityCache struct {
	mutex               lock.RWMutex
	identitiesByID      map[identity.NumericIdentity]*identity.Identity
	identitiesByLabels  map[string]*identity.Identity
	nextNumericIdentity identity.NumericIdentity
	minID               identity.NumericIdentity
	maxID               identity.NumericIdentity
	events              allocator.AllocatorEventChan
}

func newLocalIdentityCache(minID, maxID identity.NumericIdentity, events allocator.AllocatorEventChan) *localIdentityCache {
	return &localIdentityCache{
		identitiesByID:      map[identity.NumericIdentity]*identity.Identity{},
		identitiesByLabels:  map[string]*identity.Identity{},
		nextNumericIdentity: minID,
		minID:               minID,
		maxID:               maxID,
		events:              events,
	}
}

func (l *localIdentityCache) bumpNextNumericIdentity() {
	if l.nextNumericIdentity == l.maxID {
		l.nextNumericIdentity = l.minID
	} else {
		l.nextNumericIdentity++
	}
}

// getNextFreeNumericIdentity returns the next available numeric identity or an error
// The l.mutex must be held
func (l *localIdentityCache) getNextFreeNumericIdentity() (identity.NumericIdentity, error) {
	firstID := l.nextNumericIdentity
	for {
		idCandidate := l.nextNumericIdentity | identity.LocalIdentityFlag
		if _, ok := l.identitiesByID[idCandidate]; !ok {
			l.bumpNextNumericIdentity()
			return idCandidate, nil
		}

		l.bumpNextNumericIdentity()
		if l.nextNumericIdentity == firstID {
			return 0, fmt.Errorf("out of local identity space")
		}
	}
}

// lookupOrCreate searches for the existence of a local identity with the given
// labels. If it exists, the reference count is incremented and the identity is
// returned. If it does not exist, a new identity is created with a unique
// numeric identity. All identities returned by lookupOrCreate() must be
// released again via localIdentityCache.release().
func (l *localIdentityCache) lookupOrCreate(lbls labels.Labels) (*identity.Identity, bool, error) {
	l.mutex.Lock()
	defer l.mutex.Unlock()

	stringRepresentation := string(lbls.SortedList())
	if id, ok := l.identitiesByLabels[stringRepresentation]; ok {
		id.ReferenceCount++
		return id, false, nil
	}

	numericIdentity, err := l.getNextFreeNumericIdentity()
	if err != nil {
		return nil, false, err
	}

	id := &identity.Identity{
		ID:             numericIdentity,
		Labels:         lbls,
		LabelArray:     lbls.LabelArray(),
		ReferenceCount: 1,
	}

	l.identitiesByLabels[stringRepresentation] = id
	l.identitiesByID[numericIdentity] = id

	if l.events != nil {
		l.events <- allocator.AllocatorEvent{
			Typ: kvstore.EventTypeCreate,
		}
	}

	return id, true, nil
}

// release releases a local identity from the cache. true is returned when the
// last use of the identity has been released and the identity has been
// forgotten.
func (l *localIdentityCache) release(id *identity.Identity) bool {
	l.mutex.Lock()
	defer l.mutex.Unlock()

	stringRepresentation := string(id.Labels.SortedList())
	if id, ok := l.identitiesByLabels[stringRepresentation]; ok {
		switch {
		case id.ReferenceCount > 1:
			id.ReferenceCount--
			return false

		case id.ReferenceCount == 1:
			// Release is only attempted once, when the reference count is
			// hitting the last use
			stringRepresentation := string(id.Labels.SortedList())
			delete(l.identitiesByLabels, stringRepresentation)
			delete(l.identitiesByID, id.ID)

			if l.events != nil {
				l.events <- allocator.AllocatorEvent{
					Typ: kvstore.EventTypeDelete,
				}
			}

			return true
		}
	}

	return false
}

// lookup searches for a local identity matching the given labels and returns
// it. If found, the reference count is NOT incremented and thus release must
// NOT be called.
func (l *localIdentityCache) lookup(lbls labels.Labels) *identity.Identity {
	l.mutex.RLock()
	defer l.mutex.RUnlock()

	stringRepresentation := string(lbls.SortedList())
	if id, ok := l.identitiesByLabels[stringRepresentation]; ok {
		return id
	}

	return nil
}

// lookupByID searches for a local identity matching the given ID and returns
// it. If found, the reference count is NOT incremented and thus release must
// NOT be called.
func (l *localIdentityCache) lookupByID(id identity.NumericIdentity) *identity.Identity {
	l.mutex.RLock()
	defer l.mutex.RUnlock()

	if id, ok := l.identitiesByID[id]; ok {
		return id
	}

	return nil
}

// GetIdentities returns all local identities
func (l *localIdentityCache) GetIdentities() map[identity.NumericIdentity]*identity.Identity {
	cache := map[identity.NumericIdentity]*identity.Identity{}

	l.mutex.RLock()
	defer l.mutex.RUnlock()

	for key, id := range l.identitiesByID {
		cache[key] = id
	}

	return cache
}
<commit_msg>identity: Include event details also for local identities<commit_after>// Copyright 2018 Authors of Cilium
//
// 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 cache

import (
	"fmt"

	"github.com/cilium/cilium/pkg/identity"
	"github.com/cilium/cilium/pkg/idpool"
	"github.com/cilium/cilium/pkg/kvstore"
	"github.com/cilium/cilium/pkg/kvstore/allocator"
	"github.com/cilium/cilium/pkg/labels"
	"github.com/cilium/cilium/pkg/lock"
)

type localIdentityCache struct {
	mutex               lock.RWMutex
	identitiesByID      map[identity.NumericIdentity]*identity.Identity
	identitiesByLabels  map[string]*identity.Identity
	nextNumericIdentity identity.NumericIdentity
	minID               identity.NumericIdentity
	maxID               identity.NumericIdentity
	events              allocator.AllocatorEventChan
}

func newLocalIdentityCache(minID, maxID identity.NumericIdentity, events allocator.AllocatorEventChan) *localIdentityCache {
	return &localIdentityCache{
		identitiesByID:      map[identity.NumericIdentity]*identity.Identity{},
		identitiesByLabels:  map[string]*identity.Identity{},
		nextNumericIdentity: minID,
		minID:               minID,
		maxID:               maxID,
		events:              events,
	}
}

func (l *localIdentityCache) bumpNextNumericIdentity() {
	if l.nextNumericIdentity == l.maxID {
		l.nextNumericIdentity = l.minID
	} else {
		l.nextNumericIdentity++
	}
}

// getNextFreeNumericIdentity returns the next available numeric identity or an error
// The l.mutex must be held
func (l *localIdentityCache) getNextFreeNumericIdentity() (identity.NumericIdentity, error) {
	firstID := l.nextNumericIdentity
	for {
		idCandidate := l.nextNumericIdentity | identity.LocalIdentityFlag
		if _, ok := l.identitiesByID[idCandidate]; !ok {
			l.bumpNextNumericIdentity()
			return idCandidate, nil
		}

		l.bumpNextNumericIdentity()
		if l.nextNumericIdentity == firstID {
			return 0, fmt.Errorf("out of local identity space")
		}
	}
}

// lookupOrCreate searches for the existence of a local identity with the given
// labels. If it exists, the reference count is incremented and the identity is
// returned. If it does not exist, a new identity is created with a unique
// numeric identity. All identities returned by lookupOrCreate() must be
// released again via localIdentityCache.release().
func (l *localIdentityCache) lookupOrCreate(lbls labels.Labels) (*identity.Identity, bool, error) {
	l.mutex.Lock()
	defer l.mutex.Unlock()

	stringRepresentation := string(lbls.SortedList())
	if id, ok := l.identitiesByLabels[stringRepresentation]; ok {
		id.ReferenceCount++
		return id, false, nil
	}

	numericIdentity, err := l.getNextFreeNumericIdentity()
	if err != nil {
		return nil, false, err
	}

	id := &identity.Identity{
		ID:             numericIdentity,
		Labels:         lbls,
		LabelArray:     lbls.LabelArray(),
		ReferenceCount: 1,
	}

	l.identitiesByLabels[stringRepresentation] = id
	l.identitiesByID[numericIdentity] = id

	if l.events != nil {
		l.events <- allocator.AllocatorEvent{
			Typ: kvstore.EventTypeCreate,
			ID:  idpool.ID(id.ID),
			Key: globalIdentity{id.LabelArray},
		}
	}

	return id, true, nil
}

// release releases a local identity from the cache. true is returned when the
// last use of the identity has been released and the identity has been
// forgotten.
func (l *localIdentityCache) release(id *identity.Identity) bool {
	l.mutex.Lock()
	defer l.mutex.Unlock()

	stringRepresentation := string(id.Labels.SortedList())
	if id, ok := l.identitiesByLabels[stringRepresentation]; ok {
		switch {
		case id.ReferenceCount > 1:
			id.ReferenceCount--
			return false

		case id.ReferenceCount == 1:
			// Release is only attempted once, when the reference count is
			// hitting the last use
			stringRepresentation := string(id.Labels.SortedList())
			delete(l.identitiesByLabels, stringRepresentation)
			delete(l.identitiesByID, id.ID)

			if l.events != nil {
				l.events <- allocator.AllocatorEvent{
					Typ: kvstore.EventTypeDelete,
					ID:  idpool.ID(id.ID),
				}
			}

			return true
		}
	}

	return false
}

// lookup searches for a local identity matching the given labels and returns
// it. If found, the reference count is NOT incremented and thus release must
// NOT be called.
func (l *localIdentityCache) lookup(lbls labels.Labels) *identity.Identity {
	l.mutex.RLock()
	defer l.mutex.RUnlock()

	stringRepresentation := string(lbls.SortedList())
	if id, ok := l.identitiesByLabels[stringRepresentation]; ok {
		return id
	}

	return nil
}

// lookupByID searches for a local identity matching the given ID and returns
// it. If found, the reference count is NOT incremented and thus release must
// NOT be called.
func (l *localIdentityCache) lookupByID(id identity.NumericIdentity) *identity.Identity {
	l.mutex.RLock()
	defer l.mutex.RUnlock()

	if id, ok := l.identitiesByID[id]; ok {
		return id
	}

	return nil
}

// GetIdentities returns all local identities
func (l *localIdentityCache) GetIdentities() map[identity.NumericIdentity]*identity.Identity {
	cache := map[identity.NumericIdentity]*identity.Identity{}

	l.mutex.RLock()
	defer l.mutex.RUnlock()

	for key, id := range l.identitiesByID {
		cache[key] = id
	}

	return cache
}
<|endoftext|>


<commit_before>/*
Copyright 2013 The Camlistore Authors.

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

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

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

// Package closure provides tools to help with the use of the
// closure library.
//
// See https://code.google.com/p/closure-library/
package closure

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
	"regexp"
	"strings"
	"sync"
	"time"
)

// GenDeps returns the namespace dependencies between the closure javascript files in root. It does not descend in directories.
// Each of the files listed in the output is prepended with the path "../../", which is assumed to be the location where these files can be found, relative to Closure's base.js.
//
// The format for each relevant javascript file is:
// goog.addDependency("filepath", ["namespace provided"], ["required namespace 1", "required namespace 2", ...]);
func GenDeps(root http.FileSystem) ([]byte, error) {
	// In the typical configuration, Closure is served at 'closure/goog/...''
	return GenDepsWithPath("../../", root)
}

// GenDepsWithPath is like GenDeps, but you can specify a path where the files are to be found at runtime relative to Closure's base.js.
func GenDepsWithPath(pathPrefix string, root http.FileSystem) ([]byte, error) {
	d, err := root.Open("/")
	if err != nil {
		return nil, fmt.Errorf("Failed to open root of %v: %v", root, err)
	}
	fi, err := d.Stat()
	if err != nil {
		return nil, err
	}
	if !fi.IsDir() {
		return nil, fmt.Errorf("root of %v is not a dir", root)
	}
	ent, err := d.Readdir(-1)
	if err != nil {
		return nil, fmt.Errorf("Could not read dir entries of root: %v", err)
	}
	var buf bytes.Buffer
	for _, info := range ent {
		name := info.Name()
		if !strings.HasSuffix(name, ".js") {
			continue
		}
		f, err := root.Open(name)
		if err != nil {
			return nil, fmt.Errorf("Could not open %v: %v", name, err)
		}
		prov, req, err := parseProvidesRequires(info, name, f)
		f.Close()
		if err != nil {
			return nil, fmt.Errorf("Could not parse deps for %v: %v", name, err)
		}
		if len(prov) > 0 {
			fmt.Fprintf(&buf, "goog.addDependency(%q, %v, %v);\n", pathPrefix+name, jsList(prov), jsList(req))
		}
	}
	return buf.Bytes(), nil
}

var provReqRx = regexp.MustCompile(`^goog\.(provide|require)\(['"]([\w\.]+)['"]\)`)

type depCacheItem struct {
	modTime            time.Time
	provides, requires []string
}

var (
	depCacheMu sync.Mutex
	depCache   = map[string]depCacheItem{}
)

func parseProvidesRequires(fi os.FileInfo, path string, f io.Reader) (provides, requires []string, err error) {
	mt := fi.ModTime()
	depCacheMu.Lock()
	defer depCacheMu.Unlock()
	if ci := depCache[path]; ci.modTime.Equal(mt) {
		return ci.provides, ci.requires, nil
	}

	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		l := scanner.Text()
		if !strings.HasPrefix(l, "goog.") {
			continue
		}
		m := provReqRx.FindStringSubmatch(l)
		if m != nil {
			if m[1] == "provide" {
				provides = append(provides, m[2])
			} else {
				requires = append(requires, m[2])
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, nil, err
	}
	depCache[path] = depCacheItem{provides: provides, requires: requires, modTime: mt}
	return provides, requires, nil
}

// jsList prints a list of strings as JavaScript list.
type jsList []string

func (s jsList) String() string {
	var buf bytes.Buffer
	buf.WriteByte('[')
	for i, v := range s {
		if i > 0 {
			buf.WriteString(", ")
		}
		fmt.Fprintf(&buf, "%q", v)
	}
	buf.WriteByte(']')
	return buf.String()
}

// Example of a match:
// goog.addDependency('asserts/asserts.js', ['goog.asserts', 'goog.asserts.AssertionError'], ['goog.debug.Error', 'goog.string']);
// So with m := depsRx.FindStringSubmatch,
// the provider: m[1] == "asserts/asserts.js"
// the provided namespaces: m[2] == "'goog.asserts', 'goog.asserts.AssertionError'"
// the required namespaces: m[5] == "'goog.debug.Error', 'goog.string'"
var depsRx = regexp.MustCompile(`^goog.addDependency\(['"]([^/]+[a-zA-Z0-9\-\_/\.]*\.js)['"], \[((['"][\w\.]+['"])+(, ['"][\w\.]+['"])*)\], \[((['"][\w\.]+['"])+(, ['"][\w\.]+['"])*)?\]\);`)

// ParseDeps reads closure namespace dependency lines and
// returns a map giving the js file provider for each namespace,
// and a map giving the namespace dependencies for each namespace.
func ParseDeps(r io.Reader) (providedBy map[string]string, requires map[string][]string, err error) {
	providedBy = make(map[string]string)
	requires = make(map[string][]string)
	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		l := scanner.Text()
		if strings.HasPrefix(l, "//") {
			continue
		}
		if l == "" {
			continue
		}
		m := depsRx.FindStringSubmatch(l)
		if m == nil {
			return nil, nil, fmt.Errorf("Invalid line in deps: %q", l)
		}
		jsfile := m[1]
		provides := strings.Split(m[2], ", ")
		var required []string
		if m[5] != "" {
			required = strings.Split(
				strings.Replace(strings.Replace(m[5], "'", "", -1), `"`, "", -1), ", ")
		}
		for _, v := range provides {
			namespace := strings.Trim(v, `'"`)
			if otherjs, ok := providedBy[namespace]; ok {
				return nil, nil, fmt.Errorf("Name %v is provided by both %v and %v", namespace, jsfile, otherjs)
			}
			providedBy[namespace] = jsfile
			if _, ok := requires[namespace]; ok {
				return nil, nil, fmt.Errorf("Name %v has two sets of dependencies")
			}
			if required != nil {
				requires[namespace] = required
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, nil, err
	}
	return providedBy, requires, nil
}

// DeepParseDeps reads closure namespace dependency lines and
// returns a map giving all the required js files for each namespace.
func DeepParseDeps(r io.Reader) (map[string][]string, error) {
	providedBy, requires, err := ParseDeps(r)
	if err != nil {
		return nil, err
	}
	filesDeps := make(map[string][]string)
	var deeperDeps func(namespace string) []string
	deeperDeps = func(namespace string) []string {
		if jsdeps, ok := filesDeps[namespace]; ok {
			return jsdeps
		}
		jsfiles := []string{providedBy[namespace]}
		for _, dep := range requires[namespace] {
			jsfiles = append(jsfiles, deeperDeps(dep)...)
		}
		return jsfiles
	}
	for namespace, _ := range providedBy {
		filesDeps[namespace] = deeperDeps(namespace)
	}
	return filesDeps, nil
}
<commit_msg>closure: ignore emacs temp files in gendeps<commit_after>/*
Copyright 2013 The Camlistore Authors.

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

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

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

// Package closure provides tools to help with the use of the
// closure library.
//
// See https://code.google.com/p/closure-library/
package closure

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
	"regexp"
	"strings"
	"sync"
	"time"
)

// GenDeps returns the namespace dependencies between the closure javascript files in root. It does not descend in directories.
// Each of the files listed in the output is prepended with the path "../../", which is assumed to be the location where these files can be found, relative to Closure's base.js.
//
// The format for each relevant javascript file is:
// goog.addDependency("filepath", ["namespace provided"], ["required namespace 1", "required namespace 2", ...]);
func GenDeps(root http.FileSystem) ([]byte, error) {
	// In the typical configuration, Closure is served at 'closure/goog/...''
	return GenDepsWithPath("../../", root)
}

// GenDepsWithPath is like GenDeps, but you can specify a path where the files are to be found at runtime relative to Closure's base.js.
func GenDepsWithPath(pathPrefix string, root http.FileSystem) ([]byte, error) {
	d, err := root.Open("/")
	if err != nil {
		return nil, fmt.Errorf("Failed to open root of %v: %v", root, err)
	}
	fi, err := d.Stat()
	if err != nil {
		return nil, err
	}
	if !fi.IsDir() {
		return nil, fmt.Errorf("root of %v is not a dir", root)
	}
	ent, err := d.Readdir(-1)
	if err != nil {
		return nil, fmt.Errorf("Could not read dir entries of root: %v", err)
	}
	var buf bytes.Buffer
	for _, info := range ent {
		name := info.Name()
		if !strings.HasSuffix(name, ".js") {
			continue
		}
		if strings.HasPrefix(name, ".#") {
			// Emacs noise.
			continue
		}
		f, err := root.Open(name)
		if err != nil {
			return nil, fmt.Errorf("Could not open %v: %v", name, err)
		}
		prov, req, err := parseProvidesRequires(info, name, f)
		f.Close()
		if err != nil {
			return nil, fmt.Errorf("Could not parse deps for %v: %v", name, err)
		}
		if len(prov) > 0 {
			fmt.Fprintf(&buf, "goog.addDependency(%q, %v, %v);\n", pathPrefix+name, jsList(prov), jsList(req))
		}
	}
	return buf.Bytes(), nil
}

var provReqRx = regexp.MustCompile(`^goog\.(provide|require)\(['"]([\w\.]+)['"]\)`)

type depCacheItem struct {
	modTime            time.Time
	provides, requires []string
}

var (
	depCacheMu sync.Mutex
	depCache   = map[string]depCacheItem{}
)

func parseProvidesRequires(fi os.FileInfo, path string, f io.Reader) (provides, requires []string, err error) {
	mt := fi.ModTime()
	depCacheMu.Lock()
	defer depCacheMu.Unlock()
	if ci := depCache[path]; ci.modTime.Equal(mt) {
		return ci.provides, ci.requires, nil
	}

	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		l := scanner.Text()
		if !strings.HasPrefix(l, "goog.") {
			continue
		}
		m := provReqRx.FindStringSubmatch(l)
		if m != nil {
			if m[1] == "provide" {
				provides = append(provides, m[2])
			} else {
				requires = append(requires, m[2])
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, nil, err
	}
	depCache[path] = depCacheItem{provides: provides, requires: requires, modTime: mt}
	return provides, requires, nil
}

// jsList prints a list of strings as JavaScript list.
type jsList []string

func (s jsList) String() string {
	var buf bytes.Buffer
	buf.WriteByte('[')
	for i, v := range s {
		if i > 0 {
			buf.WriteString(", ")
		}
		fmt.Fprintf(&buf, "%q", v)
	}
	buf.WriteByte(']')
	return buf.String()
}

// Example of a match:
// goog.addDependency('asserts/asserts.js', ['goog.asserts', 'goog.asserts.AssertionError'], ['goog.debug.Error', 'goog.string']);
// So with m := depsRx.FindStringSubmatch,
// the provider: m[1] == "asserts/asserts.js"
// the provided namespaces: m[2] == "'goog.asserts', 'goog.asserts.AssertionError'"
// the required namespaces: m[5] == "'goog.debug.Error', 'goog.string'"
var depsRx = regexp.MustCompile(`^goog.addDependency\(['"]([^/]+[a-zA-Z0-9\-\_/\.]*\.js)['"], \[((['"][\w\.]+['"])+(, ['"][\w\.]+['"])*)\], \[((['"][\w\.]+['"])+(, ['"][\w\.]+['"])*)?\]\);`)

// ParseDeps reads closure namespace dependency lines and
// returns a map giving the js file provider for each namespace,
// and a map giving the namespace dependencies for each namespace.
func ParseDeps(r io.Reader) (providedBy map[string]string, requires map[string][]string, err error) {
	providedBy = make(map[string]string)
	requires = make(map[string][]string)
	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		l := scanner.Text()
		if strings.HasPrefix(l, "//") {
			continue
		}
		if l == "" {
			continue
		}
		m := depsRx.FindStringSubmatch(l)
		if m == nil {
			return nil, nil, fmt.Errorf("Invalid line in deps: %q", l)
		}
		jsfile := m[1]
		provides := strings.Split(m[2], ", ")
		var required []string
		if m[5] != "" {
			required = strings.Split(
				strings.Replace(strings.Replace(m[5], "'", "", -1), `"`, "", -1), ", ")
		}
		for _, v := range provides {
			namespace := strings.Trim(v, `'"`)
			if otherjs, ok := providedBy[namespace]; ok {
				return nil, nil, fmt.Errorf("Name %v is provided by both %v and %v", namespace, jsfile, otherjs)
			}
			providedBy[namespace] = jsfile
			if _, ok := requires[namespace]; ok {
				return nil, nil, fmt.Errorf("Name %v has two sets of dependencies")
			}
			if required != nil {
				requires[namespace] = required
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, nil, err
	}
	return providedBy, requires, nil
}

// DeepParseDeps reads closure namespace dependency lines and
// returns a map giving all the required js files for each namespace.
func DeepParseDeps(r io.Reader) (map[string][]string, error) {
	providedBy, requires, err := ParseDeps(r)
	if err != nil {
		return nil, err
	}
	filesDeps := make(map[string][]string)
	var deeperDeps func(namespace string) []string
	deeperDeps = func(namespace string) []string {
		if jsdeps, ok := filesDeps[namespace]; ok {
			return jsdeps
		}
		jsfiles := []string{providedBy[namespace]}
		for _, dep := range requires[namespace] {
			jsfiles = append(jsfiles, deeperDeps(dep)...)
		}
		return jsfiles
	}
	for namespace, _ := range providedBy {
		filesDeps[namespace] = deeperDeps(namespace)
	}
	return filesDeps, nil
}
<|endoftext|>


<commit_before>package cb

import (
	"testing"

	"github.com/hellofresh/janus/pkg/config"
	"github.com/hellofresh/janus/pkg/plugin"
	"github.com/hellofresh/janus/pkg/proxy"
	"github.com/hellofresh/janus/pkg/router"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestCbPlugin(t *testing.T) {
	t.Parallel()

	tests := []struct {
		scenario string
		function func(*testing.T)
	}{
		{
			scenario: "when the correct cb configuration is given",
			function: testSetupWithCorrectConfig,
		},
		{
			scenario: "when an incorrect cb configuration is given",
			function: testSetupWithIncorrectConfig,
		},
		{
			scenario: "when the plugin setup is successful",
			function: testSetupSuccess,
		},
		{
			scenario: "when the plugin admin startup is successful",
			function: testAdminStartupSuccess,
		},
		{
			scenario: "when the plugin startup is successful",
			function: testStartupSuccess,
		},
		{
			scenario: "when the plugin startup is not successful",
			function: testStartupNoSuccess,
		},
	}

	for _, test := range tests {
		t.Run(test.scenario, func(t *testing.T) {
			test.function(t)
		})
	}
}

func testStartupNoSuccess(t *testing.T) {
	event2 := plugin.OnStartup{
		Register: proxy.NewRegister(proxy.WithRouter(router.NewChiRouter())),
		Config: &config.Specification{
			Stats: config.Stats{
				DSN: "statsd:8080",
			},
		},
	}
	err := onStartup(event2)
	require.Error(t, err)
}

func testStartupSuccess(t *testing.T) {
	event2 := plugin.OnStartup{
		Register: proxy.NewRegister(proxy.WithRouter(router.NewChiRouter())),
		Config:   &config.Specification{},
	}
	err := onStartup(event2)
	require.NoError(t, err)
}

func testAdminStartupSuccess(t *testing.T) {
	event1 := plugin.OnAdminAPIStartup{Router: router.NewChiRouter()}
	err := onAdminAPIStartup(event1)
	require.NoError(t, err)
}

func testSetupSuccess(t *testing.T) {
	def := proxy.NewRouterDefinition(proxy.NewDefinition())

	err := setupCB(def, make(plugin.Config))
	require.NoError(t, err)
}

func testSetupWithCorrectConfig(t *testing.T) {
	rawConfig := map[string]interface{}{
		"timeout":                 1000,
		"max_concurrent_requests": 100,
		"error_percent_threshold": 25,
		"sleep_window":            1,
		"predicate":               "statusCode => 500",
	}

	result, err := validateConfig(rawConfig)
	assert.True(t, result)
	require.NoError(t, err)
}

func testSetupWithIncorrectConfig(t *testing.T) {
	rawConfig := map[string]interface{}{
		"timeout": "wrong",
	}

	result, err := validateConfig(rawConfig)
	assert.False(t, result)
	require.Error(t, err)
}
<commit_msg>Update test dsn<commit_after>package cb

import (
	"testing"

	"github.com/hellofresh/janus/pkg/config"
	"github.com/hellofresh/janus/pkg/plugin"
	"github.com/hellofresh/janus/pkg/proxy"
	"github.com/hellofresh/janus/pkg/router"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestCbPlugin(t *testing.T) {
	t.Parallel()

	tests := []struct {
		scenario string
		function func(*testing.T)
	}{
		{
			scenario: "when the correct cb configuration is given",
			function: testSetupWithCorrectConfig,
		},
		{
			scenario: "when an incorrect cb configuration is given",
			function: testSetupWithIncorrectConfig,
		},
		{
			scenario: "when the plugin setup is successful",
			function: testSetupSuccess,
		},
		{
			scenario: "when the plugin admin startup is successful",
			function: testAdminStartupSuccess,
		},
		{
			scenario: "when the plugin startup is successful",
			function: testStartupSuccess,
		},
		{
			scenario: "when the plugin startup is not successful",
			function: testStartupNoSuccess,
		},
	}

	for _, test := range tests {
		t.Run(test.scenario, func(t *testing.T) {
			test.function(t)
		})
	}
}

func testStartupNoSuccess(t *testing.T) {
	event2 := plugin.OnStartup{
		Register: proxy.NewRegister(proxy.WithRouter(router.NewChiRouter())),
		Config: &config.Specification{
			Stats: config.Stats{
				DSN: "statsd://statsd:8080",
			},
		},
	}
	err := onStartup(event2)
	require.Error(t, err)
}

func testStartupSuccess(t *testing.T) {
	event2 := plugin.OnStartup{
		Register: proxy.NewRegister(proxy.WithRouter(router.NewChiRouter())),
		Config:   &config.Specification{},
	}
	err := onStartup(event2)
	require.NoError(t, err)
}

func testAdminStartupSuccess(t *testing.T) {
	event1 := plugin.OnAdminAPIStartup{Router: router.NewChiRouter()}
	err := onAdminAPIStartup(event1)
	require.NoError(t, err)
}

func testSetupSuccess(t *testing.T) {
	def := proxy.NewRouterDefinition(proxy.NewDefinition())

	err := setupCB(def, make(plugin.Config))
	require.NoError(t, err)
}

func testSetupWithCorrectConfig(t *testing.T) {
	rawConfig := map[string]interface{}{
		"timeout":                 1000,
		"max_concurrent_requests": 100,
		"error_percent_threshold": 25,
		"sleep_window":            1,
		"predicate":               "statusCode => 500",
	}

	result, err := validateConfig(rawConfig)
	assert.True(t, result)
	require.NoError(t, err)
}

func testSetupWithIncorrectConfig(t *testing.T) {
	rawConfig := map[string]interface{}{
		"timeout": "wrong",
	}

	result, err := validateConfig(rawConfig)
	assert.False(t, result)
	require.Error(t, err)
}
<|endoftext|>


<commit_before>/*
Copyright 2017 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.
*/

package util

import (
	"time"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/klog"
	podutil "k8s.io/kubernetes/pkg/api/v1/pod"
	extenderv1 "k8s.io/kubernetes/pkg/scheduler/apis/extender/v1"
)

// GetPodFullName returns a name that uniquely identifies a pod.
func GetPodFullName(pod *v1.Pod) string {
	// Use underscore as the delimiter because it is not allowed in pod name
	// (DNS subdomain format).
	return pod.Name + "_" + pod.Namespace
}

// GetPodStartTime returns start time of the given pod.
func GetPodStartTime(pod *v1.Pod) *metav1.Time {
	if pod.Status.StartTime != nil {
		return pod.Status.StartTime
	}
	// Should not reach here as the start time of a running time should not be nil
	// Return current timestamp as the default value.
	// This will not affect the calculation of earliest timestamp of all the pods on one node,
	// because current timestamp is always after the StartTime of any pod in good state.
	klog.Errorf("pod.Status.StartTime is nil for pod %s. Should not reach here.", pod.Name)
	return &metav1.Time{Time: time.Now()}
}

// lessFunc is a function that receives two items and returns true if the first
// item should be placed before the second one when the list is sorted.
type lessFunc = func(item1, item2 interface{}) bool

// GetEarliestPodStartTime returns the earliest start time of all pods that
// have the highest priority among all victims.
func GetEarliestPodStartTime(victims *extenderv1.Victims) *metav1.Time {
	if len(victims.Pods) == 0 {
		// should not reach here.
		klog.Errorf("victims.Pods is empty. Should not reach here.")
		return nil
	}

	earliestPodStartTime := GetPodStartTime(victims.Pods[0])
	maxPriority := podutil.GetPodPriority(victims.Pods[0])

	for _, pod := range victims.Pods {
		if podutil.GetPodPriority(pod) == maxPriority {
			if GetPodStartTime(pod).Before(earliestPodStartTime) {
				earliestPodStartTime = GetPodStartTime(pod)
			}
		} else if podutil.GetPodPriority(pod) > maxPriority {
			maxPriority = podutil.GetPodPriority(pod)
			earliestPodStartTime = GetPodStartTime(pod)
		}
	}

	return earliestPodStartTime
}

// MoreImportantPod return true when priority of the first pod is higher than
// the second one. If two pods' priorities are equal, compare their StartTime.
// It takes arguments of the type "interface{}" to be used with SortableList,
// but expects those arguments to be *v1.Pod.
func MoreImportantPod(pod1, pod2 *v1.Pod) bool {
	p1 := podutil.GetPodPriority(pod1)
	p2 := podutil.GetPodPriority(pod2)
	if p1 != p2 {
		return p1 > p2
	}
	return GetPodStartTime(pod1).Before(GetPodStartTime(pod2))
}

// GetPodAffinityTerms gets pod affinity terms by a pod affinity object.
func GetPodAffinityTerms(podAffinity *v1.PodAffinity) (terms []v1.PodAffinityTerm) {
	if podAffinity != nil {
		if len(podAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 {
			terms = podAffinity.RequiredDuringSchedulingIgnoredDuringExecution
		}
		// TODO: Uncomment this block when implement RequiredDuringSchedulingRequiredDuringExecution.
		//if len(podAffinity.RequiredDuringSchedulingRequiredDuringExecution) != 0 {
		//	terms = append(terms, podAffinity.RequiredDuringSchedulingRequiredDuringExecution...)
		//}
	}
	return terms
}

// GetPodAntiAffinityTerms gets pod affinity terms by a pod anti-affinity.
func GetPodAntiAffinityTerms(podAntiAffinity *v1.PodAntiAffinity) (terms []v1.PodAffinityTerm) {
	if podAntiAffinity != nil {
		if len(podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 {
			terms = podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution
		}
		// TODO: Uncomment this block when implement RequiredDuringSchedulingRequiredDuringExecution.
		//if len(podAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution) != 0 {
		//	terms = append(terms, podAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution...)
		//}
	}
	return terms
}
<commit_msg>Remove Error log for nil StartTime<commit_after>/*
Copyright 2017 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.
*/

package util

import (
	"time"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/klog"
	podutil "k8s.io/kubernetes/pkg/api/v1/pod"
	extenderv1 "k8s.io/kubernetes/pkg/scheduler/apis/extender/v1"
)

// GetPodFullName returns a name that uniquely identifies a pod.
func GetPodFullName(pod *v1.Pod) string {
	// Use underscore as the delimiter because it is not allowed in pod name
	// (DNS subdomain format).
	return pod.Name + "_" + pod.Namespace
}

// GetPodStartTime returns start time of the given pod or current timestamp
// if it hasn't started yet.
func GetPodStartTime(pod *v1.Pod) *metav1.Time {
	if pod.Status.StartTime != nil {
		return pod.Status.StartTime
	}
	// Assumed pods and bound pods that haven't started don't have a StartTime yet.
	return &metav1.Time{Time: time.Now()}
}

// GetEarliestPodStartTime returns the earliest start time of all pods that
// have the highest priority among all victims.
func GetEarliestPodStartTime(victims *extenderv1.Victims) *metav1.Time {
	if len(victims.Pods) == 0 {
		// should not reach here.
		klog.Errorf("victims.Pods is empty. Should not reach here.")
		return nil
	}

	earliestPodStartTime := GetPodStartTime(victims.Pods[0])
	maxPriority := podutil.GetPodPriority(victims.Pods[0])

	for _, pod := range victims.Pods {
		if podutil.GetPodPriority(pod) == maxPriority {
			if GetPodStartTime(pod).Before(earliestPodStartTime) {
				earliestPodStartTime = GetPodStartTime(pod)
			}
		} else if podutil.GetPodPriority(pod) > maxPriority {
			maxPriority = podutil.GetPodPriority(pod)
			earliestPodStartTime = GetPodStartTime(pod)
		}
	}

	return earliestPodStartTime
}

// MoreImportantPod return true when priority of the first pod is higher than
// the second one. If two pods' priorities are equal, compare their StartTime.
// It takes arguments of the type "interface{}" to be used with SortableList,
// but expects those arguments to be *v1.Pod.
func MoreImportantPod(pod1, pod2 *v1.Pod) bool {
	p1 := podutil.GetPodPriority(pod1)
	p2 := podutil.GetPodPriority(pod2)
	if p1 != p2 {
		return p1 > p2
	}
	return GetPodStartTime(pod1).Before(GetPodStartTime(pod2))
}

// GetPodAffinityTerms gets pod affinity terms by a pod affinity object.
func GetPodAffinityTerms(podAffinity *v1.PodAffinity) (terms []v1.PodAffinityTerm) {
	if podAffinity != nil {
		if len(podAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 {
			terms = podAffinity.RequiredDuringSchedulingIgnoredDuringExecution
		}
		// TODO: Uncomment this block when implement RequiredDuringSchedulingRequiredDuringExecution.
		//if len(podAffinity.RequiredDuringSchedulingRequiredDuringExecution) != 0 {
		//	terms = append(terms, podAffinity.RequiredDuringSchedulingRequiredDuringExecution...)
		//}
	}
	return terms
}

// GetPodAntiAffinityTerms gets pod affinity terms by a pod anti-affinity.
func GetPodAntiAffinityTerms(podAntiAffinity *v1.PodAntiAffinity) (terms []v1.PodAffinityTerm) {
	if podAntiAffinity != nil {
		if len(podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 {
			terms = podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution
		}
		// TODO: Uncomment this block when implement RequiredDuringSchedulingRequiredDuringExecution.
		//if len(podAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution) != 0 {
		//	terms = append(terms, podAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution...)
		//}
	}
	return terms
}
<|endoftext|>


<commit_before>package state

import (
	"reflect"
	"testing"
	"time"

	"github.com/compose/transporter/pkg/message"
)

func TestFilestore(t *testing.T) {
	fs := NewFilestore("somelongkey", "/tmp/transporter.db", 10000*time.Millisecond)

	data := []struct {
		path string
		in   map[string]interface{}
	}{
		{
			"somepath",
			map[string]interface{}{"id": "nick1", "field1": 1},
		},
		{
			"somepath/morepath",
			map[string]interface{}{"id": "nick1", "field1": 1},
		},
	}

	for _, d := range data {
		err := fs.Save(d.path, message.NewMsg(OpTypeFromString("insert"), d.in)
		if err != nil {
			t.Errorf("got error: %s\n", err)
			t.FailNow()
		}
	}

	for _, d := range data {
		id, ts, err := fs.Get(d.path)
		if err != nil {
			t.Errorf("got error: %s\n", err)
			t.FailNow()
		}
		if !reflect.DeepEqual(id, d.id) {
			t.Errorf("wanted: %s, got: %s", d.id, id)
		}
		if !reflect.DeepEqual(ts, d.ts) {
			t.Errorf("wanted: %s, got: %s", d.ts, ts)
		}
	}

}

func TestFilestoreUpdates(t *testing.T) {
	fs := NewFilestore("somelongkey", "/tmp/transporter.db", 10000*time.Millisecond)

	data := []struct {
		path string
		in   map[string]interface{}
	}{
		{
			"somepath",
			map[string]interface{}{"id": "nick1", "field1": 1},
		},
		{
			"somepath",
			map[string]interface{}{"id": "nick1", "field1": 2},
		},
	}

	for _, d := range data {
		err := fs.Save(d.path, message.NewMsg(OpTypeFromString("insert"), d.in)
		if err != nil {
			t.Errorf("got error: %s\n", err)
			t.FailNow()
		}
	}

	d := data[len(data)-1]
	id, ts, err := fs.Get(d.path)
	if err != nil {
		t.Errorf("got error: %s\n", err)
		t.FailNow()
	}
	if !reflect.DeepEqual(id, d.id) {
		t.Errorf("wanted: %s, got: %s", d.id, id)
	}
	if !reflect.DeepEqual(ts, d.ts) {
		t.Errorf("wanted: %s, got: %s", d.ts, ts)
	}

}
<commit_msg>fix filestore tests<commit_after>package state

import (
	"reflect"
	"testing"
	"time"

	"github.com/compose/transporter/pkg/message"
)

func TestFilestore(t *testing.T) {
	fs := NewFilestore("somelongkey", "/tmp/transporter.db", 10000*time.Millisecond)

	data := []struct {
		path string
		in   *message.Msg
		out  *message.Msg
	}{
		{
			"somepath",
			message.NewMsg(message.Insert, map[string]interface{}{"id": "nick1", "field1": 1}),
			message.NewMsg(message.Insert, map[string]interface{}{"id": "nick1", "field1": 1}),
		},
		{
			"somepath/morepath",
			message.NewMsg(message.Insert, map[string]interface{}{"id": "nick1", "field1": 1}),
			message.NewMsg(message.Insert, map[string]interface{}{"id": "nick1", "field1": 1}),
		},
	}

	for _, d := range data {
		err := fs.Set(d.path, d.in)
		if err != nil {
			t.Errorf("got error: %s\n", err)
			t.FailNow()
		}
	}

	for _, d := range data {
		out, err := fs.Get(d.path)
		if err != nil {
			t.Errorf("got error: %s\n", err)
			t.FailNow()
		}
		if !reflect.DeepEqual(out, d.out) {
			t.Errorf("wanted: %s, got: %s", d.out, out)
		}
	}

}

func TestFilestoreUpdates(t *testing.T) {
	fs := NewFilestore("somelongkey", "/tmp/transporter.db", 10000*time.Millisecond)

	data := []struct {
		path string
		in   *message.Msg
		out  *message.Msg
	}{
		{
			"somepath",
			message.NewMsg(message.Insert, map[string]interface{}{"id": "nick1", "field1": 1}),
			message.NewMsg(message.Insert, map[string]interface{}{"id": "nick1", "field1": 1}),
		},
		{
			"somepath",
			message.NewMsg(message.Insert, map[string]interface{}{"id": "nick1", "field1": 2}),
			message.NewMsg(message.Insert, map[string]interface{}{"id": "nick1", "field1": 2}),
		},
	}

	for _, d := range data {
		err := fs.Set(d.path, d.in)
		if err != nil {
			t.Errorf("got error: %s\n", err)
			t.FailNow()
		}
	}

	d := data[len(data)-1]
	out, err := fs.Get(d.path)
	if err != nil {
		t.Errorf("got error: %s\n", err)
		t.FailNow()
	}
	if !reflect.DeepEqual(out, d.out) {
		t.Errorf("wanted: %s, got: %s", d.out, out)
	}

}
<|endoftext|>


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

package framework

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"sync"
	"testing"
	"time"

	"gopkg.in/yaml.v2"

	"istio.io/pkg/log"

	"istio.io/istio/pkg/test/framework/components/environment/kube"
	"istio.io/istio/pkg/test/framework/components/environment/native"
	ferrors "istio.io/istio/pkg/test/framework/errors"
	"istio.io/istio/pkg/test/framework/label"
	"istio.io/istio/pkg/test/framework/resource"
	"istio.io/istio/pkg/test/framework/resource/environment"
	"istio.io/istio/pkg/test/scopes"
)

// test.Run uses 0, 1, 2 exit codes. Use different exit codes for our framework.
const (
	// Indicates a framework-level init error
	exitCodeInitError = -1

	// Indicates an error due to the setup function supplied by the user
	exitCodeSetupError = -2
)

var (
	rt   *runtime
	rtMu sync.Mutex
)

// getSettingsFunc is a function used to extract the default settings for the Suite.
type getSettingsFunc func(string) (*resource.Settings, error)

// mRunFn abstracts testing.M.run, so that the framework itself can be tested.
type mRunFn func(ctx *suiteContext) int

// Suite allows the test author to specify suite-related metadata and do setup in a fluent-style, before commencing execution.
type Suite struct {
	testID      string
	skipMessage string
	mRun        mRunFn
	osExit      func(int)
	labels      label.Set

	requireFns []resource.SetupFn
	setupFns   []resource.SetupFn

	getSettings getSettingsFunc
	envFactory  resource.EnvironmentFactory
}

// NewSuite returns a new suite instance.
func NewSuite(testID string, m *testing.M) *Suite {
	return newSuite(testID,
		func(_ *suiteContext) int {
			return m.Run()
		},
		os.Exit,
		getSettings)
}

func newSuite(testID string, fn mRunFn, osExit func(int), getSettingsFn getSettingsFunc) *Suite {
	s := &Suite{
		testID:      testID,
		mRun:        fn,
		osExit:      osExit,
		getSettings: getSettingsFn,
		labels:      label.NewSet(),
	}

	return s
}

// EnvironmentFactory sets a custom function used for creating the resource.Environment for this Suite.
func (s *Suite) EnvironmentFactory(fn resource.EnvironmentFactory) *Suite {
	if fn != nil && s.envFactory != nil {
		scopes.CI.Warn("EnvironmentFactory overridden multiple times for Suite")
	}
	s.envFactory = fn
	return s
}

// Label all the tests in suite with the given labels
func (s *Suite) Label(labels ...label.Instance) *Suite {
	s.labels = s.labels.Add(labels...)
	return s
}

// Skip marks a suite as skipped with the given reason. This will prevent any setup functions from occurring.
func (s *Suite) Skip(reason string) *Suite {
	s.skipMessage = reason
	return s
}

// RequireEnvironment ensures that the current environment matches what the suite expects. Otherwise it
// stops test execution. This also applies the appropriate label to the suite implicitly.
func (s *Suite) RequireEnvironment(name environment.Name) *Suite {
	fn := func(ctx resource.Context) error {
		if name != ctx.Environment().EnvironmentName() {
			s.Skip(fmt.Sprintf("Required environment (%v) does not match current: %v",
				name, ctx.Environment().EnvironmentName()))
		}
		return nil
	}

	s.requireFns = append(s.requireFns, fn)
	return s
}

// RequireMinClusters ensures that the current environment contains at least the given number of clusters.
// Otherwise it stops test execution.
func (s *Suite) RequireMinClusters(minClusters int) *Suite {
	if minClusters <= 0 {
		minClusters = 1
	}

	fn := func(ctx resource.Context) error {
		if len(ctx.Environment().Clusters()) < minClusters {
			s.Skip(fmt.Sprintf("Number of clusters %d does not exceed minimum %d",
				len(ctx.Environment().Clusters()), minClusters))
		}
		return nil
	}

	s.requireFns = append(s.requireFns, fn)
	return s
}

// RequireMaxClusters ensures that the current environment contains at least the given number of clusters.
// Otherwise it stops test execution.
func (s *Suite) RequireMaxClusters(maxClusters int) *Suite {
	if maxClusters <= 0 {
		maxClusters = 1
	}

	fn := func(ctx resource.Context) error {
		if len(ctx.Environment().Clusters()) > maxClusters {
			s.Skip(fmt.Sprintf("Number of clusters %d exceeds maximum %d",
				len(ctx.Environment().Clusters()), maxClusters))
		}
		return nil
	}

	s.requireFns = append(s.requireFns, fn)
	return s
}

// RequireSingleCluster is a utility method that requires that there be exactly 1 cluster in the environment.
func (s *Suite) RequireSingleCluster() *Suite {
	return s.RequireMinClusters(1).RequireMaxClusters(1)
}

// RequireEnvironmentVersion validates the environment meets a minimum version
func (s *Suite) RequireEnvironmentVersion(version string) *Suite {
	fn := func(ctx resource.Context) error {

		if ctx.Environment().EnvironmentName() == environment.Kube {
			kenv := ctx.Environment().(*kube.Environment)
			ver, err := kenv.KubeClusters[0].GetKubernetesVersion()
			if err != nil {
				return fmt.Errorf("failed to get Kubernetes version: %v", err)
			}
			serverVersion := fmt.Sprintf("%s.%s", ver.Major, ver.Minor)
			if serverVersion < version {
				s.Skip(fmt.Sprintf("Required Kubernetes version (%v) is greater than current: %v",
					version, serverVersion))
			}
		}
		return nil
	}

	s.requireFns = append(s.requireFns, fn)
	return s
}

// Setup runs enqueues the given setup function to run before test execution.
func (s *Suite) Setup(fn resource.SetupFn) *Suite {
	s.setupFns = append(s.setupFns, fn)
	return s
}

func (s *Suite) runSetupFn(fn resource.SetupFn, ctx SuiteContext) (err error) {
	defer func() {
		// Dump if the setup function fails
		if err != nil && ctx.Settings().CIMode {
			rt.Dump()
		}
	}()
	err = fn(ctx)
	return
}

// SetupOnEnv runs the given setup function conditionally, based on the current environment.
func (s *Suite) SetupOnEnv(e environment.Name, fn resource.SetupFn) *Suite {
	s.Setup(func(ctx resource.Context) error {
		if ctx.Environment().EnvironmentName() != e {
			return nil
		}
		return fn(ctx)
	})

	return s
}

// Run the suite. This method calls os.Exit and does not return.
func (s *Suite) Run() {
	s.osExit(s.run())
}

func (s *Suite) isSkipped() bool {
	return s.skipMessage != ""
}

func (s *Suite) doSkip(ctx *suiteContext) int {
	scopes.Framework.Infof("Skipping suite %q: %s", ctx.Settings().TestID, s.skipMessage)

	// Mark this suite as skipped in the context.
	ctx.skipped = true

	// Run the tests so that the golang test framework exits normally. The tests will not run because
	// they see that this suite has been skipped.
	_ = s.mRun(ctx)

	// Return success.
	return 0
}

func (s *Suite) run() (errLevel int) {
	if err := initRuntime(s); err != nil {
		scopes.Framework.Errorf("Error during test framework init: %v", err)
		return exitCodeInitError
	}

	ctx := rt.suiteContext()

	// Skip the test if its explicitly skipped
	if s.isSkipped() {
		return s.doSkip(ctx)
	}

	// Before starting, check whether the current set of labels & label selectors will ever allow us to run tests.
	// if not, simply exit now.
	if ctx.Settings().Selector.Excludes(s.labels) {
		s.Skip(fmt.Sprintf("Label mismatch: labels=%v, selector=%v",
			s.labels,
			ctx.Settings().Selector))
		return s.doSkip(ctx)
	}

	start := time.Now()

	defer func() {
		if errLevel != 0 && ctx.Settings().CIMode {
			rt.Dump()
		}

		if err := rt.Close(); err != nil {
			scopes.Framework.Errorf("Error during close: %v", err)
			if rt.context.settings.FailOnDeprecation {
				if ferrors.IsOrContainsDeprecatedError(err) {
					errLevel = 1
				}
			}
		}
		rt = nil
	}()

	if err := s.runSetupFns(ctx); err != nil {
		scopes.Framework.Errorf("Exiting due to setup failure: %v", err)
		return exitCodeSetupError
	}

	// Check if one of the setup functions ended up skipping the suite.
	if s.isSkipped() {
		return s.doSkip(ctx)
	}

	defer func() {
		end := time.Now()
		scopes.CI.Infof("=== Suite %q run time: %v ===", ctx.Settings().TestID, end.Sub(start))
	}()

	attempt := 0
	for attempt <= ctx.settings.Retries {
		attempt++
		scopes.CI.Infof("=== BEGIN: Test Run: '%s' ===", ctx.Settings().TestID)
		errLevel = s.mRun(ctx)
		if errLevel == 0 {
			scopes.CI.Infof("=== DONE: Test Run: '%s' ===", ctx.Settings().TestID)
			break
		} else {
			scopes.CI.Infof("=== FAILED: Test Run: '%s' (exitCode: %v) ===",
				ctx.Settings().TestID, errLevel)
			if attempt <= ctx.settings.Retries {
				scopes.CI.Warnf("=== RETRY: Test Run: '%s' ===", ctx.Settings().TestID)
			}
		}
	}
	s.writeOutput()

	return
}

type SuiteOutcome struct {
	Name         string
	Environment  string
	Multicluster bool
	TestOutcomes []TestOutcome
}

func (s *Suite) writeOutput() {
	// the ARTIFACTS env var is set by prow, and uploaded to GCS as part of the job artifact
	artifactsPath := os.Getenv("ARTIFACTS")
	if artifactsPath != "" {
		ctx := rt.suiteContext()
		ctx.outcomeMu.RLock()
		out := SuiteOutcome{
			Name:         ctx.Settings().TestID,
			Environment:  ctx.Environment().EnvironmentName().String(),
			Multicluster: ctx.Environment().IsMulticluster(),
			TestOutcomes: ctx.testOutcomes,
		}
		ctx.outcomeMu.RUnlock()
		outbytes, err := yaml.Marshal(out)
		if err != nil {
			log.Errorf("failed writing test suite outcome to yaml: %s", err)
		}
		err = ioutil.WriteFile(path.Join(artifactsPath, out.Name+".yaml"), outbytes, 0644)
		if err != nil {
			log.Errorf("failed writing test suite outcome to file: %s", err)
		}
	}
}

func (s *Suite) runSetupFns(ctx SuiteContext) (err error) {
	scopes.CI.Infof("=== BEGIN: Setup: '%s' ===", ctx.Settings().TestID)

	// Run all the require functions first, then the setup functions.
	setupFns := append(append([]resource.SetupFn{}, s.requireFns...), s.setupFns...)

	for _, fn := range setupFns {
		err := s.runSetupFn(fn, ctx)
		if err != nil {
			scopes.Framework.Errorf("Test setup error: %v", err)
			scopes.CI.Infof("=== FAILED: Setup: '%s' (%v) ===", ctx.Settings().TestID, err)
			return err
		}

		if s.isSkipped() {
			return nil
		}
	}
	scopes.CI.Infof("=== DONE: Setup: '%s' ===", ctx.Settings().TestID)
	return nil
}

func initRuntime(s *Suite) error {
	rtMu.Lock()
	defer rtMu.Unlock()

	if rt != nil {
		return errors.New("framework is already initialized")
	}

	settings, err := s.getSettings(s.testID)
	if err != nil {
		return err
	}

	// Get the EnvironmentFactory.
	environmentFactory := s.envFactory
	if environmentFactory == nil {
		environmentFactory = settings.EnvironmentFactory
	}
	if environmentFactory == nil {
		environmentFactory = newEnvironment
	}

	if err := configureLogging(settings.CIMode); err != nil {
		return err
	}

	scopes.CI.Infof("=== Test Framework Settings ===")
	scopes.CI.Info(settings.String())
	scopes.CI.Infof("===============================")

	// Ensure that the work dir is set.
	if err := os.MkdirAll(settings.RunDir(), os.ModePerm); err != nil {
		return fmt.Errorf("error creating rundir %q: %v", settings.RunDir(), err)
	}
	scopes.Framework.Infof("Test run dir: %v", settings.RunDir())

	rt, err = newRuntime(settings, environmentFactory, s.labels)
	return err
}

func newEnvironment(name string, ctx resource.Context) (resource.Environment, error) {
	switch name {
	case environment.Native.String():
		return native.New(ctx)
	case environment.Kube.String():
		s, err := kube.NewSettingsFromCommandLine()
		if err != nil {
			return nil, err
		}
		return kube.New(ctx, s)
	default:
		return nil, fmt.Errorf("unknown environment: %q", name)
	}
}

func getSettings(testID string) (*resource.Settings, error) {
	// Parse flags and init logging.
	if !flag.Parsed() {
		flag.Parse()
	}

	return resource.SettingsFromCommandLine(testID)
}
<commit_msg>Derive suite name for test framework (#24556)<commit_after>// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package framework

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	goruntime "runtime"
	"strings"
	"sync"
	"testing"
	"time"

	"gopkg.in/yaml.v2"

	"istio.io/pkg/log"

	"istio.io/istio/pkg/test/framework/components/environment/kube"
	"istio.io/istio/pkg/test/framework/components/environment/native"
	ferrors "istio.io/istio/pkg/test/framework/errors"
	"istio.io/istio/pkg/test/framework/label"
	"istio.io/istio/pkg/test/framework/resource"
	"istio.io/istio/pkg/test/framework/resource/environment"
	"istio.io/istio/pkg/test/scopes"
)

// test.Run uses 0, 1, 2 exit codes. Use different exit codes for our framework.
const (
	// Indicates a framework-level init error
	exitCodeInitError = -1

	// Indicates an error due to the setup function supplied by the user
	exitCodeSetupError = -2
)

var (
	rt   *runtime
	rtMu sync.Mutex
)

// getSettingsFunc is a function used to extract the default settings for the Suite.
type getSettingsFunc func(string) (*resource.Settings, error)

// mRunFn abstracts testing.M.run, so that the framework itself can be tested.
type mRunFn func(ctx *suiteContext) int

// Suite allows the test author to specify suite-related metadata and do setup in a fluent-style, before commencing execution.
type Suite struct {
	testID      string
	skipMessage string
	mRun        mRunFn
	osExit      func(int)
	labels      label.Set

	requireFns []resource.SetupFn
	setupFns   []resource.SetupFn

	getSettings getSettingsFunc
	envFactory  resource.EnvironmentFactory
}

// Given the filename of a test, derive its suite name
func deriveSuiteName(caller string) string {
	d := filepath.Dir(caller)
	matches := []string{"istio.io/istio.io", "istio.io/istio", "tests/integration"}
	// We will trim out paths preceding some well known paths. This should handle anything in istio or docs repo,
	// as well as special case tests/integration. The end result is a test under ./tests/integration/pilot/ingress
	// will become pilot_ingress
	// Note: if this fails to trim, we end up with "ugly" suite names but otherwise no real impact.
	for _, match := range matches {
		if i := strings.Index(d, match); i >= 0 {
			d = d[i+len(match)+1:]
		}
	}
	return strings.ReplaceAll(d, "/", "_")
}

// NewSuite returns a new suite instance.
func NewSuite(testID string, m *testing.M) *Suite {
	_, f, _, _ := goruntime.Caller(1)
	return newSuite(deriveSuiteName(f),
		func(_ *suiteContext) int {
			return m.Run()
		},
		os.Exit,
		getSettings)
}

func newSuite(testID string, fn mRunFn, osExit func(int), getSettingsFn getSettingsFunc) *Suite {
	s := &Suite{
		testID:      testID,
		mRun:        fn,
		osExit:      osExit,
		getSettings: getSettingsFn,
		labels:      label.NewSet(),
	}

	return s
}

// EnvironmentFactory sets a custom function used for creating the resource.Environment for this Suite.
func (s *Suite) EnvironmentFactory(fn resource.EnvironmentFactory) *Suite {
	if fn != nil && s.envFactory != nil {
		scopes.CI.Warn("EnvironmentFactory overridden multiple times for Suite")
	}
	s.envFactory = fn
	return s
}

// Label all the tests in suite with the given labels
func (s *Suite) Label(labels ...label.Instance) *Suite {
	s.labels = s.labels.Add(labels...)
	return s
}

// Skip marks a suite as skipped with the given reason. This will prevent any setup functions from occurring.
func (s *Suite) Skip(reason string) *Suite {
	s.skipMessage = reason
	return s
}

// RequireEnvironment ensures that the current environment matches what the suite expects. Otherwise it
// stops test execution. This also applies the appropriate label to the suite implicitly.
func (s *Suite) RequireEnvironment(name environment.Name) *Suite {
	fn := func(ctx resource.Context) error {
		if name != ctx.Environment().EnvironmentName() {
			s.Skip(fmt.Sprintf("Required environment (%v) does not match current: %v",
				name, ctx.Environment().EnvironmentName()))
		}
		return nil
	}

	s.requireFns = append(s.requireFns, fn)
	return s
}

// RequireMinClusters ensures that the current environment contains at least the given number of clusters.
// Otherwise it stops test execution.
func (s *Suite) RequireMinClusters(minClusters int) *Suite {
	if minClusters <= 0 {
		minClusters = 1
	}

	fn := func(ctx resource.Context) error {
		if len(ctx.Environment().Clusters()) < minClusters {
			s.Skip(fmt.Sprintf("Number of clusters %d does not exceed minimum %d",
				len(ctx.Environment().Clusters()), minClusters))
		}
		return nil
	}

	s.requireFns = append(s.requireFns, fn)
	return s
}

// RequireMaxClusters ensures that the current environment contains at least the given number of clusters.
// Otherwise it stops test execution.
func (s *Suite) RequireMaxClusters(maxClusters int) *Suite {
	if maxClusters <= 0 {
		maxClusters = 1
	}

	fn := func(ctx resource.Context) error {
		if len(ctx.Environment().Clusters()) > maxClusters {
			s.Skip(fmt.Sprintf("Number of clusters %d exceeds maximum %d",
				len(ctx.Environment().Clusters()), maxClusters))
		}
		return nil
	}

	s.requireFns = append(s.requireFns, fn)
	return s
}

// RequireSingleCluster is a utility method that requires that there be exactly 1 cluster in the environment.
func (s *Suite) RequireSingleCluster() *Suite {
	return s.RequireMinClusters(1).RequireMaxClusters(1)
}

// RequireEnvironmentVersion validates the environment meets a minimum version
func (s *Suite) RequireEnvironmentVersion(version string) *Suite {
	fn := func(ctx resource.Context) error {

		if ctx.Environment().EnvironmentName() == environment.Kube {
			kenv := ctx.Environment().(*kube.Environment)
			ver, err := kenv.KubeClusters[0].GetKubernetesVersion()
			if err != nil {
				return fmt.Errorf("failed to get Kubernetes version: %v", err)
			}
			serverVersion := fmt.Sprintf("%s.%s", ver.Major, ver.Minor)
			if serverVersion < version {
				s.Skip(fmt.Sprintf("Required Kubernetes version (%v) is greater than current: %v",
					version, serverVersion))
			}
		}
		return nil
	}

	s.requireFns = append(s.requireFns, fn)
	return s
}

// Setup runs enqueues the given setup function to run before test execution.
func (s *Suite) Setup(fn resource.SetupFn) *Suite {
	s.setupFns = append(s.setupFns, fn)
	return s
}

func (s *Suite) runSetupFn(fn resource.SetupFn, ctx SuiteContext) (err error) {
	defer func() {
		// Dump if the setup function fails
		if err != nil && ctx.Settings().CIMode {
			rt.Dump()
		}
	}()
	err = fn(ctx)
	return
}

// SetupOnEnv runs the given setup function conditionally, based on the current environment.
func (s *Suite) SetupOnEnv(e environment.Name, fn resource.SetupFn) *Suite {
	s.Setup(func(ctx resource.Context) error {
		if ctx.Environment().EnvironmentName() != e {
			return nil
		}
		return fn(ctx)
	})

	return s
}

// Run the suite. This method calls os.Exit and does not return.
func (s *Suite) Run() {
	s.osExit(s.run())
}

func (s *Suite) isSkipped() bool {
	return s.skipMessage != ""
}

func (s *Suite) doSkip(ctx *suiteContext) int {
	scopes.Framework.Infof("Skipping suite %q: %s", ctx.Settings().TestID, s.skipMessage)

	// Mark this suite as skipped in the context.
	ctx.skipped = true

	// Run the tests so that the golang test framework exits normally. The tests will not run because
	// they see that this suite has been skipped.
	_ = s.mRun(ctx)

	// Return success.
	return 0
}

func (s *Suite) run() (errLevel int) {
	if err := initRuntime(s); err != nil {
		scopes.Framework.Errorf("Error during test framework init: %v", err)
		return exitCodeInitError
	}

	ctx := rt.suiteContext()

	// Skip the test if its explicitly skipped
	if s.isSkipped() {
		return s.doSkip(ctx)
	}

	// Before starting, check whether the current set of labels & label selectors will ever allow us to run tests.
	// if not, simply exit now.
	if ctx.Settings().Selector.Excludes(s.labels) {
		s.Skip(fmt.Sprintf("Label mismatch: labels=%v, selector=%v",
			s.labels,
			ctx.Settings().Selector))
		return s.doSkip(ctx)
	}

	start := time.Now()

	defer func() {
		if errLevel != 0 && ctx.Settings().CIMode {
			rt.Dump()
		}

		if err := rt.Close(); err != nil {
			scopes.Framework.Errorf("Error during close: %v", err)
			if rt.context.settings.FailOnDeprecation {
				if ferrors.IsOrContainsDeprecatedError(err) {
					errLevel = 1
				}
			}
		}
		rt = nil
	}()

	if err := s.runSetupFns(ctx); err != nil {
		scopes.Framework.Errorf("Exiting due to setup failure: %v", err)
		return exitCodeSetupError
	}

	// Check if one of the setup functions ended up skipping the suite.
	if s.isSkipped() {
		return s.doSkip(ctx)
	}

	defer func() {
		end := time.Now()
		scopes.CI.Infof("=== Suite %q run time: %v ===", ctx.Settings().TestID, end.Sub(start))
	}()

	attempt := 0
	for attempt <= ctx.settings.Retries {
		attempt++
		scopes.CI.Infof("=== BEGIN: Test Run: '%s' ===", ctx.Settings().TestID)
		errLevel = s.mRun(ctx)
		if errLevel == 0 {
			scopes.CI.Infof("=== DONE: Test Run: '%s' ===", ctx.Settings().TestID)
			break
		} else {
			scopes.CI.Infof("=== FAILED: Test Run: '%s' (exitCode: %v) ===",
				ctx.Settings().TestID, errLevel)
			if attempt <= ctx.settings.Retries {
				scopes.CI.Warnf("=== RETRY: Test Run: '%s' ===", ctx.Settings().TestID)
			}
		}
	}
	s.writeOutput()

	return
}

type SuiteOutcome struct {
	Name         string
	Environment  string
	Multicluster bool
	TestOutcomes []TestOutcome
}

func (s *Suite) writeOutput() {
	// the ARTIFACTS env var is set by prow, and uploaded to GCS as part of the job artifact
	artifactsPath := os.Getenv("ARTIFACTS")
	if artifactsPath != "" {
		ctx := rt.suiteContext()
		ctx.outcomeMu.RLock()
		out := SuiteOutcome{
			Name:         ctx.Settings().TestID,
			Environment:  ctx.Environment().EnvironmentName().String(),
			Multicluster: ctx.Environment().IsMulticluster(),
			TestOutcomes: ctx.testOutcomes,
		}
		ctx.outcomeMu.RUnlock()
		outbytes, err := yaml.Marshal(out)
		if err != nil {
			log.Errorf("failed writing test suite outcome to yaml: %s", err)
		}
		err = ioutil.WriteFile(path.Join(artifactsPath, out.Name+".yaml"), outbytes, 0644)
		if err != nil {
			log.Errorf("failed writing test suite outcome to file: %s", err)
		}
	}
}

func (s *Suite) runSetupFns(ctx SuiteContext) (err error) {
	scopes.CI.Infof("=== BEGIN: Setup: '%s' ===", ctx.Settings().TestID)

	// Run all the require functions first, then the setup functions.
	setupFns := append(append([]resource.SetupFn{}, s.requireFns...), s.setupFns...)

	for _, fn := range setupFns {
		err := s.runSetupFn(fn, ctx)
		if err != nil {
			scopes.Framework.Errorf("Test setup error: %v", err)
			scopes.CI.Infof("=== FAILED: Setup: '%s' (%v) ===", ctx.Settings().TestID, err)
			return err
		}

		if s.isSkipped() {
			return nil
		}
	}
	scopes.CI.Infof("=== DONE: Setup: '%s' ===", ctx.Settings().TestID)
	return nil
}

func initRuntime(s *Suite) error {
	rtMu.Lock()
	defer rtMu.Unlock()

	if rt != nil {
		return errors.New("framework is already initialized")
	}

	settings, err := s.getSettings(s.testID)
	if err != nil {
		return err
	}

	// Get the EnvironmentFactory.
	environmentFactory := s.envFactory
	if environmentFactory == nil {
		environmentFactory = settings.EnvironmentFactory
	}
	if environmentFactory == nil {
		environmentFactory = newEnvironment
	}

	if err := configureLogging(settings.CIMode); err != nil {
		return err
	}

	scopes.CI.Infof("=== Test Framework Settings ===")
	scopes.CI.Info(settings.String())
	scopes.CI.Infof("===============================")

	// Ensure that the work dir is set.
	if err := os.MkdirAll(settings.RunDir(), os.ModePerm); err != nil {
		return fmt.Errorf("error creating rundir %q: %v", settings.RunDir(), err)
	}
	scopes.Framework.Infof("Test run dir: %v", settings.RunDir())

	rt, err = newRuntime(settings, environmentFactory, s.labels)
	return err
}

func newEnvironment(name string, ctx resource.Context) (resource.Environment, error) {
	switch name {
	case environment.Native.String():
		return native.New(ctx)
	case environment.Kube.String():
		s, err := kube.NewSettingsFromCommandLine()
		if err != nil {
			return nil, err
		}
		return kube.New(ctx, s)
	default:
		return nil, fmt.Errorf("unknown environment: %q", name)
	}
}

func getSettings(testID string) (*resource.Settings, error) {
	// Parse flags and init logging.
	if !flag.Parsed() {
		flag.Parse()
	}

	return resource.SettingsFromCommandLine(testID)
}
<|endoftext|>


<commit_before>package dockermachine

import (
	"github.com/andrewsmedina/yati/tsuru/iaas"
	"github.com/docker/machine/commands/mcndirs"
	"github.com/docker/machine/libmachine"
)

func init() {
	iaas.Register("docker-machine", &dmIaas{})
}

type dmIaas struct{}

func (i *dmIaas) CreateMachine(params map[string]string) (*iaas.Machine, error) {
	api := libmachine.NewClient(mcndirs.GetBaseDir())
	driverName := "virtualbox"
	driver, _ := api.NewPluginDriver(driverName, nil)
	driver.Create()
	return &iaas.Machine{}, nil
}

func (i *dmIaas) DeleteMachine(m *iaas.Machine) error {
	return nil
}
<commit_msg>using docker machine via cmd<commit_after>package dockermachine

import (
	"github.com/andrewsmedina/yati/tsuru/iaas"
	"github.com/docker/machine/commands/mcndirs"
	"github.com/docker/machine/libmachine"
)

func init() {
	iaas.Register("docker-machine", &dmIaas{})
}

type dmIaas struct{}

func (i *dmIaas) CreateMachine(params map[string]string) (*iaas.Machine, error) {
	cmd := "docker-machine create tsuru -d virtualbox"
	api := libmachine.NewClient(mcndirs.GetBaseDir())
	driverName := "virtualbox"
	driver, _ := api.NewPluginDriver(driverName, nil)
	driver.Create()
	return &iaas.Machine{}, nil
}

func (i *dmIaas) DeleteMachine(m *iaas.Machine) error {
	return nil
}
<|endoftext|>


<commit_before>// Package aws provides core functionality for making requests to AWS services.
package aws

// SDKName is the name of this AWS SDK
const SDKName = "aws-sdk-go"

// SDKVersion is the version of this SDK
const SDKVersion = "0.9.11"
<commit_msg>Tag release v0.9.12<commit_after>// Package aws provides core functionality for making requests to AWS services.
package aws

// SDKName is the name of this AWS SDK
const SDKName = "aws-sdk-go"

// SDKVersion is the version of this SDK
const SDKVersion = "0.9.12"
<|endoftext|>


<commit_before>package soko

import (
	"fmt"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/ec2"
)

type AWSBackend struct {
	SectionConfig

	client *ec2.EC2
}

func NewAWSBackend(config SectionConfig) (*AWSBackend, error) {
	cred := credentials.NewStaticCredentials(config["access_key_id"], config["secret_access_key"], "")
	conf := &aws.Config{
		Credentials: cred,
		Region:      aws.String(config["region"]),
	}
	cli := ec2.New(conf)

	return &AWSBackend{
		SectionConfig: config,
		client:        cli,
	}, nil
}

func (b *AWSBackend) Get(serverID string, key string) (string, error) {
	params := &ec2.DescribeTagsInput{
		Filters: []*ec2.Filter{
			{
				Name:   aws.String("resource-id"),
				Values: []*string{aws.String(serverID)},
			},
			{
				Name:   aws.String("key"),
				Values: []*string{aws.String(key)},
			},
		},
	}

	tags, err := b.client.DescribeTags(params)
	if err != nil {
		return "", err
	}

	switch s := len(tags.Tags); s {
	case 0:
		sayEmpty(key)
		return "", nil
	case 1:
		return *tags.Tags[0].Value, nil
	default:
		return "", fmt.Errorf("Invalid size of key %s: %d tags exist", key, s)
	}

}

func (b *AWSBackend) Put(serverID string, key string, value string) error {
	params := &ec2.CreateTagsInput{
		Resources: []*string{
			aws.String(serverID),
		},
		Tags: []*ec2.Tag{
			{
				Key:   aws.String(key),
				Value: aws.String(value),
			},
		},
	}
	_, err := b.client.CreateTags(params)
	return err
}

func (b *AWSBackend) Delete(serverID string, key string) error {
	params := &ec2.DeleteTagsInput{
		Resources: []*string{
			aws.String(serverID),
		},
		Tags: []*ec2.Tag{
			{
				Key:   aws.String(key),
				Value: aws.String(""),
			},
		},
	}
	_, err := b.client.DeleteTags(params)
	return err
}
<commit_msg>In AWS, deleting tags must be provided with current tag value<commit_after>package soko

import (
	"fmt"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/ec2"
)

type AWSBackend struct {
	SectionConfig

	client *ec2.EC2
}

func NewAWSBackend(config SectionConfig) (*AWSBackend, error) {
	cred := credentials.NewStaticCredentials(config["access_key_id"], config["secret_access_key"], "")
	conf := &aws.Config{
		Credentials: cred,
		Region:      aws.String(config["region"]),
	}
	cli := ec2.New(conf)

	return &AWSBackend{
		SectionConfig: config,
		client:        cli,
	}, nil
}

func (b *AWSBackend) Get(serverID string, key string) (string, error) {
	return b.get(serverID, key, false)
}

func (b *AWSBackend) get(serverID string, key string, isInternal bool) (string, error) {
	params := &ec2.DescribeTagsInput{
		Filters: []*ec2.Filter{
			{
				Name:   aws.String("resource-id"),
				Values: []*string{aws.String(serverID)},
			},
			{
				Name:   aws.String("key"),
				Values: []*string{aws.String(key)},
			},
		},
	}

	tags, err := b.client.DescribeTags(params)
	if err != nil {
		return "", err
	}

	switch s := len(tags.Tags); s {
	case 0:
		if !isInternal {
			sayEmpty(key)
		}
		return "", nil
	case 1:
		return *tags.Tags[0].Value, nil
	default:
		return "", fmt.Errorf("Invalid size of key %s: %d tags exist", key, s)
	}

}

func (b *AWSBackend) Put(serverID string, key string, value string) error {
	params := &ec2.CreateTagsInput{
		Resources: []*string{
			aws.String(serverID),
		},
		Tags: []*ec2.Tag{
			{
				Key:   aws.String(key),
				Value: aws.String(value),
			},
		},
	}
	_, err := b.client.CreateTags(params)
	return err
}

func (b *AWSBackend) Delete(serverID string, key string) error {
	currentV, _ := b.get(serverID, key, true)

	params := &ec2.DeleteTagsInput{
		Resources: []*string{
			aws.String(serverID),
		},
		Tags: []*ec2.Tag{
			{
				Key:   aws.String(key),
				Value: aws.String(currentV),
			},
		},
	}
	_, err := b.client.DeleteTags(params)
	return err
}
<|endoftext|>


<commit_before>package siri

import (
	"testing"
	"time"
)

func Test_SIRIGeneralMessageRequest(t *testing.T) {
	expectedXML := `<ns7:GetGeneralMessage xmlns:ns2="http://www.siri.org.uk/siri" xmlns:ns3="http://www.ifopt.org.uk/acsb" xmlns:ns4="http://www.ifopt.org.uk/ifopt" xmlns:ns5="http://datex2.eu/schema/2_0RC1/2_0" xmlns:ns6="http://wsdl.siri.org.uk/siri" xmlns:ns7="http://wsdl.siri.org.uk">
      <ServiceRequestInfo>
        <ns2:RequestTimestamp>2016-09-21T20:14:46.000Z</ns2:RequestTimestamp>
        <ns2:RequestorRef>ref</ns2:RequestorRef>
        <ns2:MessageIdentifier>MessageId</ns2:MessageIdentifier>
      </ServiceRequestInfo>
      <Request version="2.0:FR-IDF-2.4">
        <ns2:RequestTimestamp>2016-09-21T20:14:46.000Z/ns2:RequestTimestamp>
        <ns2:MessageIdentifier>MessageId</ns2:MessageIdentifier>
      </Request>
      <RequestExtension/>
</ns7:GetGeneralMessage>`

	requestTimestamp := time.Date(2016, time.September, 21, 20, 14, 46, 0, time.UTC)

	gmRequest := &SIRIGeneralMessageRequest{
		RequestTimestamp:  requestTimestamp,
		RequestorRef:      "ref",
		MessageIdentifier: "MessageId",
	}

	xml, err := gmRequest.BuildXML()
	if err != nil {
		t.Fatal(err)
	}
	if expectedXML != xml {
		t.Errorf("Wrong XML for Request:\n got:\n%v\nwant:\n%v", xml, expectedXML)
	}

}
<commit_msg>fix forgotten test<commit_after>package siri

import (
	"testing"
	"time"
)

func Test_SIRIGeneralMessageRequest(t *testing.T) {
	expectedXML := `<ns7:GetGeneralMessage xmlns:ns2="http://www.siri.org.uk/siri" xmlns:ns3="http://www.ifopt.org.uk/acsb" xmlns:ns4="http://www.ifopt.org.uk/ifopt" xmlns:ns5="http://datex2.eu/schema/2_0RC1/2_0" xmlns:ns6="http://wsdl.siri.org.uk/siri" xmlns:ns7="http://wsdl.siri.org.uk">
      <ServiceRequestInfo>
        <ns2:RequestTimestamp>2016-09-21T20:14:46.000Z</ns2:RequestTimestamp>
        <ns2:RequestorRef>ref</ns2:RequestorRef>
        <ns2:MessageIdentifier>MessageId</ns2:MessageIdentifier>
      </ServiceRequestInfo>
      <Request version="2.0:FR-IDF-2.4">
        <ns2:RequestTimestamp>2016-09-21T20:14:46.000Z</ns2:RequestTimestamp>
        <ns2:MessageIdentifier>MessageId</ns2:MessageIdentifier>
      </Request>
      <RequestExtension/>
</ns7:GetGeneralMessage>`

	requestTimestamp := time.Date(2016, time.September, 21, 20, 14, 46, 0, time.UTC)

	gmRequest := &SIRIGeneralMessageRequest{
		RequestTimestamp:  requestTimestamp,
		RequestorRef:      "ref",
		MessageIdentifier: "MessageId",
	}

	xml, err := gmRequest.BuildXML()
	if err != nil {
		t.Fatal(err)
	}
	if expectedXML != xml {
		t.Errorf("Wrong XML for Request:\n got:\n%v\nwant:\n%v", xml, expectedXML)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"../libs/twodee"
)

type Player struct {
	*twodee.BaseEntity
	Health      float64
	eventSystem *twodee.GameEventHandler
}

func (p *Player) MoveToListener() {}

func NewPlayer(e *twodee.BaseEntity, eventSystem *twodee.GameEventHandler) (player *Player) {
	player = &Player{
		e,
		100.0,
		eventSystem,
	}
	return
}
<commit_msg>Have Player listed for move events and also unregister its observer.<commit_after>package main

import (
	"../libs/twodee"
)

type Player struct {
	*twodee.BaseEntity
	Health           float64
	eventSystem      *twodee.GameEventHandler
	moveToObserverId int
}

func (p *Player) MoveToObserver(e twodee.GETyper) {}

func (p *Player) Delete() {
	eventSystem.RemoveObserver(PlayerMove, moveToObserverId)
}

func NewPlayer(e *twodee.BaseEntity, eventSystem *twodee.GameEventHandler) (player *Player) {
	player = &Player{
		e,
		100.0,
		eventSystem,
		-1,
	}
	player.moveToObserverId = eventSystem.AddObserver(PlayerMove, player.MoveToObserver)
	return
}
<|endoftext|>


<commit_before>package main

var (
	// Map incoming response types to their internal structs
	ResponseType = map[uint8]Response{
		0xD2: &Temps{},
		0xE0: &Bypass{},
	}
)

// Temps holds the various temperature readings
// from the ventilation unit.
type Temps struct {
	Comfort     temperature
	OutsideAir  temperature
	SupplyAir   temperature
	OutAir      temperature
	ExhaustAir  temperature
	GeoHeat     temperature
	Reheating   temperature
	KitchenHood temperature
}

// UnmarshalBinary unmarshals a Temps structure to the binary
// representation. Fixed length is 9 bytes.
func (t *Temps) UnmarshalBinary(in []byte) error {

	if len(in) != 9 {
		return errPktLen
	}

	t.Comfort.UnmarshalBinary(in[0])
	t.OutsideAir.UnmarshalBinary(in[1])
	t.SupplyAir.UnmarshalBinary(in[2])
	t.OutAir.UnmarshalBinary(in[3])
	t.ExhaustAir.UnmarshalBinary(in[4])
	t.GeoHeat.UnmarshalBinary(in[6])
	t.Reheating.UnmarshalBinary(in[7])
	t.KitchenHood.UnmarshalBinary(in[8])

	return nil
}

type Bypass struct {
	Factor     uint8
	Level      uint8
	Correction uint8
	SummerMode bool
}

func (b *Bypass) UnmarshalBinary(in []byte) error {

	b.Factor = in[2]
	b.Level = in[3]
	b.Correction = in[4]
	b.SummerMode = in[6] == 1

	return nil
}
<commit_msg>Document response types, add size check on Bypass<commit_after>package main

var (
	// Map incoming response types to their internal structs
	ResponseType = map[uint8]Response{
		0xD2: &Temps{},
		0xE0: &Bypass{},
	}
)

// Type Temps holds the various temperature readings
// from the ventilation unit.
type Temps struct {
	Comfort     temperature
	OutsideAir  temperature
	SupplyAir   temperature
	OutAir      temperature
	ExhaustAir  temperature
	GeoHeat     temperature
	Reheating   temperature
	KitchenHood temperature
}

// UnmarshalBinary unmarshals the binary representation
// into a Temps structure. Fixed length is 9 bytes.
func (t *Temps) UnmarshalBinary(in []byte) error {

	if len(in) != 9 {
		return errPktLen
	}

	t.Comfort.UnmarshalBinary(in[0])
	t.OutsideAir.UnmarshalBinary(in[1])
	t.SupplyAir.UnmarshalBinary(in[2])
	t.OutAir.UnmarshalBinary(in[3])
	t.ExhaustAir.UnmarshalBinary(in[4])
	t.GeoHeat.UnmarshalBinary(in[6])
	t.Reheating.UnmarshalBinary(in[7])
	t.KitchenHood.UnmarshalBinary(in[8])

	return nil
}

// Type Bypass holds the information about
// the unit's heat exchanger bypass valve.
type Bypass struct {
	Factor     uint8
	Level      uint8
	Correction uint8
	SummerMode bool
}

// UnmarshalBinary unmarshals the binary representation
// into a Bypass structure.
func (b *Bypass) UnmarshalBinary(in []byte) error {

	if len(in) != 7 {
		return errPktLen
	}

	b.Factor = in[2]
	b.Level = in[3]
	b.Correction = in[4]
	b.SummerMode = in[6] == 1

	return nil
}
<|endoftext|>


<commit_before>package transport

import (
	"net/http"

	"google.golang.org/grpc"
)

// Service is a registerable collection of endpoints.
// These functions should be autogenerated by LZD Protobuf codegenerator.
type Service interface {
	GetDescription() ServiceDesc
}

// ServiceDesc is a description of an endpoints' collection.
// These functions should be autogenerated by LZD Protobuf codegenerator.
type ServiceDesc interface {
	RegisterGRPC(*grpc.Server)
	RegisterHTTP(Router)
	SwaggerDef() []byte
}

// Router routes HTTP requests around.
type Router interface {
	Handle(pattern string, h http.Handler)
	HandleFunc(pattern string, h http.HandlerFunc)
}
<commit_msg>Transport is fully conforming to http/ServeMux now<commit_after>package transport

import (
	"net/http"

	"google.golang.org/grpc"
)

// Service is a registerable collection of endpoints.
// These functions should be autogenerated by LZD Protobuf codegenerator.
type Service interface {
	GetDescription() ServiceDesc
}

// ServiceDesc is a description of an endpoints' collection.
// These functions should be autogenerated by LZD Protobuf codegenerator.
type ServiceDesc interface {
	RegisterGRPC(*grpc.Server)
	RegisterHTTP(Router)
	SwaggerDef() []byte
}

// Router routes HTTP requests around.
type Router interface {
	Handle(pattern string, h http.Handler)
	HandleFunc(pattern string, h func(http.ResponseWriter, *http.Request))
}
<|endoftext|>