<commit_before>package maxminddb

import (
	"bytes"
	"errors"
	"fmt"
	"net"
	"reflect"
)

const (
	// NotFound is returned by LookupOffset when a matched root record offset
	// cannot be found.
	NotFound = ^uintptr(0)

	dataSectionSeparatorSize = 16
)

var metadataStartMarker = []byte("\xAB\xCD\xEFMaxMind.com")

// Reader holds the data corresponding to the MaxMind DB file. Its only public
// field is Metadata, which contains the metadata from the MaxMind DB file.
type Reader struct {
	hasMappedFile     bool
	buffer            []byte
	decoder           decoder
	Metadata          Metadata
	ipv4Start         uint
	ipv4StartBitDepth int
}

// Metadata holds the metadata decoded from the MaxMind DB file. In particular
// in has the format version, the build time as Unix epoch time, the database
// type and description, the IP version supported, and a slice of the natural
// languages included.
type Metadata struct {
	BinaryFormatMajorVersion uint              `maxminddb:"binary_format_major_version"`
	BinaryFormatMinorVersion uint              `maxminddb:"binary_format_minor_version"`
	BuildEpoch               uint              `maxminddb:"build_epoch"`
	DatabaseType             string            `maxminddb:"database_type"`
	Description              map[string]string `maxminddb:"description"`
	IPVersion                uint              `maxminddb:"ip_version"`
	Languages                []string          `maxminddb:"languages"`
	NodeCount                uint              `maxminddb:"node_count"`
	RecordSize               uint              `maxminddb:"record_size"`
}

// FromBytes takes a byte slice corresponding to a MaxMind DB file and returns
// a Reader structure or an error.
func FromBytes(buffer []byte) (*Reader, error) {
	metadataStart := bytes.LastIndex(buffer, metadataStartMarker)

	if metadataStart == -1 {
		return nil, newInvalidDatabaseError("error opening database: invalid MaxMind DB file")
	}

	metadataStart += len(metadataStartMarker)
	metadataDecoder := decoder{buffer[metadataStart:]}

	var metadata Metadata

	rvMetdata := reflect.ValueOf(&metadata)
	_, err := metadataDecoder.decode(0, rvMetdata, 0)
	if err != nil {
		return nil, err
	}

	searchTreeSize := metadata.NodeCount * metadata.RecordSize / 4
	dataSectionStart := searchTreeSize + dataSectionSeparatorSize
	dataSectionEnd := uint(metadataStart - len(metadataStartMarker))
	if dataSectionStart > dataSectionEnd {
		return nil, newInvalidDatabaseError("the MaxMind DB contains invalid metadata")
	}
	d := decoder{
		buffer[searchTreeSize+dataSectionSeparatorSize : metadataStart-len(metadataStartMarker)],
	}

	reader := &Reader{
		buffer:    buffer,
		decoder:   d,
		Metadata:  metadata,
		ipv4Start: 0,
	}

	err = reader.setIPv4Start()

	return reader, err
}

func (r *Reader) setIPv4Start() error {
	if r.Metadata.IPVersion != 6 {
		return nil
	}

	nodeCount := r.Metadata.NodeCount

	node := uint(0)
	var err error
	i := 0
	for ; i < 96 && node < nodeCount; i++ {
		node, err = r.readNode(node, 0)
		if err != nil {
			return err
		}
	}
	r.ipv4Start = node
	r.ipv4StartBitDepth = i
	return err
}

// Lookup retrieves the database record for ip and stores it in the value
// pointed to by result. If result is nil or not a pointer, an error is
// returned. If the data in the database record cannot be stored in result
// because of type differences, an UnmarshalTypeError is returned. If the
// database is invalid or otherwise cannot be read, an InvalidDatabaseError
// is returned.
func (r *Reader) Lookup(ip net.IP, result interface{}) error {
	if r.buffer == nil {
		return errors.New("cannot call Lookup on a closed database")
	}
	pointer, _, _, err := r.lookupPointer(ip)
	if pointer == 0 || err != nil {
		return err
	}
	return r.retrieveData(pointer, result)
}

// LookupNetwork retrieves the database record for ip and stores it in the
// value pointed to by result. The network returned is the network associated
// with the data record in the database. The ok return value indicates whether
// the database contained a record for the ip.
//
// If result is nil or not a pointer, an error is returned. If the data in the
// database record cannot be stored in result because of type differences, an
// UnmarshalTypeError is returned. If the database is invalid or otherwise
// cannot be read, an InvalidDatabaseError is returned.
func (r *Reader) LookupNetwork(ip net.IP, result interface{}) (network *net.IPNet, ok bool, err error) {
	if r.buffer == nil {
		return nil, false, errors.New("cannot call Lookup on a closed database")
	}
	pointer, prefixLength, ip, err := r.lookupPointer(ip)

	network = r.cidr(ip, prefixLength)
	if pointer == 0 || err != nil {
		return network, false, err
	}

	return network, true, r.retrieveData(pointer, result)
}

// LookupOffset maps an argument net.IP to a corresponding record offset in the
// database. NotFound is returned if no such record is found, and a record may
// otherwise be extracted by passing the returned offset to Decode. LookupOffset
// is an advanced API, which exists to provide clients with a means to cache
// previously-decoded records.
func (r *Reader) LookupOffset(ip net.IP) (uintptr, error) {
	if r.buffer == nil {
		return 0, errors.New("cannot call LookupOffset on a closed database")
	}
	pointer, _, _, err := r.lookupPointer(ip)
	if pointer == 0 || err != nil {
		return NotFound, err
	}
	return r.resolveDataPointer(pointer)
}

func (r *Reader) cidr(ip net.IP, prefixLength int) *net.IPNet {
	// This is necessary as the node that the IPv4 start is at may
	// be at a bit depth that is less that 96, i.e., ipv4Start points
	// to a leaf node.
	if r.Metadata.IPVersion == 6 &&
		len(ip) == net.IPv4len &&
		r.ipv4StartBitDepth != 96 {
		return &net.IPNet{IP: net.ParseIP("::"), Mask: net.CIDRMask(r.ipv4StartBitDepth, 128)}
	}

	mask := net.CIDRMask(prefixLength, len(ip)*8)
	return &net.IPNet{IP: ip.Mask(mask), Mask: mask}
}

// Decode the record at |offset| into |result|. The result value pointed to
// must be a data value that corresponds to a record in the database. This may
// include a struct representation of the data, a map capable of holding the
// data or an empty interface{} value.
//
// If result is a pointer to a struct, the struct need not include a field
// for every value that may be in the database. If a field is not present in
// the structure, the decoder will not decode that field, reducing the time
// required to decode the record.
//
// As a special case, a struct field of type uintptr will be used to capture
// the offset of the value. Decode may later be used to extract the stored
// value from the offset. MaxMind DBs are highly normalized: for example in
// the City database, all records of the same country will reference a
// single representative record for that country. This uintptr behavior allows
// clients to leverage this normalization in their own sub-record caching.
func (r *Reader) Decode(offset uintptr, result interface{}) error {
	if r.buffer == nil {
		return errors.New("cannot call Decode on a closed database")
	}
	return r.decode(offset, result)
}

func (r *Reader) decode(offset uintptr, result interface{}) error {
	rv := reflect.ValueOf(result)
	if rv.Kind() != reflect.Ptr || rv.IsNil() {
		return errors.New("result param must be a pointer")
	}

	_, err := r.decoder.decode(uint(offset), rv, 0)
	return err
}

func (r *Reader) lookupPointer(ip net.IP) (uint, int, net.IP, error) {
	if ip == nil {
		return 0, 0, ip, errors.New("IP passed to Lookup cannot be nil")
	}

	ipV4Address := ip.To4()
	if ipV4Address != nil {
		ip = ipV4Address
	}
	if len(ip) == 16 && r.Metadata.IPVersion == 4 {
		return 0, 0, ip, fmt.Errorf("error looking up '%s': you attempted to look up an IPv6 address in an IPv4-only database", ip.String())
	}

	bitCount := uint(len(ip) * 8)

	var node uint
	if bitCount == 32 {
		node = r.ipv4Start
	}

	nodeCount := r.Metadata.NodeCount

	i := uint(0)
	for ; i < bitCount && node < nodeCount; i++ {
		bit := uint(1) & (uint(ip[i>>3]) >> (7 - (i % 8)))

		var err error
		node, err = r.readNode(node, bit)
		if err != nil {
			return 0, int(i), ip, err
		}
	}
	if node == nodeCount {
		// Record is empty
		return 0, int(i), ip, nil
	} else if node > nodeCount {
		return node, int(i), ip, nil
	}

	return 0, int(i), ip, newInvalidDatabaseError("invalid node in search tree")
}

func (r *Reader) readNode(nodeNumber uint, index uint) (uint, error) {
	RecordSize := r.Metadata.RecordSize

	baseOffset := nodeNumber * RecordSize / 4

	var nodeBytes []byte
	var prefix uint
	switch RecordSize {
	case 24:
		offset := baseOffset + index*3
		nodeBytes = r.buffer[offset : offset+3]
	case 28:
		prefix = uint(r.buffer[baseOffset+3])
		if index != 0 {
			prefix &= 0x0F
		} else {
			prefix = (0xF0 & prefix) >> 4
		}
		offset := baseOffset + index*4
		nodeBytes = r.buffer[offset : offset+3]
	case 32:
		offset := baseOffset + index*4
		nodeBytes = r.buffer[offset : offset+4]
	default:
		return 0, newInvalidDatabaseError("unknown record size: %d", RecordSize)
	}
	return uintFromBytes(prefix, nodeBytes), nil
}

func (r *Reader) retrieveData(pointer uint, result interface{}) error {
	offset, err := r.resolveDataPointer(pointer)
	if err != nil {
		return err
	}
	return r.decode(offset, result)
}

func (r *Reader) resolveDataPointer(pointer uint) (uintptr, error) {
	var resolved = uintptr(pointer - r.Metadata.NodeCount - dataSectionSeparatorSize)

	if resolved > uintptr(len(r.buffer)) {
		return 0, newInvalidDatabaseError("the MaxMind DB file's search tree is corrupt")
	}
	return resolved, nil
}
<commit_msg>Try to clarify comment on IPv4 start bit depth<commit_after>package maxminddb

import (
	"bytes"
	"errors"
	"fmt"
	"net"
	"reflect"
)

const (
	// NotFound is returned by LookupOffset when a matched root record offset
	// cannot be found.
	NotFound = ^uintptr(0)

	dataSectionSeparatorSize = 16
)

var metadataStartMarker = []byte("\xAB\xCD\xEFMaxMind.com")

// Reader holds the data corresponding to the MaxMind DB file. Its only public
// field is Metadata, which contains the metadata from the MaxMind DB file.
type Reader struct {
	hasMappedFile     bool
	buffer            []byte
	decoder           decoder
	Metadata          Metadata
	ipv4Start         uint
	ipv4StartBitDepth int
}

// Metadata holds the metadata decoded from the MaxMind DB file. In particular
// in has the format version, the build time as Unix epoch time, the database
// type and description, the IP version supported, and a slice of the natural
// languages included.
type Metadata struct {
	BinaryFormatMajorVersion uint              `maxminddb:"binary_format_major_version"`
	BinaryFormatMinorVersion uint              `maxminddb:"binary_format_minor_version"`
	BuildEpoch               uint              `maxminddb:"build_epoch"`
	DatabaseType             string            `maxminddb:"database_type"`
	Description              map[string]string `maxminddb:"description"`
	IPVersion                uint              `maxminddb:"ip_version"`
	Languages                []string          `maxminddb:"languages"`
	NodeCount                uint              `maxminddb:"node_count"`
	RecordSize               uint              `maxminddb:"record_size"`
}

// FromBytes takes a byte slice corresponding to a MaxMind DB file and returns
// a Reader structure or an error.
func FromBytes(buffer []byte) (*Reader, error) {
	metadataStart := bytes.LastIndex(buffer, metadataStartMarker)

	if metadataStart == -1 {
		return nil, newInvalidDatabaseError("error opening database: invalid MaxMind DB file")
	}

	metadataStart += len(metadataStartMarker)
	metadataDecoder := decoder{buffer[metadataStart:]}

	var metadata Metadata

	rvMetdata := reflect.ValueOf(&metadata)
	_, err := metadataDecoder.decode(0, rvMetdata, 0)
	if err != nil {
		return nil, err
	}

	searchTreeSize := metadata.NodeCount * metadata.RecordSize / 4
	dataSectionStart := searchTreeSize + dataSectionSeparatorSize
	dataSectionEnd := uint(metadataStart - len(metadataStartMarker))
	if dataSectionStart > dataSectionEnd {
		return nil, newInvalidDatabaseError("the MaxMind DB contains invalid metadata")
	}
	d := decoder{
		buffer[searchTreeSize+dataSectionSeparatorSize : metadataStart-len(metadataStartMarker)],
	}

	reader := &Reader{
		buffer:    buffer,
		decoder:   d,
		Metadata:  metadata,
		ipv4Start: 0,
	}

	err = reader.setIPv4Start()

	return reader, err
}

func (r *Reader) setIPv4Start() error {
	if r.Metadata.IPVersion != 6 {
		return nil
	}

	nodeCount := r.Metadata.NodeCount

	node := uint(0)
	var err error
	i := 0
	for ; i < 96 && node < nodeCount; i++ {
		node, err = r.readNode(node, 0)
		if err != nil {
			return err
		}
	}
	r.ipv4Start = node
	r.ipv4StartBitDepth = i
	return err
}

// Lookup retrieves the database record for ip and stores it in the value
// pointed to by result. If result is nil or not a pointer, an error is
// returned. If the data in the database record cannot be stored in result
// because of type differences, an UnmarshalTypeError is returned. If the
// database is invalid or otherwise cannot be read, an InvalidDatabaseError
// is returned.
func (r *Reader) Lookup(ip net.IP, result interface{}) error {
	if r.buffer == nil {
		return errors.New("cannot call Lookup on a closed database")
	}
	pointer, _, _, err := r.lookupPointer(ip)
	if pointer == 0 || err != nil {
		return err
	}
	return r.retrieveData(pointer, result)
}

// LookupNetwork retrieves the database record for ip and stores it in the
// value pointed to by result. The network returned is the network associated
// with the data record in the database. The ok return value indicates whether
// the database contained a record for the ip.
//
// If result is nil or not a pointer, an error is returned. If the data in the
// database record cannot be stored in result because of type differences, an
// UnmarshalTypeError is returned. If the database is invalid or otherwise
// cannot be read, an InvalidDatabaseError is returned.
func (r *Reader) LookupNetwork(ip net.IP, result interface{}) (network *net.IPNet, ok bool, err error) {
	if r.buffer == nil {
		return nil, false, errors.New("cannot call Lookup on a closed database")
	}
	pointer, prefixLength, ip, err := r.lookupPointer(ip)

	network = r.cidr(ip, prefixLength)
	if pointer == 0 || err != nil {
		return network, false, err
	}

	return network, true, r.retrieveData(pointer, result)
}

// LookupOffset maps an argument net.IP to a corresponding record offset in the
// database. NotFound is returned if no such record is found, and a record may
// otherwise be extracted by passing the returned offset to Decode. LookupOffset
// is an advanced API, which exists to provide clients with a means to cache
// previously-decoded records.
func (r *Reader) LookupOffset(ip net.IP) (uintptr, error) {
	if r.buffer == nil {
		return 0, errors.New("cannot call LookupOffset on a closed database")
	}
	pointer, _, _, err := r.lookupPointer(ip)
	if pointer == 0 || err != nil {
		return NotFound, err
	}
	return r.resolveDataPointer(pointer)
}

func (r *Reader) cidr(ip net.IP, prefixLength int) *net.IPNet {
	// This is necessary as the node that the IPv4 start is at may
	// be at a bit depth that is less that 96, i.e., ipv4Start points
	// to a leaf node. For instance, if a record was inserted at ::/8,
	// the ipv4Start would point directly at the leaf node for the
	// record and would have a bit depth of 8. This would not happen
	// with databases currently distributed by MaxMind as all of them
	// have an IPv4 subtree that is greater than a single node.
	if r.Metadata.IPVersion == 6 &&
		len(ip) == net.IPv4len &&
		r.ipv4StartBitDepth != 96 {
		return &net.IPNet{IP: net.ParseIP("::"), Mask: net.CIDRMask(r.ipv4StartBitDepth, 128)}
	}

	mask := net.CIDRMask(prefixLength, len(ip)*8)
	return &net.IPNet{IP: ip.Mask(mask), Mask: mask}
}

// Decode the record at |offset| into |result|. The result value pointed to
// must be a data value that corresponds to a record in the database. This may
// include a struct representation of the data, a map capable of holding the
// data or an empty interface{} value.
//
// If result is a pointer to a struct, the struct need not include a field
// for every value that may be in the database. If a field is not present in
// the structure, the decoder will not decode that field, reducing the time
// required to decode the record.
//
// As a special case, a struct field of type uintptr will be used to capture
// the offset of the value. Decode may later be used to extract the stored
// value from the offset. MaxMind DBs are highly normalized: for example in
// the City database, all records of the same country will reference a
// single representative record for that country. This uintptr behavior allows
// clients to leverage this normalization in their own sub-record caching.
func (r *Reader) Decode(offset uintptr, result interface{}) error {
	if r.buffer == nil {
		return errors.New("cannot call Decode on a closed database")
	}
	return r.decode(offset, result)
}

func (r *Reader) decode(offset uintptr, result interface{}) error {
	rv := reflect.ValueOf(result)
	if rv.Kind() != reflect.Ptr || rv.IsNil() {
		return errors.New("result param must be a pointer")
	}

	_, err := r.decoder.decode(uint(offset), rv, 0)
	return err
}

func (r *Reader) lookupPointer(ip net.IP) (uint, int, net.IP, error) {
	if ip == nil {
		return 0, 0, ip, errors.New("IP passed to Lookup cannot be nil")
	}

	ipV4Address := ip.To4()
	if ipV4Address != nil {
		ip = ipV4Address
	}
	if len(ip) == 16 && r.Metadata.IPVersion == 4 {
		return 0, 0, ip, fmt.Errorf("error looking up '%s': you attempted to look up an IPv6 address in an IPv4-only database", ip.String())
	}

	bitCount := uint(len(ip) * 8)

	var node uint
	if bitCount == 32 {
		node = r.ipv4Start
	}

	nodeCount := r.Metadata.NodeCount

	i := uint(0)
	for ; i < bitCount && node < nodeCount; i++ {
		bit := uint(1) & (uint(ip[i>>3]) >> (7 - (i % 8)))

		var err error
		node, err = r.readNode(node, bit)
		if err != nil {
			return 0, int(i), ip, err
		}
	}
	if node == nodeCount {
		// Record is empty
		return 0, int(i), ip, nil
	} else if node > nodeCount {
		return node, int(i), ip, nil
	}

	return 0, int(i), ip, newInvalidDatabaseError("invalid node in search tree")
}

func (r *Reader) readNode(nodeNumber uint, index uint) (uint, error) {
	RecordSize := r.Metadata.RecordSize

	baseOffset := nodeNumber * RecordSize / 4

	var nodeBytes []byte
	var prefix uint
	switch RecordSize {
	case 24:
		offset := baseOffset + index*3
		nodeBytes = r.buffer[offset : offset+3]
	case 28:
		prefix = uint(r.buffer[baseOffset+3])
		if index != 0 {
			prefix &= 0x0F
		} else {
			prefix = (0xF0 & prefix) >> 4
		}
		offset := baseOffset + index*4
		nodeBytes = r.buffer[offset : offset+3]
	case 32:
		offset := baseOffset + index*4
		nodeBytes = r.buffer[offset : offset+4]
	default:
		return 0, newInvalidDatabaseError("unknown record size: %d", RecordSize)
	}
	return uintFromBytes(prefix, nodeBytes), nil
}

func (r *Reader) retrieveData(pointer uint, result interface{}) error {
	offset, err := r.resolveDataPointer(pointer)
	if err != nil {
		return err
	}
	return r.decode(offset, result)
}

func (r *Reader) resolveDataPointer(pointer uint) (uintptr, error) {
	var resolved = uintptr(pointer - r.Metadata.NodeCount - dataSectionSeparatorSize)

	if resolved > uintptr(len(r.buffer)) {
		return 0, newInvalidDatabaseError("the MaxMind DB file's search tree is corrupt")
	}
	return resolved, nil
}
<|endoftext|>


<commit_before>package iso9660

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"os"

	"github.com/c4milo/gotoolkit"
)

var (
	// ErrInvalidImage is returned when an attempt to unpack the image Primary Volume Descriptor failed or
	// when the end of the image was reached without finding a primary volume descriptor
	ErrInvalidImage = func(err error) error { return fmt.Errorf("invalid-iso9660-image: %s", err) }
	// ErrCorruptedImage is returned when a seek operation, on the image, failed.
	ErrCorruptedImage = func(err error) error { return fmt.Errorf("corrupted-image: %s", err) }
)

// Reader defines the state of the ISO9660 image reader. It needs to be instantiated
// from its constructor.
type Reader struct {
	// File descriptor to the opened ISO image
	image io.ReadSeeker
	// Copy of unencoded Primary Volume Descriptor
	pvd PrimaryVolume
	// Queue used to walk through file system iteratively
	queue gotoolkit.Queue
	// Current sector
	sector uint32
	// Current bytes read from current sector.
	read uint32
}

// NewReader creates a new ISO9660 reader.
func NewReader(rs io.ReadSeeker) (*Reader, error) {
	// Starts reading from image data area
	sector := dataAreaSector
	// Iterates over volume descriptors until it finds the primary volume descriptor
	// or an error condition.
	for {
		offset, err := rs.Seek(int64(sector*sectorSize), os.SEEK_SET)
		if err != nil {
			return nil, ErrCorruptedImage(err)
		}

		var volDesc VolumeDescriptor
		if err := binary.Read(rs, binary.BigEndian, &volDesc); err != nil {
			return nil, ErrCorruptedImage(err)
		}

		if volDesc.Type == primaryVol {
			// backs up to the beginning of the sector again in order to unpack
			// the entire primary volume descriptor more easily.
			if _, err := rs.Seek(offset, os.SEEK_SET); err != nil {
				return nil, ErrCorruptedImage(err)
			}

			reader := new(Reader)
			reader.image = rs
			reader.queue = new(gotoolkit.SliceQueue)

			if err := reader.unpackPVD(); err != nil {
				return nil, ErrCorruptedImage(err)
			}

			return reader, nil
		}

		if volDesc.Type == volSetTerminator {
			return nil, ErrInvalidImage(errors.New("Volume Set Terminator reached. A Primary Volume Descriptor was not found."))
		}
		sector++
	}
}

// Next moves onto the next directory record using breadth-first search one step
// at the time. It first moves
func (r *Reader) Next() (os.FileInfo, error) {
	if r == nil {
		panic("missing reader instance. Use the constructor to create a Reader instance.")
	}

	if r.queue.IsEmpty() {
		return nil, io.EOF
	}

	// We only dequeue the directory when it does not contain more children
	// or when it is empty and there is no children to iterate over.
	item, err := r.queue.Peek()
	if err != nil {
		panic(err)
	}
	fi := item.(FileStat)

	if r.sector == 0 {
		r.sector = fi.ExtentLocationBE
	}

	var drecord FileStat
	var len byte
	// This loops exists so we can skip .. and . directories
	for {
		if (r.read % sectorSize) == 0 {
			_, err := r.image.Seek(int64(r.sector*sectorSize), os.SEEK_SET)
			if err != nil {
				return nil, ErrCorruptedImage(err)
			}
			r.sector++
		}

		if len, err = r.unpackDRecord(&drecord); err != nil && err != io.EOF {
			return nil, ErrCorruptedImage(err)
		}

		if err == io.EOF {
			// directory record is empty, sector wasted, move onto next sector.
			rsize := (sectorSize - (r.read % sectorSize))
			buf := make([]byte, rsize)
			if err := binary.Read(r.image, binary.BigEndian, buf); err != nil {
				return nil, ErrCorruptedImage(err)
			}
			r.read += rsize
		}
		r.read += uint32(len)

		if drecord.fileID != "\x00" && drecord.fileID != "\x01" {
			break
		}
	}
	// If there is no more entries in the current directory, dequeue it
	// and move on the next directory in the queue.
	if r.read > fi.ExtentLengthBE {
		r.read = 0
		r.sector = 0
		r.queue.Dequeue()
	}

	if drecord.fileID == "" {
		return r.Next()
	}

	if drecord.IsDir() {
		r.queue.Enqueue(drecord)
	} else {
		drecord.image = r.image
	}

	return &drecord, nil
}

// unpackDRecord unpacks directory record bits into Go's struct
func (r *Reader) unpackDRecord(fi *FileStat) (byte, error) {
	// Gets the directory record length
	var len byte
	if err := binary.Read(r.image, binary.BigEndian, &len); err != nil {
		return len, ErrCorruptedImage(err)
	}

	if len == 0 {
		return len + 1, io.EOF
	}

	// Reads directory record into Go struct
	var drecord DirectoryRecord
	if err := binary.Read(r.image, binary.BigEndian, &drecord); err != nil {
		return len, ErrCorruptedImage(err)
	}

	fi.DirectoryRecord = drecord
	// Gets the name
	name := make([]byte, drecord.FileIDLength)
	if err := binary.Read(r.image, binary.BigEndian, name); err != nil {
		return len, ErrCorruptedImage(err)
	}
	fi.fileID = string(name)

	// Padding field as per section 9.1.12 in ECMA-119
	if (drecord.FileIDLength % 2) == 0 {
		var zero byte
		if err := binary.Read(r.image, binary.BigEndian, &zero); err != nil {
			return len, ErrCorruptedImage(err)
		}
	}

	// System use field as per section 9.1.13 in ECMA-119
	// Directory record has 34 bytes in addition to the name's
	// variable length and the padding field mentioned in section 9.1.12
	totalLen := 34 + drecord.FileIDLength - (drecord.FileIDLength % 2)
	sysUseLen := int64(len - totalLen)
	if sysUseLen > 0 {
		sysData := make([]byte, sysUseLen)
		if err := binary.Read(r.image, binary.BigEndian, sysData); err != nil {
			return len, ErrCorruptedImage(err)
		}
	}
	return len, nil
}

// unpackPVD unpacks Primary Volume Descriptor in three phases. This is
// because the root directory record is a variable-length record and Go's binary
// package doesn't support unpacking variable-length structs easily.
func (r *Reader) unpackPVD() error {
	// Unpack first half
	var pvd1 PrimaryVolumePart1
	if err := binary.Read(r.image, binary.BigEndian, &pvd1); err != nil {
		return ErrCorruptedImage(err)
	}
	r.pvd.PrimaryVolumePart1 = pvd1

	// Unpack root directory record
	var drecord FileStat
	if _, err := r.unpackDRecord(&drecord); err != nil {
		return ErrCorruptedImage(err)
	}
	r.pvd.DirectoryRecord = drecord.DirectoryRecord
	r.queue.Enqueue(drecord)

	// Unpack second half
	var pvd2 PrimaryVolumePart2
	if err := binary.Read(r.image, binary.BigEndian, &pvd2); err != nil {
		return ErrCorruptedImage(err)
	}
	r.pvd.PrimaryVolumePart2 = pvd2

	return nil
}
<commit_msg>Renames dir records so they contain full file path<commit_after>package iso9660

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"

	"github.com/c4milo/gotoolkit"
)

var (
	// ErrInvalidImage is returned when an attempt to unpack the image Primary Volume Descriptor failed or
	// when the end of the image was reached without finding a primary volume descriptor
	ErrInvalidImage = func(err error) error { return fmt.Errorf("invalid-iso9660-image: %s", err) }
	// ErrCorruptedImage is returned when a seek operation, on the image, failed.
	ErrCorruptedImage = func(err error) error { return fmt.Errorf("corrupted-image: %s", err) }
)

// Reader defines the state of the ISO9660 image reader. It needs to be instantiated
// from its constructor.
type Reader struct {
	// File descriptor to the opened ISO image
	image io.ReadSeeker
	// Copy of unencoded Primary Volume Descriptor
	pvd PrimaryVolume
	// Queue used to walk through file system iteratively
	queue gotoolkit.Queue
	// Current sector
	sector uint32
	// Current bytes read from current sector.
	read uint32
}

// NewReader creates a new ISO9660 reader.
func NewReader(rs io.ReadSeeker) (*Reader, error) {
	// Starts reading from image data area
	sector := dataAreaSector
	// Iterates over volume descriptors until it finds the primary volume descriptor
	// or an error condition.
	for {
		offset, err := rs.Seek(int64(sector*sectorSize), os.SEEK_SET)
		if err != nil {
			return nil, ErrCorruptedImage(err)
		}

		var volDesc VolumeDescriptor
		if err := binary.Read(rs, binary.BigEndian, &volDesc); err != nil {
			return nil, ErrCorruptedImage(err)
		}

		if volDesc.Type == primaryVol {
			// backs up to the beginning of the sector again in order to unpack
			// the entire primary volume descriptor more easily.
			if _, err := rs.Seek(offset, os.SEEK_SET); err != nil {
				return nil, ErrCorruptedImage(err)
			}

			reader := new(Reader)
			reader.image = rs
			reader.queue = new(gotoolkit.SliceQueue)

			if err := reader.unpackPVD(); err != nil {
				return nil, ErrCorruptedImage(err)
			}

			return reader, nil
		}

		if volDesc.Type == volSetTerminator {
			return nil, ErrInvalidImage(errors.New("Volume Set Terminator reached. A Primary Volume Descriptor was not found."))
		}
		sector++
	}
}

// Next moves onto the next directory record.
func (r *Reader) Next() (os.FileInfo, error) {
	if r == nil {
		panic("missing reader instance. Use the constructor to create a Reader instance.")
	}

	if r.queue.IsEmpty() {
		return nil, io.EOF
	}

	// We only dequeue the directory when it does not contain more children
	// or when it is empty and there is no children to iterate over.
	item, err := r.queue.Peek()
	if err != nil {
		panic(err)
	}
	fi := item.(FileStat)

	if r.sector == 0 {
		r.sector = fi.ExtentLocationBE
	}

	var drecord FileStat
	var len byte
	// This loops exists so we can skip .. and . directories
	for {
		if (r.read % sectorSize) == 0 {
			_, err := r.image.Seek(int64(r.sector*sectorSize), os.SEEK_SET)
			if err != nil {
				return nil, ErrCorruptedImage(err)
			}
			r.sector++
		}

		if len, err = r.unpackDRecord(&drecord); err != nil && err != io.EOF {
			return nil, ErrCorruptedImage(err)
		}

		if err == io.EOF {
			// directory record is empty, sector space wasted, move onto next sector.
			rsize := (sectorSize - (r.read % sectorSize))
			buf := make([]byte, rsize)
			if err := binary.Read(r.image, binary.BigEndian, buf); err != nil {
				return nil, ErrCorruptedImage(err)
			}
			r.read += rsize
		}
		r.read += uint32(len)

		if drecord.fileID != "\x00" && drecord.fileID != "\x01" {
			break
		}
	}
	// If there is no more entries in the current directory, dequeue it
	// and move on the next directory in the queue.
	if r.read > fi.ExtentLengthBE {
		r.read = 0
		r.sector = 0
		r.queue.Dequeue()
	}

	if drecord.fileID == "" {
		return r.Next()
	}

	if drecord.IsDir() {
		parent := fi.Name()
		if parent == "\x00" {
			parent = "/"
		}
		drecord.fileID = filepath.Join(parent, drecord.fileID)

		r.queue.Enqueue(drecord)
	} else {
		drecord.image = r.image
	}

	return &drecord, nil
}

// unpackDRecord unpacks directory record bits into Go's struct
func (r *Reader) unpackDRecord(fi *FileStat) (byte, error) {
	// Gets the directory record length
	var len byte
	if err := binary.Read(r.image, binary.BigEndian, &len); err != nil {
		return len, ErrCorruptedImage(err)
	}

	if len == 0 {
		return len + 1, io.EOF
	}

	// Reads directory record into Go struct
	var drecord DirectoryRecord
	if err := binary.Read(r.image, binary.BigEndian, &drecord); err != nil {
		return len, ErrCorruptedImage(err)
	}

	fi.DirectoryRecord = drecord
	// Gets the name
	name := make([]byte, drecord.FileIDLength)
	if err := binary.Read(r.image, binary.BigEndian, name); err != nil {
		return len, ErrCorruptedImage(err)
	}
	fi.fileID = string(name)

	// Padding field as per section 9.1.12 in ECMA-119
	if (drecord.FileIDLength % 2) == 0 {
		var zero byte
		if err := binary.Read(r.image, binary.BigEndian, &zero); err != nil {
			return len, ErrCorruptedImage(err)
		}
	}

	// System use field as per section 9.1.13 in ECMA-119
	// Directory record has 34 bytes in addition to the name's
	// variable length and the padding field mentioned in section 9.1.12
	totalLen := 34 + drecord.FileIDLength - (drecord.FileIDLength % 2)
	sysUseLen := int64(len - totalLen)
	if sysUseLen > 0 {
		sysData := make([]byte, sysUseLen)
		if err := binary.Read(r.image, binary.BigEndian, sysData); err != nil {
			return len, ErrCorruptedImage(err)
		}
	}
	return len, nil
}

// unpackPVD unpacks Primary Volume Descriptor in three phases. This is
// because the root directory record is a variable-length record and Go's binary
// package doesn't support unpacking variable-length structs easily.
func (r *Reader) unpackPVD() error {
	// Unpack first half
	var pvd1 PrimaryVolumePart1
	if err := binary.Read(r.image, binary.BigEndian, &pvd1); err != nil {
		return ErrCorruptedImage(err)
	}
	r.pvd.PrimaryVolumePart1 = pvd1

	// Unpack root directory record
	var drecord FileStat
	if _, err := r.unpackDRecord(&drecord); err != nil {
		return ErrCorruptedImage(err)
	}
	r.pvd.DirectoryRecord = drecord.DirectoryRecord
	r.queue.Enqueue(drecord)

	// Unpack second half
	var pvd2 PrimaryVolumePart2
	if err := binary.Read(r.image, binary.BigEndian, &pvd2); err != nil {
		return ErrCorruptedImage(err)
	}
	r.pvd.PrimaryVolumePart2 = pvd2

	return nil
}
<|endoftext|>


<commit_before>package vsphere

const (
	BaseOps = `---
- type: replace
  path: /azs
  value:
  - name: z1
    cloud_properties:
      datacenters:
      - name: ((vcenter_dc))
        clusters:
        - ((vcenter_cluster)):
            resource_pool: ((vcenter_rp))
  - name: z2
    cloud_properties:
      datacenters:
      - name: ((vcenter_dc))
        clusters:
        - ((vcenter_cluster)):
            resource_pool: ((vcenter_rp))
  - name: z3
    cloud_properties:
      datacenters:
      - name: ((vcenter_dc))
        clusters:
        - ((vcenter_cluster)):
            resource_pool: ((vcenter_rp))

- type: replace
  path: /compilation
  value:
    workers: 5
    reuse_compilation_vms: true
    az: z1
    vm_type: default
    network: default

- type: replace
  path: /disk_types/name=default/disk_size?
  value: 3000

- type: replace
  path: /networks
  value:
  - name: default
    type: manual
    subnets:
    - range: ((internal_cidr))
      gateway: ((internal_gw))
      azs: [z1, z2, z3]
      dns: [8.8.8.8]
      reserved: [((jumpbox__internal_ip))]
      cloud_properties:
        name: ((network_name))

- type: replace
  path: /vm_types/name=default/cloud_properties?
  value:
    cpu: 2
    ram: 8_192
    disk: 30_000

- type: replace
  path: /vm_types/name=large/cloud_properties?
  value:
    cpu: 2
    ram: 8_192
    disk: 640_000

- type: replace
  path: /vm_types/name=minimal/cloud_properties?
  value:
    cpu: 1
    ram: 4096
    disk: 10240

- type: replace
  path: /vm_types/name=small/cloud_properties?
  value:
    cpu: 2
    ram: 8192
    disk: 10240

- type: replace
  path: /vm_types/name=small-highmem/cloud_properties?
  value:
    cpu: 4
    ram: 32768
    disk: 10240

- type: replace
  path: /vm_extensions/name=50GB_ephemeral_disk/cloud_properties?
  value:
    disk: 51200

- type: replace
  path: /vm_extensions/name=100GB_ephemeral_disk/cloud_properties?
  value:
    disk: 102400

- type: replace
  path: /vm_extensions/-
  value:
    name: cf-router-network-properties

- type: replace
  path: /vm_extensions/-
  value:
    name: cf-tcp-router-network-properties

- type: replace
  path: /vm_extensions/-
  value:
    name: diego-ssh-proxy-network-properties
`
)
<commit_msg>Add disk value for 500 GB ephemeral disk vm extension for vsphere<commit_after>package vsphere

const (
	BaseOps = `---
- type: replace
  path: /azs
  value:
  - name: z1
    cloud_properties:
      datacenters:
      - name: ((vcenter_dc))
        clusters:
        - ((vcenter_cluster)):
            resource_pool: ((vcenter_rp))
  - name: z2
    cloud_properties:
      datacenters:
      - name: ((vcenter_dc))
        clusters:
        - ((vcenter_cluster)):
            resource_pool: ((vcenter_rp))
  - name: z3
    cloud_properties:
      datacenters:
      - name: ((vcenter_dc))
        clusters:
        - ((vcenter_cluster)):
            resource_pool: ((vcenter_rp))

- type: replace
  path: /compilation
  value:
    workers: 5
    reuse_compilation_vms: true
    az: z1
    vm_type: default
    network: default

- type: replace
  path: /disk_types/name=default/disk_size?
  value: 3000

- type: replace
  path: /networks
  value:
  - name: default
    type: manual
    subnets:
    - range: ((internal_cidr))
      gateway: ((internal_gw))
      azs: [z1, z2, z3]
      dns: [8.8.8.8]
      reserved: [((jumpbox__internal_ip))]
      cloud_properties:
        name: ((network_name))

- type: replace
  path: /vm_types/name=default/cloud_properties?
  value:
    cpu: 2
    ram: 8_192
    disk: 30_000

- type: replace
  path: /vm_types/name=large/cloud_properties?
  value:
    cpu: 2
    ram: 8_192
    disk: 640_000

- type: replace
  path: /vm_types/name=minimal/cloud_properties?
  value:
    cpu: 1
    ram: 4096
    disk: 10240

- type: replace
  path: /vm_types/name=small/cloud_properties?
  value:
    cpu: 2
    ram: 8192
    disk: 10240

- type: replace
  path: /vm_types/name=small-highmem/cloud_properties?
  value:
    cpu: 4
    ram: 32768
    disk: 10240

- type: replace
  path: /vm_extensions/name=50GB_ephemeral_disk/cloud_properties?
  value:
    disk: 51200

- type: replace
  path: /vm_extensions/name=100GB_ephemeral_disk/cloud_properties?
  value:
    disk: 102400

- type: replace
  path: /vm_extensions/name=500GB_ephemeral_disk/cloud_properties?
  value:
    disk: 512000

- type: replace
  path: /vm_extensions/-
  value:
    name: cf-router-network-properties

- type: replace
  path: /vm_extensions/-
  value:
    name: cf-tcp-router-network-properties

- type: replace
  path: /vm_extensions/-
  value:
    name: diego-ssh-proxy-network-properties
`
)
<|endoftext|>


<commit_before>package blockscore

import "testing"

func init() {
	// In order to execute the Unit Test, you must set your BlockScore
	// API key as environment variable: BLOCKSCORE_API_KEY=xxxx
	if err := SetKeyEnv(); err != nil {
		panic(err)
	}
}

var peopleParams = PersonParams{
	NameFirst:          "John",
	NameMiddle:         "P",
	NameLast:           "Denver",
	DocumentType:       "ssn",
	DocumentValue:      "0000",
	BirthDay:           7,
	BirthMonth:         6,
	BirthYear:          1980,
	AddressStreet1:     "1234 Main Street",
	AddressStreet2:     "APT 12",
	AddressCity:        "Palo Alto",
	AddressSubdivision: "California",
	AddressPostalCode:  "94025",
	AddressCountryCode: "US",
	PhoneNumber:        "123-456-78910",
	IPAddress:          "127.0.0.1",
	Note:               "Hello, world",
}

var personID string

func TestCreatePeople(t *testing.T) {
	// Create the People.
	resp, err := People.Create(&peopleParams)

	if err != nil {
		t.Errorf("Expected successful People creation, got Error %s", err.Error())
	}

	personID = resp.Id

	if resp.NameFirst != peopleParams.NameFirst {
		t.Errorf("Expected NameFirst: %s, got: %s", peopleParams.NameFirst, resp.NameFirst)
	}

	if resp.NameMiddle != peopleParams.NameMiddle {
		t.Errorf("Expected NameMiddle: %s, got: %s", peopleParams.NameMiddle, resp.NameMiddle)
	}

	if resp.NameLast != peopleParams.NameLast {
		t.Errorf("Expected NameLast: %s, got: %s", peopleParams.NameLast, resp.NameLast)
	}

	if resp.DocumentType != peopleParams.DocumentType {
		t.Errorf("Expected DocumentType: %s, got: %s", peopleParams.DocumentType, resp.DocumentType)
	}

	if resp.DocumentValue != peopleParams.DocumentValue {
		t.Errorf("Expected DocumentValue: %s, got: %s", peopleParams.DocumentValue, resp.DocumentValue)
	}

	if resp.BirthDay != peopleParams.BirthDay {
		t.Errorf("Expected BirthDay: %s, got: %s", peopleParams.BirthDay, resp.BirthDay)
	}

	if resp.BirthMonth != peopleParams.BirthMonth {
		t.Errorf("Expected BirthMonth: %s, got: %s", peopleParams.BirthMonth, resp.BirthMonth)
	}

	if resp.BirthYear != peopleParams.BirthYear {
		t.Errorf("Expected BirthYear: %s, got: %s", peopleParams.BirthYear, resp.BirthYear)
	}

	if resp.AddressStreet1 != peopleParams.AddressStreet1 {
		t.Errorf("Expected AddressStreet1: %s, got: %s", peopleParams.AddressStreet1, resp.AddressStreet1)
	}

	if resp.AddressStreet2 != peopleParams.AddressStreet2 {
		t.Errorf("Expected AddressStreet2: %s, got: %s", peopleParams.AddressStreet2, resp.AddressStreet2)
	}

	if resp.AddressCity != peopleParams.AddressCity {
		t.Errorf("Expected AddressCity: %s, got: %s", peopleParams.AddressCity, resp.AddressCity)
	}

	if resp.AddressSubdivision != peopleParams.AddressSubdivision {
		t.Errorf("Expected AddressSubdivision: %s, got: %s", peopleParams.AddressSubdivision, resp.AddressSubdivision)
	}

	if resp.AddressPostalCode != peopleParams.AddressPostalCode {
		t.Errorf("Expected AddressPostalCode: %s, got: %s", peopleParams.AddressPostalCode, resp.AddressPostalCode)
	}

	if resp.AddressCountryCode != peopleParams.AddressCountryCode {
		t.Errorf("Expected AddressCountryCode: %s, got: %s", peopleParams.AddressCountryCode, resp.AddressCountryCode)
	}

	if resp.PhoneNumber != peopleParams.PhoneNumber {
		t.Errorf("Expected PhoneNumber: %s, got: %s", peopleParams.PhoneNumber, resp.PhoneNumber)
	}

	if resp.IPAddress != peopleParams.IPAddress {
		t.Errorf("Expected IPAddress: %s, got: %s", peopleParams.IPAddress, resp.IPAddress)
	}

	if resp.Note != peopleParams.Note {
		t.Errorf("Expected Note: %s, got: %s", peopleParams.Note, resp.Note)
	}
}

func TestRetrievePeople(t *testing.T) {
	resp, err := People.Retrieve(personID)

	if err != nil {
		t.Errorf("Expected successful People creation, got Error %s", err.Error())
	}

	if resp.NameFirst != peopleParams.NameFirst {
		t.Errorf("Expected NameFirst: %s, got: %s", peopleParams.NameFirst, resp.NameFirst)
	}

	if resp.NameMiddle != peopleParams.NameMiddle {
		t.Errorf("Expected NameMiddle: %s, got: %s", peopleParams.NameMiddle, resp.NameMiddle)
	}

	if resp.NameLast != peopleParams.NameLast {
		t.Errorf("Expected NameLast: %s, got: %s", peopleParams.NameLast, resp.NameLast)
	}

	if resp.DocumentType != peopleParams.DocumentType {
		t.Errorf("Expected DocumentType: %s, got: %s", peopleParams.DocumentType, resp.DocumentType)
	}

	if resp.DocumentValue != peopleParams.DocumentValue {
		t.Errorf("Expected DocumentValue: %s, got: %s", peopleParams.DocumentValue, resp.DocumentValue)
	}

	if resp.BirthDay != peopleParams.BirthDay {
		t.Errorf("Expected BirthDay: %s, got: %s", peopleParams.BirthDay, resp.BirthDay)
	}

	if resp.BirthMonth != peopleParams.BirthMonth {
		t.Errorf("Expected BirthMonth: %s, got: %s", peopleParams.BirthMonth, resp.BirthMonth)
	}

	if resp.BirthYear != peopleParams.BirthYear {
		t.Errorf("Expected BirthYear: %s, got: %s", peopleParams.BirthYear, resp.BirthYear)
	}

	if resp.AddressStreet1 != peopleParams.AddressStreet1 {
		t.Errorf("Expected AddressStreet1: %s, got: %s", peopleParams.AddressStreet1, resp.AddressStreet1)
	}

	if resp.AddressStreet2 != peopleParams.AddressStreet2 {
		t.Errorf("Expected AddressStreet2: %s, got: %s", peopleParams.AddressStreet2, resp.AddressStreet2)
	}

	if resp.AddressCity != peopleParams.AddressCity {
		t.Errorf("Expected AddressCity: %s, got: %s", peopleParams.AddressCity, resp.AddressCity)
	}

	if resp.AddressSubdivision != peopleParams.AddressSubdivision {
		t.Errorf("Expected AddressSubdivision: %s, got: %s", peopleParams.AddressSubdivision, resp.AddressSubdivision)
	}

	if resp.AddressPostalCode != peopleParams.AddressPostalCode {
		t.Errorf("Expected AddressPostalCode: %s, got: %s", peopleParams.AddressPostalCode, resp.AddressPostalCode)
	}

	if resp.AddressCountryCode != peopleParams.AddressCountryCode {
		t.Errorf("Expected AddressCountryCode: %s, got: %s", peopleParams.AddressCountryCode, resp.AddressCountryCode)
	}

	if resp.PhoneNumber != peopleParams.PhoneNumber {
		t.Errorf("Expected PhoneNumber: %s, got: %s", peopleParams.PhoneNumber, resp.PhoneNumber)
	}

	if resp.IPAddress != peopleParams.IPAddress {
		t.Errorf("Expected IPAddress: %s, got: %s", peopleParams.IPAddress, resp.IPAddress)
	}

	if resp.Note != peopleParams.Note {
		t.Errorf("Expected Note: %s, got: %s", peopleParams.Note, resp.Note)
	}
}

func TestListPeople(t *testing.T) {
	_, err := People.List()
	if err != nil {
		t.Errorf("Error: %s", err.Error())
	}
}

func TestListNPeople(t *testing.T) {
	_, err := People.ListN(2, 5)
	if err != nil {
		t.Errorf("Error: %s", err.Error())
	}
}
<commit_msg>tweak printed text<commit_after>package blockscore

import "testing"

func init() {
	// In order to execute the Unit Test, you must set your BlockScore
	// API key as environment variable: BLOCKSCORE_API_KEY=xxxx
	if err := SetKeyEnv(); err != nil {
		panic(err)
	}
}

var peopleParams = PersonParams{
	NameFirst:          "John",
	NameMiddle:         "P",
	NameLast:           "Denver",
	DocumentType:       "ssn",
	DocumentValue:      "0000",
	BirthDay:           7,
	BirthMonth:         6,
	BirthYear:          1980,
	AddressStreet1:     "1234 Main Street",
	AddressStreet2:     "APT 12",
	AddressCity:        "Palo Alto",
	AddressSubdivision: "California",
	AddressPostalCode:  "94025",
	AddressCountryCode: "US",
	PhoneNumber:        "123-456-78910",
	IPAddress:          "127.0.0.1",
	Note:               "Hello, world",
}

var personID string

func TestCreatePeople(t *testing.T) {
	// Create the People.
	resp, err := People.Create(&peopleParams)

	if err != nil {
		t.Errorf("Expected successful Person creation, got Error %s", err.Error())
	}

	personID = resp.Id

	if resp.NameFirst != peopleParams.NameFirst {
		t.Errorf("Expected NameFirst: %s, got: %s", peopleParams.NameFirst, resp.NameFirst)
	}

	if resp.NameMiddle != peopleParams.NameMiddle {
		t.Errorf("Expected NameMiddle: %s, got: %s", peopleParams.NameMiddle, resp.NameMiddle)
	}

	if resp.NameLast != peopleParams.NameLast {
		t.Errorf("Expected NameLast: %s, got: %s", peopleParams.NameLast, resp.NameLast)
	}

	if resp.DocumentType != peopleParams.DocumentType {
		t.Errorf("Expected DocumentType: %s, got: %s", peopleParams.DocumentType, resp.DocumentType)
	}

	if resp.DocumentValue != peopleParams.DocumentValue {
		t.Errorf("Expected DocumentValue: %s, got: %s", peopleParams.DocumentValue, resp.DocumentValue)
	}

	if resp.BirthDay != peopleParams.BirthDay {
		t.Errorf("Expected BirthDay: %s, got: %s", peopleParams.BirthDay, resp.BirthDay)
	}

	if resp.BirthMonth != peopleParams.BirthMonth {
		t.Errorf("Expected BirthMonth: %s, got: %s", peopleParams.BirthMonth, resp.BirthMonth)
	}

	if resp.BirthYear != peopleParams.BirthYear {
		t.Errorf("Expected BirthYear: %s, got: %s", peopleParams.BirthYear, resp.BirthYear)
	}

	if resp.AddressStreet1 != peopleParams.AddressStreet1 {
		t.Errorf("Expected AddressStreet1: %s, got: %s", peopleParams.AddressStreet1, resp.AddressStreet1)
	}

	if resp.AddressStreet2 != peopleParams.AddressStreet2 {
		t.Errorf("Expected AddressStreet2: %s, got: %s", peopleParams.AddressStreet2, resp.AddressStreet2)
	}

	if resp.AddressCity != peopleParams.AddressCity {
		t.Errorf("Expected AddressCity: %s, got: %s", peopleParams.AddressCity, resp.AddressCity)
	}

	if resp.AddressSubdivision != peopleParams.AddressSubdivision {
		t.Errorf("Expected AddressSubdivision: %s, got: %s", peopleParams.AddressSubdivision, resp.AddressSubdivision)
	}

	if resp.AddressPostalCode != peopleParams.AddressPostalCode {
		t.Errorf("Expected AddressPostalCode: %s, got: %s", peopleParams.AddressPostalCode, resp.AddressPostalCode)
	}

	if resp.AddressCountryCode != peopleParams.AddressCountryCode {
		t.Errorf("Expected AddressCountryCode: %s, got: %s", peopleParams.AddressCountryCode, resp.AddressCountryCode)
	}

	if resp.PhoneNumber != peopleParams.PhoneNumber {
		t.Errorf("Expected PhoneNumber: %s, got: %s", peopleParams.PhoneNumber, resp.PhoneNumber)
	}

	if resp.IPAddress != peopleParams.IPAddress {
		t.Errorf("Expected IPAddress: %s, got: %s", peopleParams.IPAddress, resp.IPAddress)
	}

	if resp.Note != peopleParams.Note {
		t.Errorf("Expected Note: %s, got: %s", peopleParams.Note, resp.Note)
	}
}

func TestRetrievePeople(t *testing.T) {
	resp, err := People.Retrieve(personID)

	if err != nil {
		t.Errorf("Expected successful People retrieval, got Error %s", err.Error())
	}

	if resp.NameFirst != peopleParams.NameFirst {
		t.Errorf("Expected NameFirst: %s, got: %s", peopleParams.NameFirst, resp.NameFirst)
	}

	if resp.NameMiddle != peopleParams.NameMiddle {
		t.Errorf("Expected NameMiddle: %s, got: %s", peopleParams.NameMiddle, resp.NameMiddle)
	}

	if resp.NameLast != peopleParams.NameLast {
		t.Errorf("Expected NameLast: %s, got: %s", peopleParams.NameLast, resp.NameLast)
	}

	if resp.DocumentType != peopleParams.DocumentType {
		t.Errorf("Expected DocumentType: %s, got: %s", peopleParams.DocumentType, resp.DocumentType)
	}

	if resp.DocumentValue != peopleParams.DocumentValue {
		t.Errorf("Expected DocumentValue: %s, got: %s", peopleParams.DocumentValue, resp.DocumentValue)
	}

	if resp.BirthDay != peopleParams.BirthDay {
		t.Errorf("Expected BirthDay: %s, got: %s", peopleParams.BirthDay, resp.BirthDay)
	}

	if resp.BirthMonth != peopleParams.BirthMonth {
		t.Errorf("Expected BirthMonth: %s, got: %s", peopleParams.BirthMonth, resp.BirthMonth)
	}

	if resp.BirthYear != peopleParams.BirthYear {
		t.Errorf("Expected BirthYear: %s, got: %s", peopleParams.BirthYear, resp.BirthYear)
	}

	if resp.AddressStreet1 != peopleParams.AddressStreet1 {
		t.Errorf("Expected AddressStreet1: %s, got: %s", peopleParams.AddressStreet1, resp.AddressStreet1)
	}

	if resp.AddressStreet2 != peopleParams.AddressStreet2 {
		t.Errorf("Expected AddressStreet2: %s, got: %s", peopleParams.AddressStreet2, resp.AddressStreet2)
	}

	if resp.AddressCity != peopleParams.AddressCity {
		t.Errorf("Expected AddressCity: %s, got: %s", peopleParams.AddressCity, resp.AddressCity)
	}

	if resp.AddressSubdivision != peopleParams.AddressSubdivision {
		t.Errorf("Expected AddressSubdivision: %s, got: %s", peopleParams.AddressSubdivision, resp.AddressSubdivision)
	}

	if resp.AddressPostalCode != peopleParams.AddressPostalCode {
		t.Errorf("Expected AddressPostalCode: %s, got: %s", peopleParams.AddressPostalCode, resp.AddressPostalCode)
	}

	if resp.AddressCountryCode != peopleParams.AddressCountryCode {
		t.Errorf("Expected AddressCountryCode: %s, got: %s", peopleParams.AddressCountryCode, resp.AddressCountryCode)
	}

	if resp.PhoneNumber != peopleParams.PhoneNumber {
		t.Errorf("Expected PhoneNumber: %s, got: %s", peopleParams.PhoneNumber, resp.PhoneNumber)
	}

	if resp.IPAddress != peopleParams.IPAddress {
		t.Errorf("Expected IPAddress: %s, got: %s", peopleParams.IPAddress, resp.IPAddress)
	}

	if resp.Note != peopleParams.Note {
		t.Errorf("Expected Note: %s, got: %s", peopleParams.Note, resp.Note)
	}
}

func TestListPeople(t *testing.T) {
	_, err := People.List()
	if err != nil {
		t.Errorf("Error: %s", err.Error())
	}
}

func TestListNPeople(t *testing.T) {
	_, err := People.ListN(2, 5)
	if err != nil {
		t.Errorf("Error: %s", err.Error())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"log"
	"sort"
	"strings"

	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
)

type permissions struct {
	token         string
	alwaysAllowed []string
	teamMembers   map[string][]string // repo -> list of members
}

func (p *permissions) isAllowed(repo, login string) bool {
	// Check the list of always allowed users
	for _, user := range p.alwaysAllowed {
		if login == user {
			return true
		}
	}

	// Check the cached list of team members for the given repo
	for _, user := range p.teamMembers[repo] {
		if login == user {
			return true
		}
	}

	// Refresh the team members list as it may be out of date
	log.Println("Refreshing the list of collaborators on", repo, "...")
	users, err := p.collaborators(repo)
	if err != nil {
		return false
	}
	log.Println(" ... got", users)
	p.teamMembers[repo] = users
	for _, user := range p.teamMembers[repo] {
		if login == user {
			return true
		}
	}

	log.Println("Permission denied for", login)

	// Nope, no match
	return false
}

func (p *permissions) collaborators(repo string) ([]string, error) {
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: p.token},
	)
	tc := oauth2.NewClient(oauth2.NoContext, ts)

	client := github.NewClient(tc)

	opt := &github.ListOptions{PerPage: 50}
	var allCollabs []*github.User
	ps := strings.Split(repo, "/")
	owner, repo := ps[0], ps[1]
	for {
		users, resp, err := client.Repositories.ListCollaborators(context.TODO(), owner, repo, opt)
		if err != nil {
			return nil, err
		}
		allCollabs = append(allCollabs, users...)
		if resp.NextPage == 0 {
			break
		}
		opt.Page = resp.NextPage
	}

	userMap := make(map[string]bool)
	for _, user := range allCollabs {
		userMap[*user.Login] = true
	}

	var users []string
	for user := range userMap {
		users = append(users, user)
	}
	sort.Strings(users)
	return users, nil
}
<commit_msg>GitHub API update<commit_after>package main

import (
	"context"
	"log"
	"sort"
	"strings"

	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
)

type permissions struct {
	token         string
	alwaysAllowed []string
	teamMembers   map[string][]string // repo -> list of members
}

func (p *permissions) isAllowed(repo, login string) bool {
	// Check the list of always allowed users
	for _, user := range p.alwaysAllowed {
		if login == user {
			return true
		}
	}

	// Check the cached list of team members for the given repo
	for _, user := range p.teamMembers[repo] {
		if login == user {
			return true
		}
	}

	// Refresh the team members list as it may be out of date
	log.Println("Refreshing the list of collaborators on", repo, "...")
	users, err := p.collaborators(repo)
	if err != nil {
		return false
	}
	log.Println(" ... got", users)
	p.teamMembers[repo] = users
	for _, user := range p.teamMembers[repo] {
		if login == user {
			return true
		}
	}

	log.Println("Permission denied for", login)

	// Nope, no match
	return false
}

func (p *permissions) collaborators(repo string) ([]string, error) {
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: p.token},
	)
	tc := oauth2.NewClient(oauth2.NoContext, ts)

	client := github.NewClient(tc)

	opt := new(github.ListCollaboratorsOptions)
	opt.PerPage = 50
	var allCollabs []*github.User
	ps := strings.Split(repo, "/")
	owner, repo := ps[0], ps[1]
	for {
		users, resp, err := client.Repositories.ListCollaborators(context.TODO(), owner, repo, opt)
		if err != nil {
			return nil, err
		}
		allCollabs = append(allCollabs, users...)
		if resp.NextPage == 0 {
			break
		}
		opt.Page = resp.NextPage
	}

	userMap := make(map[string]bool)
	for _, user := range allCollabs {
		userMap[*user.Login] = true
	}

	var users []string
	for user := range userMap {
		users = append(users, user)
	}
	sort.Strings(users)
	return users, nil
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"testing"
	"time"
)

const requestTimeout = time.Second * 5

var (
	edgeHost    = flag.String("edgeHost", "www.gov.uk", "Hostname of edge")
	originPort  = flag.Int("originPort", 8080, "Origin port to listen on for requests")
	insecureTLS = flag.Bool("insecureTLS", false, "Whether to check server certificates")

	client       *http.Transport
	originServer *CDNServeMux
)

// Setup clients and servers.
func init() {

	flag.Parse()

	tlsOptions := &tls.Config{}
	if *insecureTLS {
		tlsOptions.InsecureSkipVerify = true
	}

	client = &http.Transport{
		ResponseHeaderTimeout: requestTimeout,
		TLSClientConfig:       tlsOptions,
	}
	originServer = StartServer(*originPort)

	log.Println("Confirming that CDN has successfully probed Origin")
	err := confirmOriginIsEnabled(originServer, *edgeHost)
	if err != nil {
		log.Fatal(err)
	}
}

func TestHelpers(t *testing.T) {
	testHelpersCDNServeMuxHandlers(t, originServer)
	testHelpersCDNServeMuxProbes(t, originServer)
}

// Should redirect from HTTP to HTTPS without hitting origin.
func TestProtocolRedirect(t *testing.T) {
	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		t.Error("Request should not have made it to origin")
	})

	sourceUrl := fmt.Sprintf("http://%s/foo/bar", *edgeHost)
	destUrl := fmt.Sprintf("https://%s/foo/bar", *edgeHost)

	req, _ := http.NewRequest("GET", sourceUrl, nil)
	resp, err := client.RoundTrip(req)

	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != 301 {
		t.Errorf("Status code expected 301, got %d", resp.StatusCode)
	}
	if d := resp.Header.Get("Location"); d != destUrl {
		t.Errorf("Location header expected %s, got %s", destUrl, d)
	}
}

// Should send request to origin by default
func TestRequestsGoToOriginByDefault(t *testing.T) {
	uuid := NewUUID()
	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" && r.URL.Path == fmt.Sprintf("/%s", uuid) {
			w.Header().Set("EnsureOriginServed", uuid)
		}
	})

	sourceUrl := fmt.Sprintf("https://%s/%s", *edgeHost, uuid)

	req, _ := http.NewRequest("GET", sourceUrl, nil)
	resp, err := client.RoundTrip(req)

	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != 200 {
		t.Errorf("Status code expected 200, got %d", resp.StatusCode)
	}
	if d := resp.Header.Get("EnsureOriginServed"); d != uuid {
		t.Errorf("EnsureOriginServed header has not come from Origin: expected %q, got %q", uuid, d)
	}

}

// Should cache first response and return it on second request without
// hitting origin again.
func TestFirstResponseCached(t *testing.T) {
	const bodyExpected = "first request"
	const requestsExpectedCount = 1
	requestsReceivedCount := 0

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		if requestsReceivedCount == 0 {
			w.Write([]byte(bodyExpected))
		} else {
			w.Write([]byte("subsequent request"))
		}

		requestsReceivedCount++
	})

	url := fmt.Sprintf("https://%s/%s", *edgeHost, NewUUID())
	req, _ := http.NewRequest("GET", url, nil)

	for i := 0; i < 2; i++ {
		resp, err := client.RoundTrip(req)
		if err != nil {
			t.Fatal(err)
		}

		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			t.Fatal(err)
		}
		if string(body) != bodyExpected {
			t.Errorf("Incorrect response body. Expected %q, got %q", bodyExpected, body)
		}
	}

	if requestsReceivedCount > requestsExpectedCount {
		t.Errorf("originServer got too many requests. Expected %d requests, got %d", requestsExpectedCount, requestsReceivedCount)
	}
}

// Should return 403 for PURGE requests from IPs not in the whitelist.
func TestRestrictPurgeRequests(t *testing.T) {
	t.Error("Not implemented")
}

// Should create an X-Forwarded-For header containing the client's IP.
func TestHeaderCreateXFF(t *testing.T) {
	t.Error("Not implemented")
}

// Should append client's IP to existing X-Forwarded-For header.
func TestHeaderAppendXFF(t *testing.T) {
	t.Error("Not implemented")
}

// Should create a True-Client-IP header containing the client's IP
// address, discarding the value provided in the original request.
func TestHeaderUnspoofableClientIP(t *testing.T) {
	t.Error("Not implemented")
}

// Should not modify Host header from original request.
func TestHeaderHostUnmodified(t *testing.T) {
	t.Error("Not implemented")
}

// Should set a default TTL if the response doesn't set one.
func TestDefaultTTL(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin is down and
// object is beyond TTL but still in cache.
func TestFailoverOriginDownServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin returns a 5xx
// response and object is beyond TTL but still in cache.
func TestFailoverOrigin5xxServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin is down and object is not in
// cache (active or stale).
func TestFailoverOriginDownUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin returns 5xx response and object
// is not in cache (active or stale).
func TestFailoverOrigin5xxUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror are
// down.
func TestFailoverOriginDownFirstMirrorDownUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror return
// 5xx responses.
func TestFailoverOrigin5xxFirstMirror5xxUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should not fallback to mirror if origin returns a 5xx response with a
// No-Fallback header.
func TestFailoverNoFallbackHeader(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve a known static error page if cannot serve a page
// from origin, stale or any mirror.
// NB: ideally this should be a page that we control that has a mechanism
//     to alert us that it has been served.
func TestErrorPageIsServedWhenNoBackendAvailable(t *testing.T) {
	t.Error("Not implemented")
}

// Should not cache a response with a Set-Cookie a header.
func TestNoCacheHeaderSetCookie(t *testing.T) {
	t.Error("Not implemented")
}

// Should not cache a response with a Cache-Control: private header.
func TestNoCacheHeaderCacheControlPrivate(t *testing.T) {
	t.Error("Not implemented")
}

// ---------------------------------------------------------
// Test that useful common cache-related parameters are sent to the
// client by this CDN provider.

// Should set an Age header itself rather than passing the Age header from origin.
func TestAgeHeaderIsSetByProviderNotOrigin(t *testing.T) {
	t.Error("Not implemented")
}

// Should set an X-Cache header containing HIT/MISS from 'origin, itself'
func TestXCacheHeaderContainsHitMissFromBothProviderAndOrigin(t *testing.T) {
	t.Error("Not implemented")
}

// Should set an X-Served-By header giving information on the node and location served from.
func TestXServedByHeaderContainsANodeIdAndLocation(t *testing.T) {
	t.Error("Not implemented")
}

// Should set an X-Cache-Hits header containing hit count for this object,
// from the provider not origin
func TestXCacheHitsContainsProviderHitCountForThisObject(t *testing.T) {
	t.Error("Not implemented")
}
<commit_msg>Implement test for PURGE returning 403<commit_after>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"testing"
	"time"
)

const requestTimeout = time.Second * 5

var (
	edgeHost    = flag.String("edgeHost", "www.gov.uk", "Hostname of edge")
	originPort  = flag.Int("originPort", 8080, "Origin port to listen on for requests")
	insecureTLS = flag.Bool("insecureTLS", false, "Whether to check server certificates")

	client       *http.Transport
	originServer *CDNServeMux
)

// Setup clients and servers.
func init() {

	flag.Parse()

	tlsOptions := &tls.Config{}
	if *insecureTLS {
		tlsOptions.InsecureSkipVerify = true
	}

	client = &http.Transport{
		ResponseHeaderTimeout: requestTimeout,
		TLSClientConfig:       tlsOptions,
	}
	originServer = StartServer(*originPort)

	log.Println("Confirming that CDN has successfully probed Origin")
	err := confirmOriginIsEnabled(originServer, *edgeHost)
	if err != nil {
		log.Fatal(err)
	}
}

func TestHelpers(t *testing.T) {
	testHelpersCDNServeMuxHandlers(t, originServer)
	testHelpersCDNServeMuxProbes(t, originServer)
}

// Should redirect from HTTP to HTTPS without hitting origin.
func TestProtocolRedirect(t *testing.T) {
	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		t.Error("Request should not have made it to origin")
	})

	sourceUrl := fmt.Sprintf("http://%s/foo/bar", *edgeHost)
	destUrl := fmt.Sprintf("https://%s/foo/bar", *edgeHost)

	req, _ := http.NewRequest("GET", sourceUrl, nil)
	resp, err := client.RoundTrip(req)

	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != 301 {
		t.Errorf("Status code expected 301, got %d", resp.StatusCode)
	}
	if d := resp.Header.Get("Location"); d != destUrl {
		t.Errorf("Location header expected %s, got %s", destUrl, d)
	}
}

// Should send request to origin by default
func TestRequestsGoToOriginByDefault(t *testing.T) {
	uuid := NewUUID()
	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" && r.URL.Path == fmt.Sprintf("/%s", uuid) {
			w.Header().Set("EnsureOriginServed", uuid)
		}
	})

	sourceUrl := fmt.Sprintf("https://%s/%s", *edgeHost, uuid)

	req, _ := http.NewRequest("GET", sourceUrl, nil)
	resp, err := client.RoundTrip(req)

	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != 200 {
		t.Errorf("Status code expected 200, got %d", resp.StatusCode)
	}
	if d := resp.Header.Get("EnsureOriginServed"); d != uuid {
		t.Errorf("EnsureOriginServed header has not come from Origin: expected %q, got %q", uuid, d)
	}

}

// Should cache first response and return it on second request without
// hitting origin again.
func TestFirstResponseCached(t *testing.T) {
	const bodyExpected = "first request"
	const requestsExpectedCount = 1
	requestsReceivedCount := 0

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		if requestsReceivedCount == 0 {
			w.Write([]byte(bodyExpected))
		} else {
			w.Write([]byte("subsequent request"))
		}

		requestsReceivedCount++
	})

	url := fmt.Sprintf("https://%s/%s", *edgeHost, NewUUID())
	req, _ := http.NewRequest("GET", url, nil)

	for i := 0; i < 2; i++ {
		resp, err := client.RoundTrip(req)
		if err != nil {
			t.Fatal(err)
		}

		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			t.Fatal(err)
		}
		if string(body) != bodyExpected {
			t.Errorf("Incorrect response body. Expected %q, got %q", bodyExpected, body)
		}
	}

	if requestsReceivedCount > requestsExpectedCount {
		t.Errorf("originServer got too many requests. Expected %d requests, got %d", requestsExpectedCount, requestsReceivedCount)
	}
}

// Should return 403 for PURGE requests from IPs not in the whitelist. We
// assume that this is not running from a whitelisted address.
func TestRestrictPurgeRequests(t *testing.T) {
	const expectedStatusCode = 403

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		t.Error("Request should not have made it to origin")
	})

	url := fmt.Sprintf("https://%s/", *edgeHost)
	req, _ := http.NewRequest("PURGE", url, nil)

	resp, err := client.RoundTrip(req)
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != expectedStatusCode {
		t.Errorf("Incorrect status code. Expected %d, got %d", expectedStatusCode, resp.StatusCode)
	}
}

// Should create an X-Forwarded-For header containing the client's IP.
func TestHeaderCreateXFF(t *testing.T) {
	t.Error("Not implemented")
}

// Should append client's IP to existing X-Forwarded-For header.
func TestHeaderAppendXFF(t *testing.T) {
	t.Error("Not implemented")
}

// Should create a True-Client-IP header containing the client's IP
// address, discarding the value provided in the original request.
func TestHeaderUnspoofableClientIP(t *testing.T) {
	t.Error("Not implemented")
}

// Should not modify Host header from original request.
func TestHeaderHostUnmodified(t *testing.T) {
	t.Error("Not implemented")
}

// Should set a default TTL if the response doesn't set one.
func TestDefaultTTL(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin is down and
// object is beyond TTL but still in cache.
func TestFailoverOriginDownServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin returns a 5xx
// response and object is beyond TTL but still in cache.
func TestFailoverOrigin5xxServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin is down and object is not in
// cache (active or stale).
func TestFailoverOriginDownUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin returns 5xx response and object
// is not in cache (active or stale).
func TestFailoverOrigin5xxUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror are
// down.
func TestFailoverOriginDownFirstMirrorDownUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror return
// 5xx responses.
func TestFailoverOrigin5xxFirstMirror5xxUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should not fallback to mirror if origin returns a 5xx response with a
// No-Fallback header.
func TestFailoverNoFallbackHeader(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve a known static error page if cannot serve a page
// from origin, stale or any mirror.
// NB: ideally this should be a page that we control that has a mechanism
//     to alert us that it has been served.
func TestErrorPageIsServedWhenNoBackendAvailable(t *testing.T) {
	t.Error("Not implemented")
}

// Should not cache a response with a Set-Cookie a header.
func TestNoCacheHeaderSetCookie(t *testing.T) {
	t.Error("Not implemented")
}

// Should not cache a response with a Cache-Control: private header.
func TestNoCacheHeaderCacheControlPrivate(t *testing.T) {
	t.Error("Not implemented")
}

// ---------------------------------------------------------
// Test that useful common cache-related parameters are sent to the
// client by this CDN provider.

// Should set an Age header itself rather than passing the Age header from origin.
func TestAgeHeaderIsSetByProviderNotOrigin(t *testing.T) {
	t.Error("Not implemented")
}

// Should set an X-Cache header containing HIT/MISS from 'origin, itself'
func TestXCacheHeaderContainsHitMissFromBothProviderAndOrigin(t *testing.T) {
	t.Error("Not implemented")
}

// Should set an X-Served-By header giving information on the node and location served from.
func TestXServedByHeaderContainsANodeIdAndLocation(t *testing.T) {
	t.Error("Not implemented")
}

// Should set an X-Cache-Hits header containing hit count for this object,
// from the provider not origin
func TestXCacheHitsContainsProviderHitCountForThisObject(t *testing.T) {
	t.Error("Not implemented")
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"net/http"
	"testing"
)

var edgeHost = flag.String("edgeHost", "www.gov.uk", "Hostname of edge")

// Should redirect from HTTP to HTTPS without hitting origin.
func TestProtocolRedirect(t *testing.T) {
	sourceUrl := fmt.Sprintf("http://%s/foo/bar", *edgeHost)
	destUrl := fmt.Sprintf("https://%s/foo/bar", *edgeHost)

	client := &http.Transport{}
	req, _ := http.NewRequest("GET", sourceUrl, nil)
	resp, err := client.RoundTrip(req)

	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != 301 {
		t.Errorf("Status code expected 301, got %d", resp.StatusCode)
	}
	if d := resp.Header.Get("Location"); d != destUrl {
		t.Errorf("Location header expected %s, got %s", destUrl, d)
	}

	t.Error("Not implemented test to confirm that it doesn't hit origin")
}

// Should send request to origin by default
func TestRequestsGoToOriginByDefault(t *testing.T) {
	t.Error("Not implemented")
}

// Should return 403 for PURGE requests from IPs not in the whitelist.
func TestRestrictPurgeRequests(t *testing.T) {
	t.Error("Not implemented")
}

// Should create an X-Forwarded-For header containing the client's IP.
func TestHeaderCreateXFF(t *testing.T) {
	t.Error("Not implemented")
}

// Should append client's IP to existing X-Forwarded-For header.
func TestHeaderAppendXFF(t *testing.T) {
	t.Error("Not implemented")
}

// Should create a True-Client-IP header containing the client's IP
// address, discarding the value provided in the original request.
func TestHeaderUnspoofableClientIP(t *testing.T) {
	t.Error("Not implemented")
}

// Should not modify Host header from original request.
func TestHeaderHostUnmodified(t *testing.T) {
	t.Error("Not implemented")
}

// Should set a default TTL if the response doesn't set one.
func TestDefaultTTL(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin is down and
// object is beyond TTL but still in cache.
func TestFailoverOriginDownServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin returns a 5xx
// response and object is beyond TTL but still in cache.
func TestFailoverOrigin5xxServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin is down and object is not in
// cache (active or stale).
func TestFailoverOriginDownUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin returns 5xx response and object
// is not in cache (active or stale).
func TestFailoverOrigin5xxUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror are
// down.
func TestFailoverOriginDownFirstMirrorDownUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror return
// 5xx responses.
func TestFailoverOrigin5xxFirstMirror5xxUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should not fallback to mirror if origin returns a 5xx response with a
// No-Fallback header.
func TestFailoverNoFallbackHeader(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve a known static error page if cannot serve a page
// from origin, stale or any mirror.
// NB: ideally this should be a page that we control that has a mechanism
//     to alert us that it has been served.
func TestErrorPageIsServedWhenNoBackendAvailable(t *testing.T) {
	t.Error("Not implemented")
}

// Should not cache a response with a Set-Cookie a header.
func TestNoCacheHeaderSetCookie(t *testing.T) {
	t.Error("Not implemented")
}

// Should not cache a response with a Cache-Control: private header.
func TestNoCacheHeaderCacheControlPrivate(t *testing.T) {
	t.Error("Not implemented")
}
<commit_msg>Empty tests describing useful response headers<commit_after>package main

import (
	"flag"
	"fmt"
	"net/http"
	"testing"
)

var edgeHost = flag.String("edgeHost", "www.gov.uk", "Hostname of edge")

// Should redirect from HTTP to HTTPS without hitting origin.
func TestProtocolRedirect(t *testing.T) {
	sourceUrl := fmt.Sprintf("http://%s/foo/bar", *edgeHost)
	destUrl := fmt.Sprintf("https://%s/foo/bar", *edgeHost)

	client := &http.Transport{}
	req, _ := http.NewRequest("GET", sourceUrl, nil)
	resp, err := client.RoundTrip(req)

	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != 301 {
		t.Errorf("Status code expected 301, got %d", resp.StatusCode)
	}
	if d := resp.Header.Get("Location"); d != destUrl {
		t.Errorf("Location header expected %s, got %s", destUrl, d)
	}

	t.Error("Not implemented test to confirm that it doesn't hit origin")
}

// Should send request to origin by default
func TestRequestsGoToOriginByDefault(t *testing.T) {
	t.Error("Not implemented")
}

// Should return 403 for PURGE requests from IPs not in the whitelist.
func TestRestrictPurgeRequests(t *testing.T) {
	t.Error("Not implemented")
}

// Should create an X-Forwarded-For header containing the client's IP.
func TestHeaderCreateXFF(t *testing.T) {
	t.Error("Not implemented")
}

// Should append client's IP to existing X-Forwarded-For header.
func TestHeaderAppendXFF(t *testing.T) {
	t.Error("Not implemented")
}

// Should create a True-Client-IP header containing the client's IP
// address, discarding the value provided in the original request.
func TestHeaderUnspoofableClientIP(t *testing.T) {
	t.Error("Not implemented")
}

// Should not modify Host header from original request.
func TestHeaderHostUnmodified(t *testing.T) {
	t.Error("Not implemented")
}

// Should set a default TTL if the response doesn't set one.
func TestDefaultTTL(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin is down and
// object is beyond TTL but still in cache.
func TestFailoverOriginDownServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin returns a 5xx
// response and object is beyond TTL but still in cache.
func TestFailoverOrigin5xxServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin is down and object is not in
// cache (active or stale).
func TestFailoverOriginDownUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin returns 5xx response and object
// is not in cache (active or stale).
func TestFailoverOrigin5xxUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror are
// down.
func TestFailoverOriginDownFirstMirrorDownUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror return
// 5xx responses.
func TestFailoverOrigin5xxFirstMirror5xxUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should not fallback to mirror if origin returns a 5xx response with a
// No-Fallback header.
func TestFailoverNoFallbackHeader(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve a known static error page if cannot serve a page
// from origin, stale or any mirror.
// NB: ideally this should be a page that we control that has a mechanism
//     to alert us that it has been served.
func TestErrorPageIsServedWhenNoBackendAvailable(t *testing.T) {
	t.Error("Not implemented")
}

// Should not cache a response with a Set-Cookie a header.
func TestNoCacheHeaderSetCookie(t *testing.T) {
	t.Error("Not implemented")
}

// Should not cache a response with a Cache-Control: private header.
func TestNoCacheHeaderCacheControlPrivate(t *testing.T) {
	t.Error("Not implemented")
}

// ---------------------------------------------------------
// Test that useful common cache-related parameters are sent to the
// client by this CDN provider.

// Should set an Age header itself rather than passing the Age header from origin.
func TestAgeHeaderIsSetByProviderNotOrigin(t *testing.T) {
	t.Error("Not implemented")
}

// Should set an X-Cache header containing HIT/MISS from 'origin, itself'
func TestXCacheHeaderContainsHitMissFromBothProviderAndOrigin(t *testing.T) {
	t.Error("Not implemented")
}

// Should set an X-Served-By header giving information on the node and location served from.
func TestXServedByHeaderContainsANodeIdAndLocation(t *testing.T) {
	t.Error("Not implemented")
}

// Should set an X-Cache-Hits header containing hit count for this object,
// from the provider not origin
func TestXCacheHitsContainsProviderHitCountForThisObject(t *testing.T) {
	t.Error("Not implemented")
}
<|endoftext|>


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

package das // Dictionary by any for strings

import (
	"bytes"
	"fmt"
	"text/template"
)

var keyBuff = bytes.NewBufferString("Test")
var keyTmpl = template.New("Test")
var keyStrg = "Test"
var keyInt8 = 4711
var keyBool = true

var newData = []string{"Foo", "Bar", "Buh", "Foo", "Bar"}
var addData = []string{"Foo", "Bar", "Buh", "Foo", "Bar"}

func ExampleDas_Assign() {
	var das *Das // test also lazyInit

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)
}

func ExampleDas_Append() {
	var das *Das // test also lazyInit

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)
}

func ExampleDas_Das() {
	var das *Das // test also lazyInit
	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	for key, val := range das.Das() {
		fmt.Printf("%s:\t\t\n", key)
		for v := range val {
			fmt.Printf("\t%s\t\n", v)
		}
	}
}

func ExampleDas_Delete() {
	var das *Das // test also lazyInit

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	das = das.Delete(keyBuff)
	das = das.Delete(keyTmpl)
	das = das.Delete(keyStrg)
	das = das.Delete(keyInt8)
	das = das.Delete(keyBool)

	fmt.Println("Len == 0 ?", das.Len())
}

func ExampleDas_Fetch() {
	var das *Das // test also lazyInit

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	key := keyBool
	fmt.Printf("%s:\t\t\n", key)
	for v := range das.Fetch(key) {
		fmt.Printf("\t%s\t\n", v)
	}
}

func ExampleDas_Len() {
	var das *Das // test also lazyInit

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	fmt.Println("Len == 10 ?", das.Len())
}

func ExampleDas_Lookup() {
	var das *Das // test also lazyInit

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	var res []string
	res = das.Lookup(keyBuff)
	res = das.Lookup(keyTmpl)
	res = das.Lookup(keyStrg)
	res = das.Lookup(keyInt8)
	res = das.Lookup(keyBool)

	fmt.Println("Len == 5 ?", len(res))
}

func ExampleDas_KeyS() {
	das := New()
	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	var res []interface{}
	res = das.KeyS()
	fmt.Println("Len == 3 ???", len(res))
	fmt.Println("Is result sorted?", res)

}

func ExampleDas_Init() {
	var das *Das // test also lazyInit

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	fmt.Println("Len == 5 ?", das.Len())
	das = das.Init()
	fmt.Println("Len == 0 ?", das.Len())

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	fmt.Println("Len == 5 ?", das.Len())
}
<commit_msg>was stupid<commit_after>// Copyright 2016 Andreas Pannewitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package das // Dictionary by any for strings

import (
	"bytes"
	"fmt"
	"text/template"
)

var keyBuff = bytes.NewBufferString("Test")
var keyTmpl = template.New("Test")
var keyStrg = "Test"
var keyInt8 = 4711
var keyBool = true

var newData = []string{"Foo", "Bar", "Buh", "Foo", "Bar"}
var addData = []string{"Foo", "Bar", "Buh", "Foo", "Bar"}

func ExampleDas_Assign() {
	var das *Das // test also lazyInit

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)
}

func ExampleDas_Append() {
	var das *Das // test also lazyInit

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)
}

func ExampleDas_Das() {
	var das *Das // test also lazyInit
	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	for key, val := range das.Das() {
		fmt.Printf("%s:\t\t\n", key)
		for v := range val {
			fmt.Printf("\t%s\t\n", v)
		}
	}
}

func ExampleDas_Delete() {
	var das *Das // test also lazyInit

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	das = das.Delete(keyBuff)
	das = das.Delete(keyTmpl)
	das = das.Delete(keyStrg)
	das = das.Delete(keyInt8)
	das = das.Delete(keyBool)

	fmt.Println("Len == 0 ?", das.Len())
}

func ExampleDas_Fetch() {
	var das *Das // test also lazyInit

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	key := keyBool
	fmt.Printf("%s:\t\t\n", key)
	if vS, ok := das.Fetch(key); ok {
		for i := range vS {
			fmt.Printf("\t%s\t\n", vS[i])
		}
	}
}

func ExampleDas_Len() {
	var das *Das // test also lazyInit

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	fmt.Println("Len == 10 ?", das.Len())
}

func ExampleDas_Lookup() {
	var das *Das // test also lazyInit

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	var res []string
	res = das.Lookup(keyBuff)
	res = das.Lookup(keyTmpl)
	res = das.Lookup(keyStrg)
	res = das.Lookup(keyInt8)
	res = das.Lookup(keyBool)

	fmt.Println("Len == 5 ?", len(res))
}

func ExampleDas_KeyS() {
	das := New()
	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	var res []interface{}
	res = das.KeyS()
	fmt.Println("Len == 3 ???", len(res))
	fmt.Println("Is result sorted?", res)

}

func ExampleDas_Init() {
	var das *Das // test also lazyInit

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	fmt.Println("Len == 5 ?", das.Len())
	das = das.Init()
	fmt.Println("Len == 0 ?", das.Len())

	das = das.Assign(keyBuff, newData...)
	das = das.Assign(keyTmpl, newData...)
	das = das.Assign(keyStrg, newData...)
	das = das.Assign(keyInt8, newData...)
	das = das.Assign(keyBool, newData...)

	das = das.Append(keyBuff, addData...)
	das = das.Append(keyTmpl, addData...)
	das = das.Append(keyStrg, addData...)
	das = das.Append(keyInt8, addData...)
	das = das.Append(keyBool, addData...)

	fmt.Println("Len == 5 ?", das.Len())
}
<|endoftext|>