<commit_before>package dynamodb

import (
	"bytes"
	"hash/crc32"
	"io"
	"io/ioutil"
	"math"
	"strconv"
	"time"

	"github.com/awslabs/aws-sdk-go/aws"
)

func init() {
	initService = func(s *aws.Service) {
		s.DefaultMaxRetries = 10
		s.RetryRules = func(r *aws.Request) time.Duration {
			delay := time.Duration(math.Pow(2, float64(r.RetryCount))) * 50
			return delay * time.Millisecond
		}

		s.Handlers.Unmarshal.PushFront(validateCRC32)
	}
}

func drainBody(b io.ReadCloser) (out *bytes.Buffer, err error) {
	var buf bytes.Buffer
	if _, err = buf.ReadFrom(b); err != nil {
		return nil, err
	}
	if err = b.Close(); err != nil {
		return nil, err
	}
	return &buf, nil
}

func validateCRC32(r *aws.Request) {
	if r.Error != nil {
		return // already have an error, no need to verify CRC
	}

	// Checksum validation is off, skip
	if r.Service.Config.DisableComputeChecksums {
		return
	}

	// Try to get CRC from response
	header := r.HTTPResponse.Header.Get("X-Amz-Crc32")
	if header == "" {
		return // No header, skip
	}

	expected, err := strconv.ParseUint(header, 10, 32)
	if err != nil {
		return // Could not determine CRC value, skip
	}

	buf, err := drainBody(r.HTTPResponse.Body)
	if err != nil { // failed to read the response body, skip
		return
	}

	// Reset body for subsequent reads
	r.HTTPResponse.Body = ioutil.NopCloser(bytes.NewReader(buf.Bytes()))

	// Compute the CRC checksum
	crc := crc32.ChecksumIEEE(buf.Bytes())

	if crc != uint32(expected) {
		// CRC does not match, set a retryable error
		r.Retryable = true
		r.Error = &aws.APIError{
			Code:    "CRC32CheckFailed",
			Message: "CRC32 integrity check failed",
		}
	}
}
<commit_msg>Disable gzip compression on DynamoDB requests.<commit_after>package dynamodb

import (
	"bytes"
	"hash/crc32"
	"io"
	"io/ioutil"
	"math"
	"strconv"
	"time"

	"github.com/awslabs/aws-sdk-go/aws"
)

func init() {
	initService = func(s *aws.Service) {
		s.DefaultMaxRetries = 10
		s.RetryRules = func(r *aws.Request) time.Duration {
			delay := time.Duration(math.Pow(2, float64(r.RetryCount))) * 50
			return delay * time.Millisecond
		}

		s.Handlers.Build.PushBack(disableCompression)
		s.Handlers.Unmarshal.PushFront(validateCRC32)
	}
}

func drainBody(b io.ReadCloser) (out *bytes.Buffer, err error) {
	var buf bytes.Buffer
	if _, err = buf.ReadFrom(b); err != nil {
		return nil, err
	}
	if err = b.Close(); err != nil {
		return nil, err
	}
	return &buf, nil
}

func disableCompression(r *aws.Request) {
	r.HTTPRequest.Header.Set("Accept-Encoding", "identity")
}

func validateCRC32(r *aws.Request) {
	if r.Error != nil {
		return // already have an error, no need to verify CRC
	}

	// Checksum validation is off, skip
	if r.Service.Config.DisableComputeChecksums {
		return
	}

	// Try to get CRC from response
	header := r.HTTPResponse.Header.Get("X-Amz-Crc32")
	if header == "" {
		return // No header, skip
	}

	expected, err := strconv.ParseUint(header, 10, 32)
	if err != nil {
		return // Could not determine CRC value, skip
	}

	buf, err := drainBody(r.HTTPResponse.Body)
	if err != nil { // failed to read the response body, skip
		return
	}

	// Reset body for subsequent reads
	r.HTTPResponse.Body = ioutil.NopCloser(bytes.NewReader(buf.Bytes()))

	// Compute the CRC checksum
	crc := crc32.ChecksumIEEE(buf.Bytes())

	if crc != uint32(expected) {
		// CRC does not match, set a retryable error
		r.Retryable = true
		r.Error = &aws.APIError{
			Code:    "CRC32CheckFailed",
			Message: "CRC32 integrity check failed",
		}
	}
}
<|endoftext|>


<commit_before>// types.go

// This file contains the various types used by the API

package atlas

import "net/http"

// Client is the main struct holding state in an API client
type Client struct {
	config Config
	client *http.Client
	opts   map[string]string // Default, optional options
}

// Config is the main object when creating an API Client
type Config struct {
	APIKey       string
	DefaultProbe int
	PoolSize     int
	WantAF       string
	ProxyAuth    string
	Verbose      bool
}

// APIError is for errors returned by the RIPE API.
type APIError struct {
	Error struct {
		Status int    `json:"status"`
		Code   int    `json:"code"`
		Detail string `json:"detail"`
		Title  string `json:"title"`
		Errors []struct {
			Source struct {
				Pointer string
			} `json:"source"`
			Detail string
		} `json:"errors"`
	} `json:"error"`
}

// Key is holding the API key parameters
type Key struct {
	UUID      string `json:"uuid"`
	ValidFrom string `json:"valid_from"`
	ValidTo   string `json:"valid_to"`
	Enabled   bool
	IsActive  bool    `json:"is_active"`
	CreatedAt string  `json:"created_at"`
	Label     string  `json:"label"`
	Grants    []Grant `json:"grants"`
	Type      string  `json:"type"`
}

// Grant is the permission(s) associated with a key
type Grant struct {
	Permission string `json:"permission"`
	Target     struct {
		Type string `json:"type"`
		ID   string `json:"id"`
	} `json:"target"`
}

// Credits is holding credits data
type Credits struct {
	CurrentBalance            int    `json:"current_balance"`
	EstimatedDailyIncome      int    `json:"estimated_daily_income"`
	EstimatedDailyExpenditure int    `json:"estimated_daily_expenditure"`
	EstimatedDailyBalance     int    `json:"estimated_daily_balance"`
	CalculationTime           string `json:"calculation_time"`
	EstimatedRunoutSeconds    int    `json:"estimated_runout_seconds"`
	PastDayMeasurementResults int    `json:"past_day_measurement_results"`
	PastDayCreditsSpent       int    `json:"past_day_credits_spent"`
	IncomeItems               string `json:"income_items"`
	ExpenseItems              string `json:"expense_items"`
	Transactions              string `json:"transactions"`
}

// Probe is holding probe's data
type Probe struct {
	AddressV4      string `json:"address_v4"`
	AddressV6      string `json:"address_v6"`
	AsnV4          int    `json:"asn_v4"`
	AsnV6          int    `json:"asn_v6"`
	CountryCode    string `json:"country_code"`
	Description    string `json:"description"`
	FirstConnected int    `json:"first_connected"`
	Geometry       struct {
		Type        string    `json:"type"`
		Coordinates []float64 `json:"coordinates"`
	} `json:"geometry"`
	ID            int    `json:"id"`
	IsAnchor      bool   `json:"is_anchor"`
	IsPublic      bool   `json:"is_public"`
	LastConnected int    `json:"last_connected"`
	PrefixV4      string `json:"prefix_v4"`
	PrefixV6      string `json:"prefix_v6"`
	Status        struct {
		Since string `json:"since"`
		ID    int    `json:"id"`
		Name  string `json:"name"`
	} `json:"status"`
	StatusSince int `json:"status_since"`
	Tags        []struct {
		Name string `json:"name"`
		Slug string `json:"slug"`
	} `json:"tags"`
	Type string `json:"type"`
}

// Measurement is what we are working with
type Measurement struct {
	Af                    int                    `json:"af"`
	CreationTime          int                    `json:"creation_time"`
	Description           string                 `json:"description"`
	DestinationOptionSize interface{}            `json:"destination_option_size"`
	DontFragment          interface{}            `json:"dont_fragment"`
	DuplicateTimeout      interface{}            `json:"duplicate_timeout"`
	FirstHop              int                    `json:"first_hop"`
	Group                 string                 `json:"group"`
	GroupID               int                    `json:"group_id"`
	HopByHopOptionSize    interface{}            `json:"hop_by_hop_option_size"`
	ID                    int                    `json:"id"`
	InWifiGroup           bool                   `json:"in_wifi_group"`
	Interval              int                    `json:"interval"`
	IsAllScheduled        bool                   `json:"is_all_scheduled"`
	IsOneoff              bool                   `json:"is_oneoff"`
	IsPublic              bool                   `json:"is_public"`
	MaxHops               int                    `json:"max_hops"`
	PacketInterval        interface{}            `json:"packet_interval"`
	Packets               int                    `json:"packets"`
	Paris                 int                    `json:"paris"`
	ParticipantCount      int                    `json:"participant_count"`
	ParticipationRequests []ParticipationRequest `json:"participation_requests"`
	Port                  interface{}            `json:"port"`
	ProbesRequested       int                    `json:"probes_requested"`
	ProbesScheduled       int                    `json:"probes_scheduled"`
	Protocol              string                 `json:"protocol"`
	ResolveOnProbe        bool                   `json:"resolve_on_probe"`
	ResolvedIPs           []string               `json:"resolved_ips"`
	ResponseTimeout       int                    `json:"response_timeout"`
	Result                string                 `json:"result"`
	Size                  int                    `json:"size"`
	Spread                interface{}            `json:"spread"`
	StartTime             int                    `json:"start_time"`
	Status                struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"status"`
	StopTime  int    `json:"stop_time"`
	Target    string `json:"target"`
	TargetASN int    `json:"target_asn"`
	TargetIP  string `json:"target_ip"`
	Type      string `json:"type"`
}

// ParticipationRequest allow you to add or remove probes from a measurement that
// was already created
type ParticipationRequest struct {
	Action        string `json:"action"`
	CreatedAt     int    `json:"created_at,omitempty"`
	ID            int    `json:"id,omitempty"`
	Self          string `json:"self,omitempty"`
	Measurement   string `json:"measurement,omitempty"`
	MeasurementID int    `json:"measurement_id,omitempty"`
	Requested     int    `json:"requested,omitempty"`
	Type          string `json:"type,omitempty"`
	Value         string `json:"value,omitempty"`
	Logs          string `json:"logs,omitempty"`
}

var (
	// ProbeTypes should be obvious
	ProbeTypes = []string{"area", "country", "prefix", "asn", "probes", "msm"}
	// AreaTypes should also be obvious
	AreaTypes = []string{"WW", "West", "North-Central", "South-Central", "North-East", "South-East"}
)

// MeasurementRequest contains the different measurement to create/view
type MeasurementRequest struct {
	// see below for definition
	Definitions []Definition `json:"definitions"`

	// requested set of probes
	Probes ProbeSet `json:"probes"`
	//
	BillTo       int  `json:"bill_to,omitempty"`
	IsOneoff     bool `json:"is_oneoff,omitempty"`
	SkipDNSCheck bool `json:"skip_dns_check,omitempty"`
	Times        int  `json:"times,omitempty"`
	StartTime    int  `json:"start_time,omitempty"`
	StopTime     int  `json:"stop_time,omitempty"`
}

// ProbeSet is a set of probes obviously
type ProbeSet []struct {
	Requested int               `json:"requested"` // number of probes
	Type      string            `json:"type"`      // area, country, prefix, asn, probes, msm
	Value     string            `json:"value"`     // can be numeric or string
	Tags      map[string]string `json:"tags,omitempty"`
}

// Definition is used to create measurements
type Definition struct {
	// Required fields
	Description string `json:"description"`
	Type        string `json:"type"`
	AF          int    `json:"af"`

	// Required for all but "dns"
	Target string `json:"target,omitempty"`

	GroupID        int    `json:"group_id,omitempty"`
	Group          string `json:"group,omitempty"`
	InWifiGroup    bool   `json:"in_wifi_group,omitempty"`
	Spread         int    `json:"spread,omitempty"`
	Packets        int    `json:"packets,omitempty"`
	PacketInterval int    `json:"packet_interval,omitempty"`

	// Common parameters
	ExtraWait      int  `json:"extra_wait,omitempty"`
	IsOneoff       bool `json:"is_oneoff,omitempty"`
	IsPublic       bool `json:"is_public,omitempty"`
	ResolveOnProbe bool `json:"resolve_on_probe,omitempty"`

	// Default depends on type
	Interval int `json:"interval,omitempty"`

	// dns & traceroute parameters
	Protocol string `json:"protocol,omitempty"`

	// dns parameters
	QueryClass       string `json:"query_class,omitempty"`
	QueryType        string `json:"query_type,omitempty"`
	QueryArgument    string `json:"query_argument,omitempty"`
	Retry            int    `json:"retry,omitempty"`
	SetCDBit         bool   `json:"set_cd_bit,omitempty"`
	SetDOBit         bool   `json:"set_do_bit,omitempty"`
	SetNSIDBit       bool   `json:"set_nsid_bit,omitempty"`
	SetRDBit         bool   `json:"set_rd_bit,omitempty"`
	UDPPayloadSize   int    `json:"udp_payload_size,omitempty"`
	UseProbeResolver bool   `json:"use_probe_resolver"`

	// ping parameters
	//   none (see target)

	// traceroute parameters
	DestinationOptionSize int  `json:"destination_option_size,omitempty"`
	DontFragment          bool `json:"dont_fragment,omitempty"`
	DuplicateTimeout      int  `json:"duplicate_timeout,omitempty"`
	FirstHop              int  `json:"first_hop,omitempty"`
	HopByHopOptionSize    int  `json:"hop_by_hop_option_size,omitempty"`
	MaxHops               int  `json:"max_hops,omitempty"`
	Paris                 int  `json:"paris,omitempty"`

	// ntp parameters
	//   none (see target)

	// http parameters
	ExtendedTiming     bool   `json:"extended_timing,omitempty"`
	HeaderBytes        int    `json:"header_bytes,omitempty"`
	Method             string `json:"method,omitempty"`
	MoreExtendedTiming bool   `json:"more_extended_timing,omitempty"`
	Path               string `json:"path,omitempty"`
	QueryOptions       string `json:"query_options,omitempty"`
	UserAgent          string `json:"user_agent,omitempty"`
	Version            string `json:"version,omitempty"`

	// sslcert parameters
	//   none (see target)

	// sslcert & traceroute & http parameters
	Port int `json:"port,omitempty"`

	// ping & traceroute parameters
	Size int `json:"size,omitempty"`

	// wifi parameters
	AnonymousIdentity string `json:"anonymous_identity,omitempty"`
	Cert              string `json:"cert,omitempty"`
	EAP               string `json:"eap,omitempty"`
}
<commit_msg>Add a Logger object to the Client struct.<commit_after>// types.go

// This file contains the various types used by the API

package atlas

import (
	"log"
	"net/http"
)

// Client is the main struct holding state in an API client
type Client struct {
	config Config
	client *http.Client
	log    *log.Logger
	opts   map[string]string // Default, optional options
}

// Config is the main object when creating an API Client
type Config struct {
	APIKey       string
	DefaultProbe int
	PoolSize     int
	WantAF       string
	ProxyAuth    string
	Verbose      bool
}

// APIError is for errors returned by the RIPE API.
type APIError struct {
	Error struct {
		Status int    `json:"status"`
		Code   int    `json:"code"`
		Detail string `json:"detail"`
		Title  string `json:"title"`
		Errors []struct {
			Source struct {
				Pointer string
			} `json:"source"`
			Detail string
		} `json:"errors"`
	} `json:"error"`
}

// Key is holding the API key parameters
type Key struct {
	UUID      string `json:"uuid"`
	ValidFrom string `json:"valid_from"`
	ValidTo   string `json:"valid_to"`
	Enabled   bool
	IsActive  bool    `json:"is_active"`
	CreatedAt string  `json:"created_at"`
	Label     string  `json:"label"`
	Grants    []Grant `json:"grants"`
	Type      string  `json:"type"`
}

// Grant is the permission(s) associated with a key
type Grant struct {
	Permission string `json:"permission"`
	Target     struct {
		Type string `json:"type"`
		ID   string `json:"id"`
	} `json:"target"`
}

// Credits is holding credits data
type Credits struct {
	CurrentBalance            int    `json:"current_balance"`
	EstimatedDailyIncome      int    `json:"estimated_daily_income"`
	EstimatedDailyExpenditure int    `json:"estimated_daily_expenditure"`
	EstimatedDailyBalance     int    `json:"estimated_daily_balance"`
	CalculationTime           string `json:"calculation_time"`
	EstimatedRunoutSeconds    int    `json:"estimated_runout_seconds"`
	PastDayMeasurementResults int    `json:"past_day_measurement_results"`
	PastDayCreditsSpent       int    `json:"past_day_credits_spent"`
	IncomeItems               string `json:"income_items"`
	ExpenseItems              string `json:"expense_items"`
	Transactions              string `json:"transactions"`
}

// Probe is holding probe's data
type Probe struct {
	AddressV4      string `json:"address_v4"`
	AddressV6      string `json:"address_v6"`
	AsnV4          int    `json:"asn_v4"`
	AsnV6          int    `json:"asn_v6"`
	CountryCode    string `json:"country_code"`
	Description    string `json:"description"`
	FirstConnected int    `json:"first_connected"`
	Geometry       struct {
		Type        string    `json:"type"`
		Coordinates []float64 `json:"coordinates"`
	} `json:"geometry"`
	ID            int    `json:"id"`
	IsAnchor      bool   `json:"is_anchor"`
	IsPublic      bool   `json:"is_public"`
	LastConnected int    `json:"last_connected"`
	PrefixV4      string `json:"prefix_v4"`
	PrefixV6      string `json:"prefix_v6"`
	Status        struct {
		Since string `json:"since"`
		ID    int    `json:"id"`
		Name  string `json:"name"`
	} `json:"status"`
	StatusSince int `json:"status_since"`
	Tags        []struct {
		Name string `json:"name"`
		Slug string `json:"slug"`
	} `json:"tags"`
	Type string `json:"type"`
}

// Measurement is what we are working with
type Measurement struct {
	Af                    int                    `json:"af"`
	CreationTime          int                    `json:"creation_time"`
	Description           string                 `json:"description"`
	DestinationOptionSize interface{}            `json:"destination_option_size"`
	DontFragment          interface{}            `json:"dont_fragment"`
	DuplicateTimeout      interface{}            `json:"duplicate_timeout"`
	FirstHop              int                    `json:"first_hop"`
	Group                 string                 `json:"group"`
	GroupID               int                    `json:"group_id"`
	HopByHopOptionSize    interface{}            `json:"hop_by_hop_option_size"`
	ID                    int                    `json:"id"`
	InWifiGroup           bool                   `json:"in_wifi_group"`
	Interval              int                    `json:"interval"`
	IsAllScheduled        bool                   `json:"is_all_scheduled"`
	IsOneoff              bool                   `json:"is_oneoff"`
	IsPublic              bool                   `json:"is_public"`
	MaxHops               int                    `json:"max_hops"`
	PacketInterval        interface{}            `json:"packet_interval"`
	Packets               int                    `json:"packets"`
	Paris                 int                    `json:"paris"`
	ParticipantCount      int                    `json:"participant_count"`
	ParticipationRequests []ParticipationRequest `json:"participation_requests"`
	Port                  interface{}            `json:"port"`
	ProbesRequested       int                    `json:"probes_requested"`
	ProbesScheduled       int                    `json:"probes_scheduled"`
	Protocol              string                 `json:"protocol"`
	ResolveOnProbe        bool                   `json:"resolve_on_probe"`
	ResolvedIPs           []string               `json:"resolved_ips"`
	ResponseTimeout       int                    `json:"response_timeout"`
	Result                string                 `json:"result"`
	Size                  int                    `json:"size"`
	Spread                interface{}            `json:"spread"`
	StartTime             int                    `json:"start_time"`
	Status                struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"status"`
	StopTime  int    `json:"stop_time"`
	Target    string `json:"target"`
	TargetASN int    `json:"target_asn"`
	TargetIP  string `json:"target_ip"`
	Type      string `json:"type"`
}

// ParticipationRequest allow you to add or remove probes from a measurement that
// was already created
type ParticipationRequest struct {
	Action        string `json:"action"`
	CreatedAt     int    `json:"created_at,omitempty"`
	ID            int    `json:"id,omitempty"`
	Self          string `json:"self,omitempty"`
	Measurement   string `json:"measurement,omitempty"`
	MeasurementID int    `json:"measurement_id,omitempty"`
	Requested     int    `json:"requested,omitempty"`
	Type          string `json:"type,omitempty"`
	Value         string `json:"value,omitempty"`
	Logs          string `json:"logs,omitempty"`
}

var (
	// ProbeTypes should be obvious
	ProbeTypes = []string{"area", "country", "prefix", "asn", "probes", "msm"}
	// AreaTypes should also be obvious
	AreaTypes = []string{"WW", "West", "North-Central", "South-Central", "North-East", "South-East"}
)

// MeasurementRequest contains the different measurement to create/view
type MeasurementRequest struct {
	// see below for definition
	Definitions []Definition `json:"definitions"`

	// requested set of probes
	Probes ProbeSet `json:"probes"`
	//
	BillTo       int  `json:"bill_to,omitempty"`
	IsOneoff     bool `json:"is_oneoff,omitempty"`
	SkipDNSCheck bool `json:"skip_dns_check,omitempty"`
	Times        int  `json:"times,omitempty"`
	StartTime    int  `json:"start_time,omitempty"`
	StopTime     int  `json:"stop_time,omitempty"`
}

// ProbeSet is a set of probes obviously
type ProbeSet []struct {
	Requested int               `json:"requested"` // number of probes
	Type      string            `json:"type"`      // area, country, prefix, asn, probes, msm
	Value     string            `json:"value"`     // can be numeric or string
	Tags      map[string]string `json:"tags,omitempty"`
}

// Definition is used to create measurements
type Definition struct {
	// Required fields
	Description string `json:"description"`
	Type        string `json:"type"`
	AF          int    `json:"af"`

	// Required for all but "dns"
	Target string `json:"target,omitempty"`

	GroupID        int    `json:"group_id,omitempty"`
	Group          string `json:"group,omitempty"`
	InWifiGroup    bool   `json:"in_wifi_group,omitempty"`
	Spread         int    `json:"spread,omitempty"`
	Packets        int    `json:"packets,omitempty"`
	PacketInterval int    `json:"packet_interval,omitempty"`

	// Common parameters
	ExtraWait      int  `json:"extra_wait,omitempty"`
	IsOneoff       bool `json:"is_oneoff,omitempty"`
	IsPublic       bool `json:"is_public,omitempty"`
	ResolveOnProbe bool `json:"resolve_on_probe,omitempty"`

	// Default depends on type
	Interval int `json:"interval,omitempty"`

	// dns & traceroute parameters
	Protocol string `json:"protocol,omitempty"`

	// dns parameters
	QueryClass       string `json:"query_class,omitempty"`
	QueryType        string `json:"query_type,omitempty"`
	QueryArgument    string `json:"query_argument,omitempty"`
	Retry            int    `json:"retry,omitempty"`
	SetCDBit         bool   `json:"set_cd_bit,omitempty"`
	SetDOBit         bool   `json:"set_do_bit,omitempty"`
	SetNSIDBit       bool   `json:"set_nsid_bit,omitempty"`
	SetRDBit         bool   `json:"set_rd_bit,omitempty"`
	UDPPayloadSize   int    `json:"udp_payload_size,omitempty"`
	UseProbeResolver bool   `json:"use_probe_resolver"`

	// ping parameters
	//   none (see target)

	// traceroute parameters
	DestinationOptionSize int  `json:"destination_option_size,omitempty"`
	DontFragment          bool `json:"dont_fragment,omitempty"`
	DuplicateTimeout      int  `json:"duplicate_timeout,omitempty"`
	FirstHop              int  `json:"first_hop,omitempty"`
	HopByHopOptionSize    int  `json:"hop_by_hop_option_size,omitempty"`
	MaxHops               int  `json:"max_hops,omitempty"`
	Paris                 int  `json:"paris,omitempty"`

	// ntp parameters
	//   none (see target)

	// http parameters
	ExtendedTiming     bool   `json:"extended_timing,omitempty"`
	HeaderBytes        int    `json:"header_bytes,omitempty"`
	Method             string `json:"method,omitempty"`
	MoreExtendedTiming bool   `json:"more_extended_timing,omitempty"`
	Path               string `json:"path,omitempty"`
	QueryOptions       string `json:"query_options,omitempty"`
	UserAgent          string `json:"user_agent,omitempty"`
	Version            string `json:"version,omitempty"`

	// sslcert parameters
	//   none (see target)

	// sslcert & traceroute & http parameters
	Port int `json:"port,omitempty"`

	// ping & traceroute parameters
	Size int `json:"size,omitempty"`

	// wifi parameters
	AnonymousIdentity string `json:"anonymous_identity,omitempty"`
	Cert              string `json:"cert,omitempty"`
	EAP               string `json:"eap,omitempty"`
}
<|endoftext|>


<commit_before>package wmi

import "time"

type Win32_PerfRawData_Tcpip_NetworkInterface struct {
	BytesReceivedPerSec             uint32
	BytesSentPerSec                 uint32
	BytesTotalPerSec                uint64
	Caption                         string
	CurrentBandwidth                uint32
	Description                     string
	Frequency_Object                uint64
	Frequency_PerfTime              uint64
	Frequency_Sys100NS              uint64
	Name                            string
	OutputQueueLength               uint32
	PacketsOutboundDiscarded        uint32
	PacketsOutboundErrors           uint32
	PacketsPerSec                   uint32
	PacketsReceivedDiscarded        uint32
	PacketsReceivedErrors           uint32
	PacketsReceivedNonUnicastPerSec uint32
	PacketsReceivedPerSec           uint32
	PacketsReceivedUnicastPerSec    uint32
	PacketsReceivedUnknown          uint32
	PacketsSentNonUnicastPerSec     uint32
	PacketsSentPerSec               uint32
	PacketsSentUnicastPerSec        uint32
	Timestamp_Object                uint64
	Timestamp_PerfTime              uint64
	Timestamp_Sys100NS              uint64
}

type Win32_PerfRawData_PerfOS_Processor struct {
	C1TransitionsPerSec   uint64
	C2TransitionsPerSec   uint64
	C3TransitionsPerSec   uint64
	Caption               string
	DPCRate               uint32
	DPCsQueuedPerSec      uint32
	Description           string
	Frequency_Object      uint64
	Frequency_PerfTime    uint64
	Frequency_Sys100NS    uint64
	InterruptsPerSec      uint32
	Name                  string
	PercentC1Time         uint64
	PercentC2Time         uint64
	PercentC3Time         uint64
	PercentDPCTime        uint64
	PercentIdleTime       uint64
	PercentInterruptTime  uint64
	PercentPrivilegedTime uint64
	PercentProcessorTime  uint64
	PercentUserTime       uint64
	Timestamp_Object      uint64
	Timestamp_PerfTime    uint64
	Timestamp_Sys100NS    uint64
}

type Win32_Process struct {
	CSCreationClassName        string
	CSName                     string
	Caption                    string
	CommandLine                string
	CreationClassName          string
	CreationDate               time.Time
	Description                string
	ExecutablePath             string
	ExecutionState             uint16
	Handle                     string
	HandleCount                uint32
	InstallDate                time.Time
	KernelModeTime             uint64
	MaximumWorkingSetSize      uint32
	MinimumWorkingSetSize      uint32
	Name                       string
	OSCreationClassName        string
	OSName                     string
	OtherOperationCount        uint64
	OtherTransferCount         uint64
	PageFaults                 uint32
	PageFileUsage              uint32
	ParentProcessId            uint32
	PeakPageFileUsage          uint32
	PeakVirtualSize            uint64
	PeakWorkingSetSize         uint32
	Priority                   uint32
	PrivatePageCount           uint64
	ProcessId                  uint32
	QuotaNonPagedPoolUsage     uint32
	QuotaPagedPoolUsage        uint32
	QuotaPeakNonPagedPoolUsage uint32
	QuotaPeakPagedPoolUsage    uint32
	ReadOperationCount         uint64
	ReadTransferCount          uint64
	SessionId                  uint32
	Status                     string
	TerminationDate            time.Time
	ThreadCount                uint32
	UserModeTime               uint64
	VirtualSize                uint64
	WindowsVersion             string
	WorkingSetSize             uint64
	WriteOperationCount        uint64
	WriteTransferCount         uint64
}

type Win32_PerfRawData_PerfOS_Memory struct {
	AvailableBytes                  uint64
	AvailableKBytes                 uint64
	AvailableMBytes                 uint64
	CacheBytes                      uint64
	CacheBytesPeak                  uint64
	CacheFaultsPerSec               uint32
	Caption                         string
	CommitLimit                     uint64
	CommittedBytes                  uint64
	DemandZeroFaultsPerSec          uint32
	Description                     string
	FreeSystemPageTableEntries      uint32
	Frequency_Object                uint64
	Frequency_PerfTime              uint64
	Frequency_Sys100NS              uint64
	Name                            string
	PageFaultsPerSec                uint32
	PageReadsPerSec                 uint32
	PagesInputPerSec                uint32
	PagesOutputPerSec               uint32
	PagesPerSec                     uint32
	PageWritesPerSec                uint32
	PercentCommittedBytesInUse      uint32
	PercentCommittedBytesInUse_Base uint32
	PoolNonpagedAllocs              uint32
	PoolNonpagedBytes               uint64
	PoolPagedAllocs                 uint32
	PoolPagedBytes                  uint64
	PoolPagedResidentBytes          uint64
	SystemCacheResidentBytes        uint64
	SystemCodeResidentBytes         uint64
	SystemCodeTotalBytes            uint64
	SystemDriverResidentBytes       uint64
	SystemDriverTotalBytes          uint64
	Timestamp_Object                uint64
	Timestamp_PerfTime              uint64
	Timestamp_Sys100NS              uint64
	TransitionFaultsPerSec          uint32
	WriteCopiesPerSec               uint32
}

type Win32_PerfRawData_PerfDisk_PhysicalDisk struct {
	AvgDiskBytesPerRead          uint64
	AvgDiskBytesPerRead_Base     uint32
	AvgDiskBytesPerTransfer      uint64
	AvgDiskBytesPerTransfer_Base uint64
	AvgDiskBytesPerWrite         uint64
	AvgDiskBytesPerWrite_Base    uint64
	AvgDiskQueueLength           uint64
	AvgDiskReadQueueLength       uint64
	AvgDiskSecPerRead            uint32
	AvgDiskSecPerRead_Base       uint32
	AvgDiskSecPerTransfer        uint32
	AvgDiskSecPerTransfer_Base   uint32
	AvgDiskSecPerWrite           uint32
	AvgDiskSecPerWrite_Base      uint32
	AvgDiskWriteQueueLength      uint64
	Caption                      string
	CurrentDiskQueueLength       uint32
	Description                  string
	DiskBytesPerSec              uint64
	DiskReadBytesPerSec          uint64
	DiskReadsPerSec              uint32
	DiskTransfersPerSec          uint32
	DiskWriteBytesPerSec         uint64
	DiskWritesPerSec             uint32
	Frequency_Object             uint64
	Frequency_PerfTime           uint64
	Frequency_Sys100NS           uint64
	Name                         string
	PercentDiskReadTime          uint64
	PercentDiskReadTime_Base     uint64
	PercentDiskTime              uint64
	PercentDiskTime_Base         uint64
	PercentDiskWriteTime         uint64
	PercentDiskWriteTime_Base    uint64
	PercentIdleTime              uint64
	PercentIdleTime_Base         uint64
	SplitIOPerSec                uint32
	Timestamp_Object             uint64
	Timestamp_PerfTime           uint64
	Timestamp_Sys100NS           uint64
}

type Win32_OperatingSystem struct {
	BootDevice                                string
	BuildNumber                               string
	BuildType                                 string
	Caption                                   string
	CodeSet                                   string
	CountryCode                               string
	CreationClassName                         string
	CSCreationClassName                       string
	CSDVersion                                string
	CSName                                    string
	CurrentTimeZone                           int16
	DataExecutionPrevention_Available         bool
	DataExecutionPrevention_32BitApplications bool
	DataExecutionPrevention_Drivers           bool
	DataExecutionPrevention_SupportPolicy     uint8
	Debug                                     bool
	Description                               string
	Distributed                               bool
	EncryptionLevel                           uint32
	ForegroundApplicationBoost                uint8
	FreePhysicalMemory                        uint64
	FreeSpaceInPagingFiles                    uint64
	FreeVirtualMemory                         uint64
	InstallDate                               time.Time
	LargeSystemCache                          uint32
	LastBootUpTime                            time.Time
	LocalDateTime                             time.Time
	Locale                                    string
	Manufacturer                              string
	MaxNumberOfProcesses                      uint32
	MaxProcessMemorySize                      uint64
	MUILanguages                              []string
	Name                                      string
	NumberOfLicensedUsers                     uint32
	NumberOfProcesses                         uint32
	NumberOfUsers                             uint32
	OperatingSystemSKU                        uint32
	Organization                              string
	OSArchitecture                            string
	OSLanguage                                uint32
	OSProductSuite                            uint32
	OSType                                    uint16
	OtherTypeDescription                      string
	PAEEnabled                                bool
	PlusProductID                             string
	PlusVersionNumber                         string
	PortableOperatingSystem                   bool
	Primary                                   bool
	ProductType                               uint32
	RegisteredUser                            string
	SerialNumber                              string
	ServicePackMajorVersion                   uint16
	ServicePackMinorVersion                   uint16
	SizeStoredInPagingFiles                   uint64
	Status                                    string
	SuiteMask                                 uint32
	SystemDevice                              string
	SystemDirectory                           string
	SystemDrive                               string
	TotalSwapSpaceSize                        uint64
	TotalVirtualMemorySize                    uint64
	TotalVisibleMemorySize                    uint64
	Version                                   string
	WindowsDirectory                          string
}
<commit_msg>Add LogicalDisk type to get space utilization on partitions<commit_after>package wmi

import "time"

type Win32_PerfRawData_Tcpip_NetworkInterface struct {
	BytesReceivedPerSec             uint32
	BytesSentPerSec                 uint32
	BytesTotalPerSec                uint64
	Caption                         string
	CurrentBandwidth                uint32
	Description                     string
	Frequency_Object                uint64
	Frequency_PerfTime              uint64
	Frequency_Sys100NS              uint64
	Name                            string
	OutputQueueLength               uint32
	PacketsOutboundDiscarded        uint32
	PacketsOutboundErrors           uint32
	PacketsPerSec                   uint32
	PacketsReceivedDiscarded        uint32
	PacketsReceivedErrors           uint32
	PacketsReceivedNonUnicastPerSec uint32
	PacketsReceivedPerSec           uint32
	PacketsReceivedUnicastPerSec    uint32
	PacketsReceivedUnknown          uint32
	PacketsSentNonUnicastPerSec     uint32
	PacketsSentPerSec               uint32
	PacketsSentUnicastPerSec        uint32
	Timestamp_Object                uint64
	Timestamp_PerfTime              uint64
	Timestamp_Sys100NS              uint64
}

type Win32_PerfRawData_PerfOS_Processor struct {
	C1TransitionsPerSec   uint64
	C2TransitionsPerSec   uint64
	C3TransitionsPerSec   uint64
	Caption               string
	DPCRate               uint32
	DPCsQueuedPerSec      uint32
	Description           string
	Frequency_Object      uint64
	Frequency_PerfTime    uint64
	Frequency_Sys100NS    uint64
	InterruptsPerSec      uint32
	Name                  string
	PercentC1Time         uint64
	PercentC2Time         uint64
	PercentC3Time         uint64
	PercentDPCTime        uint64
	PercentIdleTime       uint64
	PercentInterruptTime  uint64
	PercentPrivilegedTime uint64
	PercentProcessorTime  uint64
	PercentUserTime       uint64
	Timestamp_Object      uint64
	Timestamp_PerfTime    uint64
	Timestamp_Sys100NS    uint64
}

type Win32_Process struct {
	CSCreationClassName        string
	CSName                     string
	Caption                    string
	CommandLine                string
	CreationClassName          string
	CreationDate               time.Time
	Description                string
	ExecutablePath             string
	ExecutionState             uint16
	Handle                     string
	HandleCount                uint32
	InstallDate                time.Time
	KernelModeTime             uint64
	MaximumWorkingSetSize      uint32
	MinimumWorkingSetSize      uint32
	Name                       string
	OSCreationClassName        string
	OSName                     string
	OtherOperationCount        uint64
	OtherTransferCount         uint64
	PageFaults                 uint32
	PageFileUsage              uint32
	ParentProcessId            uint32
	PeakPageFileUsage          uint32
	PeakVirtualSize            uint64
	PeakWorkingSetSize         uint32
	Priority                   uint32
	PrivatePageCount           uint64
	ProcessId                  uint32
	QuotaNonPagedPoolUsage     uint32
	QuotaPagedPoolUsage        uint32
	QuotaPeakNonPagedPoolUsage uint32
	QuotaPeakPagedPoolUsage    uint32
	ReadOperationCount         uint64
	ReadTransferCount          uint64
	SessionId                  uint32
	Status                     string
	TerminationDate            time.Time
	ThreadCount                uint32
	UserModeTime               uint64
	VirtualSize                uint64
	WindowsVersion             string
	WorkingSetSize             uint64
	WriteOperationCount        uint64
	WriteTransferCount         uint64
}

type Win32_PerfRawData_PerfOS_Memory struct {
	AvailableBytes                  uint64
	AvailableKBytes                 uint64
	AvailableMBytes                 uint64
	CacheBytes                      uint64
	CacheBytesPeak                  uint64
	CacheFaultsPerSec               uint32
	Caption                         string
	CommitLimit                     uint64
	CommittedBytes                  uint64
	DemandZeroFaultsPerSec          uint32
	Description                     string
	FreeSystemPageTableEntries      uint32
	Frequency_Object                uint64
	Frequency_PerfTime              uint64
	Frequency_Sys100NS              uint64
	Name                            string
	PageFaultsPerSec                uint32
	PageReadsPerSec                 uint32
	PagesInputPerSec                uint32
	PagesOutputPerSec               uint32
	PagesPerSec                     uint32
	PageWritesPerSec                uint32
	PercentCommittedBytesInUse      uint32
	PercentCommittedBytesInUse_Base uint32
	PoolNonpagedAllocs              uint32
	PoolNonpagedBytes               uint64
	PoolPagedAllocs                 uint32
	PoolPagedBytes                  uint64
	PoolPagedResidentBytes          uint64
	SystemCacheResidentBytes        uint64
	SystemCodeResidentBytes         uint64
	SystemCodeTotalBytes            uint64
	SystemDriverResidentBytes       uint64
	SystemDriverTotalBytes          uint64
	Timestamp_Object                uint64
	Timestamp_PerfTime              uint64
	Timestamp_Sys100NS              uint64
	TransitionFaultsPerSec          uint32
	WriteCopiesPerSec               uint32
}

type Win32_PerfRawData_PerfDisk_PhysicalDisk struct {
	AvgDiskBytesPerRead          uint64
	AvgDiskBytesPerRead_Base     uint32
	AvgDiskBytesPerTransfer      uint64
	AvgDiskBytesPerTransfer_Base uint64
	AvgDiskBytesPerWrite         uint64
	AvgDiskBytesPerWrite_Base    uint64
	AvgDiskQueueLength           uint64
	AvgDiskReadQueueLength       uint64
	AvgDiskSecPerRead            uint32
	AvgDiskSecPerRead_Base       uint32
	AvgDiskSecPerTransfer        uint32
	AvgDiskSecPerTransfer_Base   uint32
	AvgDiskSecPerWrite           uint32
	AvgDiskSecPerWrite_Base      uint32
	AvgDiskWriteQueueLength      uint64
	Caption                      string
	CurrentDiskQueueLength       uint32
	Description                  string
	DiskBytesPerSec              uint64
	DiskReadBytesPerSec          uint64
	DiskReadsPerSec              uint32
	DiskTransfersPerSec          uint32
	DiskWriteBytesPerSec         uint64
	DiskWritesPerSec             uint32
	Frequency_Object             uint64
	Frequency_PerfTime           uint64
	Frequency_Sys100NS           uint64
	Name                         string
	PercentDiskReadTime          uint64
	PercentDiskReadTime_Base     uint64
	PercentDiskTime              uint64
	PercentDiskTime_Base         uint64
	PercentDiskWriteTime         uint64
	PercentDiskWriteTime_Base    uint64
	PercentIdleTime              uint64
	PercentIdleTime_Base         uint64
	SplitIOPerSec                uint32
	Timestamp_Object             uint64
	Timestamp_PerfTime           uint64
	Timestamp_Sys100NS           uint64
}

type Win32_OperatingSystem struct {
	BootDevice                                string
	BuildNumber                               string
	BuildType                                 string
	Caption                                   string
	CodeSet                                   string
	CountryCode                               string
	CreationClassName                         string
	CSCreationClassName                       string
	CSDVersion                                string
	CSName                                    string
	CurrentTimeZone                           int16
	DataExecutionPrevention_Available         bool
	DataExecutionPrevention_32BitApplications bool
	DataExecutionPrevention_Drivers           bool
	DataExecutionPrevention_SupportPolicy     uint8
	Debug                                     bool
	Description                               string
	Distributed                               bool
	EncryptionLevel                           uint32
	ForegroundApplicationBoost                uint8
	FreePhysicalMemory                        uint64
	FreeSpaceInPagingFiles                    uint64
	FreeVirtualMemory                         uint64
	InstallDate                               time.Time
	LargeSystemCache                          uint32
	LastBootUpTime                            time.Time
	LocalDateTime                             time.Time
	Locale                                    string
	Manufacturer                              string
	MaxNumberOfProcesses                      uint32
	MaxProcessMemorySize                      uint64
	MUILanguages                              []string
	Name                                      string
	NumberOfLicensedUsers                     uint32
	NumberOfProcesses                         uint32
	NumberOfUsers                             uint32
	OperatingSystemSKU                        uint32
	Organization                              string
	OSArchitecture                            string
	OSLanguage                                uint32
	OSProductSuite                            uint32
	OSType                                    uint16
	OtherTypeDescription                      string
	PAEEnabled                                bool
	PlusProductID                             string
	PlusVersionNumber                         string
	PortableOperatingSystem                   bool
	Primary                                   bool
	ProductType                               uint32
	RegisteredUser                            string
	SerialNumber                              string
	ServicePackMajorVersion                   uint16
	ServicePackMinorVersion                   uint16
	SizeStoredInPagingFiles                   uint64
	Status                                    string
	SuiteMask                                 uint32
	SystemDevice                              string
	SystemDirectory                           string
	SystemDrive                               string
	TotalSwapSpaceSize                        uint64
	TotalVirtualMemorySize                    uint64
	TotalVisibleMemorySize                    uint64
	Version                                   string
	WindowsDirectory                          string
}

type Win32_PerfRawData_PerfDisk_LogicalDisk struct {
	AvgDiskBytesPerRead          uint64
	AvgDiskBytesPerRead_Base     uint32
	AvgDiskBytesPerTransfer      uint64
	AvgDiskBytesPerTransfer_Base uint32
	AvgDiskBytesPerWrite         uint64
	AvgDiskBytesPerWrite_Base    uint32
	AvgDiskQueueLength           uint64
	AvgDiskReadQueueLength       uint64
	AvgDiskSecPerRead            uint32
	AvgDiskSecPerRead_Base       uint32
	AvgDiskSecPerTransfer        uint32
	AvgDiskSecPerTransfer_Base   uint32
	AvgDiskSecPerWrite           uint32
	AvgDiskSecPerWrite_Base      uint32
	AvgDiskWriteQueueLength      uint64
	Caption                      string
	CurrentDiskQueueLength       uint32
	Description                  string
	DiskBytesPerSec              uint64
	DiskReadBytesPerSec          uint64
	DiskReadsPerSec              uint32
	DiskTransfersPerSec          uint32
	DiskWriteBytesPerSec         uint64
	DiskWritesPerSec             uint32
	FreeMegabytes                uint32
	Frequency_Object             uint64
	Frequency_PerfTime           uint64
	Frequency_Sys100NS           uint64
	Name                         string
	PercentDiskReadTime          uint64
	PercentDiskReadTime_Base     uint64
	PercentDiskTime              uint64
	PercentDiskTime_Base         uint64
	PercentDiskWriteTime         uint64
	PercentDiskWriteTime_Base    uint64
	PercentFreeSpace             uint32
	PercentFreeSpace_Base        uint32
	PercentIdleTime              uint64
	PercentIdleTime_Base         uint64
	SplitIOPerSec                uint32
	Timestamp_Object             uint64
	Timestamp_PerfTime           uint64
	Timestamp_Sys100NS           uint64
}
<|endoftext|>


<commit_before>package recipes

import (
	"github.com/hawx/img/crop"
	"github.com/hawx/img/utils"
	"image"
	"image/color"
	"image/draw"
)

const (
	TOP_BORDER = 0.1
	SIDE_BORDER = 0.1
	BOTTOM_BORDER = 0.3
)

func Edwn(in image.Image) image.Image {
	// Crop:

	in = crop.Square(in, -1, utils.Centre)
	rect := in.Bounds()

	// Calculate border widths:

	topBorder    := int(float64(rect.Dy()) * TOP_BORDER)
	sideBorder   := int(float64(rect.Dx()) * SIDE_BORDER)
	bottomBorder := int(float64(rect.Dy()) * BOTTOM_BORDER)

	fullWidth  := rect.Dx() + 2 * sideBorder + 2
	fullHeight := rect.Dy() + topBorder + bottomBorder + 2

	// Put white border round image
	// Put 1px black border round

	imageSize := image.Rect(sideBorder+1, topBorder+1, sideBorder+1 + rect.Dx(), topBorder+1 + rect.Dy())
	whiteSize := image.Rect(1, 1, fullWidth - 1, fullHeight - 1)
	blackSize := image.Rect(0, 0, fullWidth, fullHeight)

	white     := image.NewUniform(color.White)
	black     := image.NewUniform(color.Black)

	final := image.NewRGBA(blackSize)

	draw.Draw(final, blackSize, black, image.Pt(0, 0), draw.Src)
	draw.Draw(final, whiteSize, white, image.Pt(0, 0), draw.Src)
  draw.Draw(final, imageSize, in, image.Pt(0, 0), draw.Src)

	return final
}
<commit_msg>Fix edwn drawing with whitespace on left<commit_after>package recipes

import (
	"github.com/hawx/img/crop"
	"github.com/hawx/img/utils"
	"image"
	"image/color"
	"image/draw"
)

const (
	TOP_BORDER    = 0.1
	SIDE_BORDER   = 0.1
	BOTTOM_BORDER = 0.3
)

func Edwn(in image.Image) image.Image {
	// Crop:
	in = crop.Square(in, -1, utils.Right)
	rect := in.Bounds()

	// Calculate border widths:
	topBorder := int(float64(rect.Dy()) * TOP_BORDER)
	sideBorder := int(float64(rect.Dx()) * SIDE_BORDER)
	bottomBorder := int(float64(rect.Dy()) * BOTTOM_BORDER)

	fullWidth := rect.Dx() + 2*sideBorder + 2
	fullHeight := rect.Dy() + topBorder + bottomBorder + 2

	// Bounds now start off (0, 0) since the image has been cropped, so need to
	// correct for this when calculating the image size and remove the margin
	imageSize := image.Rect(sideBorder+1-rect.Min.X, topBorder+1-rect.Min.Y, sideBorder+1+rect.Dx(), topBorder+1+rect.Dy())

	// Put white border round image
	whiteSize := image.Rect(1, 1, fullWidth-1, fullHeight-1)

	// Put 1px black border round
	blackSize := image.Rect(0, 0, fullWidth, fullHeight)

	white := image.NewUniform(color.White)
	black := image.NewUniform(color.Black)

	final := image.NewRGBA(blackSize)
	draw.Draw(final, blackSize, black, image.Pt(0, 0), draw.Src)
	draw.Draw(final, whiteSize, white, image.Pt(0, 0), draw.Src)
	draw.Draw(final, imageSize, in, image.Pt(0, 0), draw.Src)

	return final
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"sync"

	"gopnik"
)

const (
	PENDING    = 0
	INPROGRESS = 1
	DONE       = 2
)

type plan struct {
	bboxes []gopnik.TileCoord
	status []uint8
	cursor int
	mu     sync.Mutex
	cond   *sync.Cond
	condMu sync.Mutex
}

func newPlan(bboxes []gopnik.TileCoord) *plan {
	self := &plan{
		bboxes: bboxes,
		status: make([]uint8, len(bboxes)),
	}
	self.cond = sync.NewCond(&self.condMu)
	return self
}

func (self *plan) TotalTasks() int {
	return len(self.bboxes)
}

func (self *plan) DoneTasks() int {
	self.mu.Lock()
	defer self.mu.Unlock()

	return self.countTasks(DONE)
}

func (self *plan) ProgressTasksCoord() (coordInProg []gopnik.TileCoord) {
	self.mu.Lock()
	defer self.mu.Unlock()

	for i, v := range self.status {
		if v == INPROGRESS {
			coordInProg = append(coordInProg, self.bboxes[i])
		}
	}
	return
}

func (self *plan) countTasks(status uint8) int {
	result := 0
	for _, s := range self.status {
		if s == status {
			result++
		}
	}
	return result
}

func (self *plan) GetTask() *gopnik.TileCoord {
	self.mu.Lock()
	defer self.mu.Unlock()

	oldCursor := self.cursor
	allDone := true
	for {
		self.cursor++
		if self.cursor == len(self.bboxes) {
			self.cursor = 0
		}

		if self.status[self.cursor] == PENDING {
			bb := self.bboxes[self.cursor]
			self.status[self.cursor] = INPROGRESS
			return &bb
		}
		if self.status[self.cursor] != DONE {
			allDone = false
		}

		// On start point again
		if self.cursor == oldCursor {
			// Is plan complete?
			if allDone {
				return nil
			}
			// Waiting...
			log.Debug("Waiting for %v tasks...", self.countTasks(INPROGRESS))
			self.condMu.Lock()
			self.mu.Unlock()
			self.cond.Wait()
			self.condMu.Unlock()
			self.mu.Lock()
			oldCursor = self.cursor
			allDone = true
		}
	}
}

func (self *plan) setStatus(coord gopnik.TileCoord, status uint8) error {
	self.mu.Lock()
	defer self.mu.Unlock()

	for i, c := range self.bboxes {
		if coord.Equals(&c) {
			self.status[i] = status
			self.cond.Broadcast()
			return nil
		}
	}
	return fmt.Errorf("Can't find task %v", coord)
}

func (self *plan) FailTask(coord gopnik.TileCoord) error {
	return self.setStatus(coord, PENDING)
}

func (self *plan) DoneTask(coord gopnik.TileCoord) error {
	return self.setStatus(coord, DONE)
}
<commit_msg>use cond.Signal for plan wake up<commit_after>package main

import (
	"fmt"
	"sync"

	"gopnik"
)

const (
	PENDING    = 0
	INPROGRESS = 1
	DONE       = 2
)

type plan struct {
	bboxes []gopnik.TileCoord
	status []uint8
	cursor int
	mu     sync.Mutex
	cond   *sync.Cond
	condMu sync.Mutex
}

func newPlan(bboxes []gopnik.TileCoord) *plan {
	self := &plan{
		bboxes: bboxes,
		status: make([]uint8, len(bboxes)),
	}
	self.cond = sync.NewCond(&self.condMu)
	return self
}

func (self *plan) TotalTasks() int {
	return len(self.bboxes)
}

func (self *plan) DoneTasks() int {
	self.mu.Lock()
	defer self.mu.Unlock()

	return self.countTasks(DONE)
}

func (self *plan) ProgressTasksCoord() (coordInProg []gopnik.TileCoord) {
	self.mu.Lock()
	defer self.mu.Unlock()

	for i, v := range self.status {
		if v == INPROGRESS {
			coordInProg = append(coordInProg, self.bboxes[i])
		}
	}
	return
}

func (self *plan) countTasks(status uint8) int {
	result := 0
	for _, s := range self.status {
		if s == status {
			result++
		}
	}
	return result
}

func (self *plan) GetTask() *gopnik.TileCoord {
	self.mu.Lock()
	defer self.mu.Unlock()

	oldCursor := self.cursor
	allDone := true
	for {
		self.cursor++
		if self.cursor == len(self.bboxes) {
			self.cursor = 0
		}

		if self.status[self.cursor] == PENDING {
			bb := self.bboxes[self.cursor]
			self.status[self.cursor] = INPROGRESS
			return &bb
		}
		if self.status[self.cursor] != DONE {
			allDone = false
		}

		// On start point again
		if self.cursor == oldCursor {
			// Is plan complete?
			if allDone {
				return nil
			}
			// Waiting...
			log.Debug("Waiting for %v tasks...", self.countTasks(INPROGRESS))
			self.condMu.Lock()
			self.mu.Unlock()
			self.cond.Wait()
			self.condMu.Unlock()
			self.mu.Lock()
			oldCursor = self.cursor
			allDone = true
		}
	}
}

func (self *plan) setStatus(coord gopnik.TileCoord, status uint8) error {
	self.mu.Lock()
	defer self.mu.Unlock()

	for i, c := range self.bboxes {
		if coord.Equals(&c) {
			self.status[i] = status
			self.cond.Signal()
			return nil
		}
	}
	return fmt.Errorf("Can't find task %v", coord)
}

func (self *plan) FailTask(coord gopnik.TileCoord) error {
	return self.setStatus(coord, PENDING)
}

func (self *plan) DoneTask(coord gopnik.TileCoord) error {
	return self.setStatus(coord, DONE)
}
<|endoftext|>


<commit_before>package context

import (
	"sync"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestStack(t *testing.T) {
	c := Enter()
	c.Put("a", 1)
	Enter().
		Put("b", 2).
		Put("c", 3)
	c.Enter().
		Put("c", 4).
		Put("d", 5)

	var assertMutex sync.Mutex
	assertContents := func(expected Map) {
		m := AsMap()
		assertMutex.Lock()
		assert.Equal(t, expected, m)
		assertMutex.Unlock()
	}

	var wg sync.WaitGroup
	wg.Add(1)
	Go(func() {
		Enter().Put("e", 6)
		assertContents(Map{
			"a": 1,
			"b": 2,
			"c": 4,
			"d": 5,
			"e": 6,
		})
		wg.Done()
	})
	wg.Wait()

	assertContents(Map{
		"a": 1,
		"b": 2,
		"c": 4,
		"d": 5,
	})

	c.Exit()
	assertContents(Map{
		"a": 1,
		"b": 2,
		"c": 3,
	})

	c.Exit()
	assertContents(Map{
		"a": 1,
	})

	c.Exit()
	assertContents(Map{})

	// Exit again, just for good measure
	c.Exit()
	assertContents(Map{})

	// Spawn a goroutine with no existing contexts
	wg.Add(1)
	Go(func() {
		Enter().Put("f", 7)
		assertContents(Map{
			"f": 7,
		})
		wg.Done()
	})
	wg.Wait()
}

func BenchmarkPut(b *testing.B) {
	c := Enter()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		c.Put("key", "value")
	}
}

func BenchmarkAsMapCheap(b *testing.B) {
	c := Enter().Put("a", 1).Put("b", 2)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		c.AsMap()
	}
}

func BenchmarkAsMapExpensive(b *testing.B) {
	Enter().Put("a", 1).Put("b", 2)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		AsMap()
	}
}
<commit_msg>Added assertion about contexts getting cleaned up<commit_after>package context

import (
	"sync"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestStack(t *testing.T) {
	c := Enter()
	c.Put("a", 1)
	Enter().
		Put("b", 2).
		Put("c", 3)
	c.Enter().
		Put("c", 4).
		Put("d", 5)

	var assertMutex sync.Mutex
	assertContents := func(expected Map) {
		m := AsMap()
		assertMutex.Lock()
		assert.Equal(t, expected, m)
		assertMutex.Unlock()
	}

	var wg sync.WaitGroup
	wg.Add(1)
	Go(func() {
		defer Enter().Put("e", 6).Exit()
		assertContents(Map{
			"a": 1,
			"b": 2,
			"c": 4,
			"d": 5,
			"e": 6,
		})
		wg.Done()
	})
	wg.Wait()

	assertContents(Map{
		"a": 1,
		"b": 2,
		"c": 4,
		"d": 5,
	})

	c.Exit()
	assertContents(Map{
		"a": 1,
		"b": 2,
		"c": 3,
	})

	c.Exit()
	assertContents(Map{
		"a": 1,
	})

	c.Exit()
	assertContents(Map{})

	// Exit again, just for good measure
	c.Exit()
	assertContents(Map{})

	// Spawn a goroutine with no existing contexts
	wg.Add(1)
	Go(func() {
		defer Enter().Put("f", 7).Exit()
		assertContents(Map{
			"f": 7,
		})
		wg.Done()
	})
	wg.Wait()

	allmx.RLock()
	assert.Empty(t, contexts, "No contexts should be left")
	allmx.RUnlock()
}

func BenchmarkPut(b *testing.B) {
	c := Enter()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		c.Put("key", "value")
	}
}

func BenchmarkAsMapCheap(b *testing.B) {
	c := Enter().Put("a", 1).Put("b", 2)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		c.AsMap()
	}
}

func BenchmarkAsMapExpensive(b *testing.B) {
	Enter().Put("a", 1).Put("b", 2)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		AsMap()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/PandoCloud/pando-cloud/pkg/models"
	"github.com/PandoCloud/pando-cloud/pkg/mysql"
	"github.com/PandoCloud/pando-cloud/pkg/rpcs"
	"testing"
)

func testVendor(t *testing.T, r *Registry) {
	vendor := &models.Vendor{
		VendorName:        "testvendor",
		VendorDescription: "this is a test vendor",
	}
	err := r.SaveVendor(vendor, vendor)
	if err != nil {
		t.Fatal(err)
	}
	t.Log(vendor)
}

var (
	testProductKey = ""
)

func testProduct(t *testing.T, r *Registry) {
	product := &models.Product{
		VendorID:           1,
		ProductName:        "test product.",
		ProductDescription: "this is a test product",
		ProductConfig:      "{}",
	}
	err := r.SaveProduct(product, product)
	if err != nil {
		t.Fatal(err)
	}
	t.Log(product)

	product.ProductName = "test for update."
	err = r.SaveProduct(product, product)
	if err != nil {
		t.Fatal(err)
	}
	t.Log(product)

	reply := &models.Product{}
	err = r.ValidateProduct(product.ProductKey, reply)
	if err != nil {
		t.Error(err)
	}
	t.Log(reply)

	testProductKey = product.ProductKey

	err = r.ValidateProduct("this is a wrong key , you know", reply)
	if err == nil {
		t.Error("wrong key should fail product key validation.")
	}
}

func testDevice(t *testing.T, r *Registry) {
	args := &rpcs.DeviceRegisterArgs{
		ProductKey:    testProductKey,
		DeviceCode:    "ffffaaeeccbb",
		DeviceVersion: "android-gprs-v1",
	}
	device := &models.Device{}
	err := r.RegisterDevice(args, device)
	if err != nil {
		t.Fatal(err)
	}
	t.Log(device)

	device.DeviceDescription = "test change device info."

	args2 := &rpcs.DeviceUpdateArgs{
		DeviceIdentifier:  device.DeviceIdentifier,
		DeviceName:        "testupdatename",
		DeviceDescription: "test change device info.",
	}
	err = r.UpdateDeviceInfo(args2, device)
	if err != nil {
		t.Error(err)
	}
	t.Log(device)
}

func TestRegistry(t *testing.T) {
	err := mysql.MigrateDatabase(defaultDBHost, defaultDBPort, defaultDBName, defaultDBUser, "")
	if err != nil {
		t.Fatal(err)
	}

	*confAESKey = "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"

	*confDBPass = ""
	r, err := NewRegistry()
	if err != nil {
		t.Fatal(err)
	}

	testVendor(t, r)
	testProduct(t, r)
	testDevice(t, r)
}
<commit_msg>fix registry unit test fail.<commit_after>package main

import (
	"github.com/PandoCloud/pando-cloud/pkg/models"
	"github.com/PandoCloud/pando-cloud/pkg/mysql"
	"github.com/PandoCloud/pando-cloud/pkg/rpcs"
	"testing"
)

func testVendor(t *testing.T, r *Registry) {
	vendor := &models.Vendor{
		VendorName:        "testvendor",
		VendorDescription: "this is a test vendor",
	}
	err := r.SaveVendor(vendor, vendor)
	if err != nil {
		t.Fatal(err)
	}
	t.Log(vendor)
}

var (
	testProductKey = ""
)

func testProduct(t *testing.T, r *Registry) {
	product := &models.Product{
		VendorID:           1,
		ProductName:        "test product.",
		ProductDescription: "this is a test product",
		ProductConfig:      "{}",
	}
	err := r.SaveProduct(product, product)
	if err != nil {
		t.Fatal(err)
	}
	t.Log(product)

	product.ProductName = "test for update."
	err = r.SaveProduct(product, product)
	if err != nil {
		t.Fatal(err)
	}
	t.Log(product)

	reply := &models.Product{}
	err = r.ValidateProduct(product.ProductKey, reply)
	if err != nil {
		t.Error(err)
	}
	t.Log(reply)

	testProductKey = product.ProductKey

	err = r.ValidateProduct("this is a wrong key , you know", reply)
	if err == nil {
		t.Error("wrong key should fail product key validation.")
	}
}

func testDevice(t *testing.T, r *Registry) {
	args := &rpcs.ArgsDeviceRegister{
		ProductKey:    testProductKey,
		DeviceCode:    "ffffaaeeccbb",
		DeviceVersion: "android-gprs-v1",
	}
	device := &models.Device{}
	err := r.RegisterDevice(args, device)
	if err != nil {
		t.Fatal(err)
	}
	t.Log(device)

	device.DeviceDescription = "test change device info."

	args2 := &rpcs.ArgsDeviceUpdate{
		DeviceIdentifier:  device.DeviceIdentifier,
		DeviceName:        "testupdatename",
		DeviceDescription: "test change device info.",
	}
	err = r.UpdateDeviceInfo(args2, device)
	if err != nil {
		t.Error(err)
	}
	t.Log(device)
}

func TestRegistry(t *testing.T) {
	err := mysql.MigrateDatabase(defaultDBHost, defaultDBPort, defaultDBName, defaultDBUser, "")
	if err != nil {
		t.Fatal(err)
	}

	*confAESKey = "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"

	*confDBPass = ""
	r, err := NewRegistry()
	if err != nil {
		t.Fatal(err)
	}

	testVendor(t, r)
	testProduct(t, r)
	testDevice(t, r)
}
<|endoftext|>


<commit_before>/*
Copyright 2016 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 feature

import (
	"fmt"
	"sort"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"

	"github.com/golang/glog"
	"github.com/spf13/pflag"
)

type Feature string

const (
	flagName = "feature-gates"

	// allAlphaGate is a global toggle for alpha features. Per-feature key
	// values override the default set by allAlphaGate. Examples:
	//   AllAlpha=false,NewFeature=true  will result in newFeature=true
	//   AllAlpha=true,NewFeature=false  will result in newFeature=false
	allAlphaGate Feature = "AllAlpha"
)

var (
	// The generic features.
	defaultFeatures = map[Feature]FeatureSpec{
		allAlphaGate: {Default: false, PreRelease: Alpha},
	}

	// Special handling for a few gates.
	specialFeatures = map[Feature]func(known map[Feature]FeatureSpec, enabled map[Feature]bool, val bool){
		allAlphaGate: setUnsetAlphaGates,
	}

	// DefaultFeatureGate is a shared global FeatureGate.
	DefaultFeatureGate FeatureGate = NewFeatureGate()
)

type FeatureSpec struct {
	Default    bool
	PreRelease prerelease
}

type prerelease string

const (
	// Values for PreRelease.
	Alpha = prerelease("ALPHA")
	Beta  = prerelease("BETA")
	GA    = prerelease("")

	// Deprecated
	Deprecated = prerelease("DEPRECATED")
)

// FeatureGate parses and stores flag gates for known features from
// a string like feature1=true,feature2=false,...
type FeatureGate interface {
	// AddFlag adds a flag for setting global feature gates to the specified FlagSet.
	AddFlag(fs *pflag.FlagSet)
	// Set parses and stores flag gates for known features
	// from a string like feature1=true,feature2=false,...
	Set(value string) error
	// SetFromMap stores flag gates for known features from a map[string]bool or returns an error
	SetFromMap(m map[string]bool) error
	// Enabled returns true if the key is enabled.
	Enabled(key Feature) bool
	// Add adds features to the featureGate.
	Add(features map[Feature]FeatureSpec) error
	// KnownFeatures returns a slice of strings describing the FeatureGate's known features.
	KnownFeatures() []string
	// DeepCopy returns a deep copy of the FeatureGate object, such that gates can be
	// set on the copy without mutating the original. This is useful for validating
	// config against potential feature gate changes before committing those changes.
	DeepCopy() FeatureGate
}

// featureGate implements FeatureGate as well as pflag.Value for flag parsing.
type featureGate struct {
	special map[Feature]func(map[Feature]FeatureSpec, map[Feature]bool, bool)

	// lock guards writes to known, enabled, and reads/writes of closed
	lock sync.Mutex
	// known holds a map[Feature]FeatureSpec
	known *atomic.Value
	// enabled holds a map[Feature]bool
	enabled *atomic.Value
	// closed is set to true when AddFlag is called, and prevents subsequent calls to Add
	closed bool
}

func setUnsetAlphaGates(known map[Feature]FeatureSpec, enabled map[Feature]bool, val bool) {
	for k, v := range known {
		if v.PreRelease == Alpha {
			if _, found := enabled[k]; !found {
				enabled[k] = val
			}
		}
	}
}

// Set, String, and Type implement pflag.Value
var _ pflag.Value = &featureGate{}

func NewFeatureGate() *featureGate {
	known := map[Feature]FeatureSpec{}
	for k, v := range defaultFeatures {
		known[k] = v
	}

	knownValue := &atomic.Value{}
	knownValue.Store(known)

	enabled := map[Feature]bool{}
	enabledValue := &atomic.Value{}
	enabledValue.Store(enabled)

	f := &featureGate{
		known:   knownValue,
		special: specialFeatures,
		enabled: enabledValue,
	}
	return f
}

// Set parses a string of the form "key1=value1,key2=value2,..." into a
// map[string]bool of known keys or returns an error.
func (f *featureGate) Set(value string) error {
	f.lock.Lock()
	defer f.lock.Unlock()

	// Copy existing state
	known := map[Feature]FeatureSpec{}
	for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
		known[k] = v
	}
	enabled := map[Feature]bool{}
	for k, v := range f.enabled.Load().(map[Feature]bool) {
		enabled[k] = v
	}

	for _, s := range strings.Split(value, ",") {
		if len(s) == 0 {
			continue
		}
		arr := strings.SplitN(s, "=", 2)
		k := Feature(strings.TrimSpace(arr[0]))
		featureSpec, ok := known[k]
		if !ok {
			return fmt.Errorf("unrecognized key: %s", k)
		}
		if len(arr) != 2 {
			return fmt.Errorf("missing bool value for %s", k)
		}
		v := strings.TrimSpace(arr[1])
		boolValue, err := strconv.ParseBool(v)
		if err != nil {
			return fmt.Errorf("invalid value of %s: %s, err: %v", k, v, err)
		}
		enabled[k] = boolValue
		if boolValue && featureSpec.PreRelease == Deprecated {
			glog.Warningf("enabling deprecated feature gate %s", k)
		}

		// Handle "special" features like "all alpha gates"
		if fn, found := f.special[k]; found {
			fn(known, enabled, boolValue)
		}
	}

	// Persist changes
	f.known.Store(known)
	f.enabled.Store(enabled)

	glog.Infof("feature gates: %v", enabled)
	return nil
}

// SetFromMap stores flag gates for known features from a map[string]bool or returns an error
func (f *featureGate) SetFromMap(m map[string]bool) error {
	f.lock.Lock()
	defer f.lock.Unlock()

	// Copy existing state
	known := map[Feature]FeatureSpec{}
	for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
		known[k] = v
	}
	enabled := map[Feature]bool{}
	for k, v := range f.enabled.Load().(map[Feature]bool) {
		enabled[k] = v
	}

	for k, v := range m {
		k := Feature(k)
		_, ok := known[k]
		if !ok {
			return fmt.Errorf("unrecognized key: %s", k)
		}
		enabled[k] = v
		// Handle "special" features like "all alpha gates"
		if fn, found := f.special[k]; found {
			fn(known, enabled, v)
		}
	}

	// Persist changes
	f.known.Store(known)
	f.enabled.Store(enabled)

	glog.Infof("feature gates: %v", f.enabled)
	return nil
}

// String returns a string containing all enabled feature gates, formatted as "key1=value1,key2=value2,...".
func (f *featureGate) String() string {
	pairs := []string{}
	for k, v := range f.enabled.Load().(map[Feature]bool) {
		pairs = append(pairs, fmt.Sprintf("%s=%t", k, v))
	}
	sort.Strings(pairs)
	return strings.Join(pairs, ",")
}

func (f *featureGate) Type() string {
	return "mapStringBool"
}

// Add adds features to the featureGate.
func (f *featureGate) Add(features map[Feature]FeatureSpec) error {
	f.lock.Lock()
	defer f.lock.Unlock()

	if f.closed {
		return fmt.Errorf("cannot add a feature gate after adding it to the flag set")
	}

	// Copy existing state
	known := map[Feature]FeatureSpec{}
	for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
		known[k] = v
	}

	for name, spec := range features {
		if existingSpec, found := known[name]; found {
			if existingSpec == spec {
				continue
			}
			return fmt.Errorf("feature gate %q with different spec already exists: %v", name, existingSpec)
		}

		known[name] = spec
	}

	// Persist updated state
	f.known.Store(known)

	return nil
}

// Enabled returns true if the key is enabled.
func (f *featureGate) Enabled(key Feature) bool {
	if v, ok := f.enabled.Load().(map[Feature]bool)[key]; ok {
		return v
	}
	return f.known.Load().(map[Feature]FeatureSpec)[key].Default
}

// AddFlag adds a flag for setting global feature gates to the specified FlagSet.
func (f *featureGate) AddFlag(fs *pflag.FlagSet) {
	f.lock.Lock()
	// TODO(mtaufen): Shouldn't we just close it on the first Set/SetFromMap instead?
	// Not all components expose a feature gates flag using this AddFlag method, and
	// in the future, all components will completely stop exposing a feature gates flag,
	// in favor of componentconfig.
	f.closed = true
	f.lock.Unlock()

	known := f.KnownFeatures()
	fs.Var(f, flagName, ""+
		"A set of key=value pairs that describe feature gates for alpha/experimental features. "+
		"Options are:\n"+strings.Join(known, "\n"))
}

// KnownFeatures returns a slice of strings describing the FeatureGate's known features.
func (f *featureGate) KnownFeatures() []string {
	var known []string
	for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
		pre := ""
		if v.PreRelease != GA {
			pre = fmt.Sprintf("%s - ", v.PreRelease)
		}
		known = append(known, fmt.Sprintf("%s=true|false (%sdefault=%t)", k, pre, v.Default))
	}
	sort.Strings(known)
	return known
}

// DeepCopy returns a deep copy of the FeatureGate object, such that gates can be
// set on the copy without mutating the original. This is useful for validating
// config against potential feature gate changes before committing those changes.
func (f *featureGate) DeepCopy() FeatureGate {
	// Copy existing state.
	known := map[Feature]FeatureSpec{}
	for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
		known[k] = v
	}
	enabled := map[Feature]bool{}
	for k, v := range f.enabled.Load().(map[Feature]bool) {
		enabled[k] = v
	}

	// Store copied state in new atomics.
	knownValue := &atomic.Value{}
	knownValue.Store(known)
	enabledValue := &atomic.Value{}
	enabledValue.Store(enabled)

	// Construct a new featureGate around the copied state.
	// Note that specialFeatures is treated as immutable by convention,
	// and we maintain the value of f.closed across the copy.
	return &featureGate{
		special: specialFeatures,
		known:   knownValue,
		enabled: enabledValue,
		closed:  f.closed,
	}
}
<commit_msg>apiserver: do not print feature gates for glog v=0<commit_after>/*
Copyright 2016 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 feature

import (
	"fmt"
	"sort"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"

	"github.com/golang/glog"
	"github.com/spf13/pflag"
)

type Feature string

const (
	flagName = "feature-gates"

	// allAlphaGate is a global toggle for alpha features. Per-feature key
	// values override the default set by allAlphaGate. Examples:
	//   AllAlpha=false,NewFeature=true  will result in newFeature=true
	//   AllAlpha=true,NewFeature=false  will result in newFeature=false
	allAlphaGate Feature = "AllAlpha"
)

var (
	// The generic features.
	defaultFeatures = map[Feature]FeatureSpec{
		allAlphaGate: {Default: false, PreRelease: Alpha},
	}

	// Special handling for a few gates.
	specialFeatures = map[Feature]func(known map[Feature]FeatureSpec, enabled map[Feature]bool, val bool){
		allAlphaGate: setUnsetAlphaGates,
	}

	// DefaultFeatureGate is a shared global FeatureGate.
	DefaultFeatureGate FeatureGate = NewFeatureGate()
)

type FeatureSpec struct {
	Default    bool
	PreRelease prerelease
}

type prerelease string

const (
	// Values for PreRelease.
	Alpha = prerelease("ALPHA")
	Beta  = prerelease("BETA")
	GA    = prerelease("")

	// Deprecated
	Deprecated = prerelease("DEPRECATED")
)

// FeatureGate parses and stores flag gates for known features from
// a string like feature1=true,feature2=false,...
type FeatureGate interface {
	// AddFlag adds a flag for setting global feature gates to the specified FlagSet.
	AddFlag(fs *pflag.FlagSet)
	// Set parses and stores flag gates for known features
	// from a string like feature1=true,feature2=false,...
	Set(value string) error
	// SetFromMap stores flag gates for known features from a map[string]bool or returns an error
	SetFromMap(m map[string]bool) error
	// Enabled returns true if the key is enabled.
	Enabled(key Feature) bool
	// Add adds features to the featureGate.
	Add(features map[Feature]FeatureSpec) error
	// KnownFeatures returns a slice of strings describing the FeatureGate's known features.
	KnownFeatures() []string
	// DeepCopy returns a deep copy of the FeatureGate object, such that gates can be
	// set on the copy without mutating the original. This is useful for validating
	// config against potential feature gate changes before committing those changes.
	DeepCopy() FeatureGate
}

// featureGate implements FeatureGate as well as pflag.Value for flag parsing.
type featureGate struct {
	special map[Feature]func(map[Feature]FeatureSpec, map[Feature]bool, bool)

	// lock guards writes to known, enabled, and reads/writes of closed
	lock sync.Mutex
	// known holds a map[Feature]FeatureSpec
	known *atomic.Value
	// enabled holds a map[Feature]bool
	enabled *atomic.Value
	// closed is set to true when AddFlag is called, and prevents subsequent calls to Add
	closed bool
}

func setUnsetAlphaGates(known map[Feature]FeatureSpec, enabled map[Feature]bool, val bool) {
	for k, v := range known {
		if v.PreRelease == Alpha {
			if _, found := enabled[k]; !found {
				enabled[k] = val
			}
		}
	}
}

// Set, String, and Type implement pflag.Value
var _ pflag.Value = &featureGate{}

func NewFeatureGate() *featureGate {
	known := map[Feature]FeatureSpec{}
	for k, v := range defaultFeatures {
		known[k] = v
	}

	knownValue := &atomic.Value{}
	knownValue.Store(known)

	enabled := map[Feature]bool{}
	enabledValue := &atomic.Value{}
	enabledValue.Store(enabled)

	f := &featureGate{
		known:   knownValue,
		special: specialFeatures,
		enabled: enabledValue,
	}
	return f
}

// Set parses a string of the form "key1=value1,key2=value2,..." into a
// map[string]bool of known keys or returns an error.
func (f *featureGate) Set(value string) error {
	f.lock.Lock()
	defer f.lock.Unlock()

	// Copy existing state
	known := map[Feature]FeatureSpec{}
	for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
		known[k] = v
	}
	enabled := map[Feature]bool{}
	for k, v := range f.enabled.Load().(map[Feature]bool) {
		enabled[k] = v
	}

	for _, s := range strings.Split(value, ",") {
		if len(s) == 0 {
			continue
		}
		arr := strings.SplitN(s, "=", 2)
		k := Feature(strings.TrimSpace(arr[0]))
		featureSpec, ok := known[k]
		if !ok {
			return fmt.Errorf("unrecognized key: %s", k)
		}
		if len(arr) != 2 {
			return fmt.Errorf("missing bool value for %s", k)
		}
		v := strings.TrimSpace(arr[1])
		boolValue, err := strconv.ParseBool(v)
		if err != nil {
			return fmt.Errorf("invalid value of %s: %s, err: %v", k, v, err)
		}
		enabled[k] = boolValue
		if boolValue && featureSpec.PreRelease == Deprecated {
			glog.Warningf("enabling deprecated feature gate %s", k)
		}

		// Handle "special" features like "all alpha gates"
		if fn, found := f.special[k]; found {
			fn(known, enabled, boolValue)
		}
	}

	// Persist changes
	f.known.Store(known)
	f.enabled.Store(enabled)

	glog.V(1).Infof("feature gates: %v", enabled)
	return nil
}

// SetFromMap stores flag gates for known features from a map[string]bool or returns an error
func (f *featureGate) SetFromMap(m map[string]bool) error {
	f.lock.Lock()
	defer f.lock.Unlock()

	// Copy existing state
	known := map[Feature]FeatureSpec{}
	for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
		known[k] = v
	}
	enabled := map[Feature]bool{}
	for k, v := range f.enabled.Load().(map[Feature]bool) {
		enabled[k] = v
	}

	for k, v := range m {
		k := Feature(k)
		_, ok := known[k]
		if !ok {
			return fmt.Errorf("unrecognized key: %s", k)
		}
		enabled[k] = v
		// Handle "special" features like "all alpha gates"
		if fn, found := f.special[k]; found {
			fn(known, enabled, v)
		}
	}

	// Persist changes
	f.known.Store(known)
	f.enabled.Store(enabled)

	glog.V(1).Infof("feature gates: %v", f.enabled)
	return nil
}

// String returns a string containing all enabled feature gates, formatted as "key1=value1,key2=value2,...".
func (f *featureGate) String() string {
	pairs := []string{}
	for k, v := range f.enabled.Load().(map[Feature]bool) {
		pairs = append(pairs, fmt.Sprintf("%s=%t", k, v))
	}
	sort.Strings(pairs)
	return strings.Join(pairs, ",")
}

func (f *featureGate) Type() string {
	return "mapStringBool"
}

// Add adds features to the featureGate.
func (f *featureGate) Add(features map[Feature]FeatureSpec) error {
	f.lock.Lock()
	defer f.lock.Unlock()

	if f.closed {
		return fmt.Errorf("cannot add a feature gate after adding it to the flag set")
	}

	// Copy existing state
	known := map[Feature]FeatureSpec{}
	for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
		known[k] = v
	}

	for name, spec := range features {
		if existingSpec, found := known[name]; found {
			if existingSpec == spec {
				continue
			}
			return fmt.Errorf("feature gate %q with different spec already exists: %v", name, existingSpec)
		}

		known[name] = spec
	}

	// Persist updated state
	f.known.Store(known)

	return nil
}

// Enabled returns true if the key is enabled.
func (f *featureGate) Enabled(key Feature) bool {
	if v, ok := f.enabled.Load().(map[Feature]bool)[key]; ok {
		return v
	}
	return f.known.Load().(map[Feature]FeatureSpec)[key].Default
}

// AddFlag adds a flag for setting global feature gates to the specified FlagSet.
func (f *featureGate) AddFlag(fs *pflag.FlagSet) {
	f.lock.Lock()
	// TODO(mtaufen): Shouldn't we just close it on the first Set/SetFromMap instead?
	// Not all components expose a feature gates flag using this AddFlag method, and
	// in the future, all components will completely stop exposing a feature gates flag,
	// in favor of componentconfig.
	f.closed = true
	f.lock.Unlock()

	known := f.KnownFeatures()
	fs.Var(f, flagName, ""+
		"A set of key=value pairs that describe feature gates for alpha/experimental features. "+
		"Options are:\n"+strings.Join(known, "\n"))
}

// KnownFeatures returns a slice of strings describing the FeatureGate's known features.
func (f *featureGate) KnownFeatures() []string {
	var known []string
	for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
		pre := ""
		if v.PreRelease != GA {
			pre = fmt.Sprintf("%s - ", v.PreRelease)
		}
		known = append(known, fmt.Sprintf("%s=true|false (%sdefault=%t)", k, pre, v.Default))
	}
	sort.Strings(known)
	return known
}

// DeepCopy returns a deep copy of the FeatureGate object, such that gates can be
// set on the copy without mutating the original. This is useful for validating
// config against potential feature gate changes before committing those changes.
func (f *featureGate) DeepCopy() FeatureGate {
	// Copy existing state.
	known := map[Feature]FeatureSpec{}
	for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
		known[k] = v
	}
	enabled := map[Feature]bool{}
	for k, v := range f.enabled.Load().(map[Feature]bool) {
		enabled[k] = v
	}

	// Store copied state in new atomics.
	knownValue := &atomic.Value{}
	knownValue.Store(known)
	enabledValue := &atomic.Value{}
	enabledValue.Store(enabled)

	// Construct a new featureGate around the copied state.
	// Note that specialFeatures is treated as immutable by convention,
	// and we maintain the value of f.closed across the copy.
	return &featureGate{
		special: specialFeatures,
		known:   knownValue,
		enabled: enabledValue,
		closed:  f.closed,
	}
}
<|endoftext|>


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

// Package maphash provides hash functions on byte sequences.
// These hash functions are intended to be used to implement hash tables or
// other data structures that need to map arbitrary strings or byte
// sequences to a uniform distribution of integers.
//
// The hash functions are collision-resistant but not cryptographically secure.
// (See crypto/sha256 and crypto/sha512 for cryptographic use.)
//
// The hash value of a given byte sequence is consistent within a
// single process, but will be different in different processes.
package maphash

import "unsafe"

// A Seed is a random value that selects the specific hash function
// computed by a Hash. If two Hashes use the same Seeds, they
// will compute the same hash values for any given input.
// If two Hashes use different Seeds, they are very likely to compute
// distinct hash values for any given input.
//
// A Seed must be initialized by calling MakeSeed.
// The zero seed is uninitialized and not valid for use with Hash's SetSeed method.
//
// Each Seed value is local to a single process and cannot be serialized
// or otherwise recreated in a different process.
type Seed struct {
	s uint64
}

// A Hash computes a seeded hash of a byte sequence.
//
// The zero Hash is a valid Hash ready to use.
// A zero Hash chooses a random seed for itself during
// the first call to a Reset, Write, Seed, Sum64, or Seed method.
// For control over the seed, use SetSeed.
//
// The computed hash values depend only on the initial seed and
// the sequence of bytes provided to the Hash object, not on the way
// in which the bytes are provided. For example, the three sequences
//
//     h.Write([]byte{'f','o','o'})
//     h.WriteByte('f'); h.WriteByte('o'); h.WriteByte('o')
//     h.WriteString("foo")
//
// all have the same effect.
//
// Hashes are intended to be collision-resistant, even for situations
// where an adversary controls the byte sequences being hashed.
//
// A Hash is not safe for concurrent use by multiple goroutines, but a Seed is.
// If multiple goroutines must compute the same seeded hash,
// each can declare its own Hash and call SetSeed with a common Seed.
type Hash struct {
	_     [0]func() // not comparable
	seed  Seed      // initial seed used for this hash
	state Seed      // current hash of all flushed bytes
	buf   [64]byte  // unflushed byte buffer
	n     int       // number of unflushed bytes
}

// initSeed seeds the hash if necessary.
// initSeed is called lazily before any operation that actually uses h.seed/h.state.
// Note that this does not include Write/WriteByte/WriteString in the case
// where they only add to h.buf. (If they write too much, they call h.flush,
// which does call h.initSeed.)
func (h *Hash) initSeed() {
	if h.seed.s == 0 {
		h.SetSeed(MakeSeed())
	}
}

// WriteByte adds b to the sequence of bytes hashed by h.
// It never fails; the error result is for implementing io.ByteWriter.
func (h *Hash) WriteByte(b byte) error {
	if h.n == len(h.buf) {
		h.flush()
	}
	h.buf[h.n] = b
	h.n++
	return nil
}

// Write adds b to the sequence of bytes hashed by h.
// It always writes all of b and never fails; the count and error result are for implementing io.Writer.
func (h *Hash) Write(b []byte) (int, error) {
	size := len(b)
	for h.n+len(b) > len(h.buf) {
		k := copy(h.buf[h.n:], b)
		h.n = len(h.buf)
		b = b[k:]
		h.flush()
	}
	h.n += copy(h.buf[h.n:], b)
	return size, nil
}

// WriteString adds the bytes of s to the sequence of bytes hashed by h.
// It always writes all of s and never fails; the count and error result are for implementing io.StringWriter.
func (h *Hash) WriteString(s string) (int, error) {
	size := len(s)
	for h.n+len(s) > len(h.buf) {
		k := copy(h.buf[h.n:], s)
		h.n = len(h.buf)
		s = s[k:]
		h.flush()
	}
	h.n += copy(h.buf[h.n:], s)
	return size, nil
}

// Seed returns h's seed value.
func (h *Hash) Seed() Seed {
	h.initSeed()
	return h.seed
}

// SetSeed sets h to use seed, which must have been returned by MakeSeed
// or by another Hash's Seed method.
// Two Hash objects with the same seed behave identically.
// Two Hash objects with different seeds will very likely behave differently.
// Any bytes added to h before this call will be discarded.
func (h *Hash) SetSeed(seed Seed) {
	if seed.s == 0 {
		panic("maphash: use of uninitialized Seed")
	}
	h.seed = seed
	h.state = seed
	h.n = 0
}

// Reset discards all bytes added to h.
// (The seed remains the same.)
func (h *Hash) Reset() {
	h.initSeed()
	h.state = h.seed
	h.n = 0
}

// precondition: buffer is full.
func (h *Hash) flush() {
	if h.n != len(h.buf) {
		panic("maphash: flush of partially full buffer")
	}
	h.initSeed()
	h.state.s = rthash(h.buf[:], h.state.s)
	h.n = 0
}

// Sum64 returns h's current 64-bit value, which depends on
// h's seed and the sequence of bytes added to h since the
// last call to Reset or SetSeed.
//
// All bits of the Sum64 result are close to uniformly and
// independently distributed, so it can be safely reduced
// by using bit masking, shifting, or modular arithmetic.
func (h *Hash) Sum64() uint64 {
	h.initSeed()
	return rthash(h.buf[:h.n], h.state.s)
}

// MakeSeed returns a new random seed.
func MakeSeed() Seed {
	var s1, s2 uint64
	for {
		s1 = uint64(runtime_fastrand())
		s2 = uint64(runtime_fastrand())
		// We use seed 0 to indicate an uninitialized seed/hash,
		// so keep trying until we get a non-zero seed.
		if s1|s2 != 0 {
			break
		}
	}
	return Seed{s: s1<<32 + s2}
}

//go:linkname runtime_fastrand runtime.fastrand
func runtime_fastrand() uint32

func rthash(b []byte, seed uint64) uint64 {
	if len(b) == 0 {
		return seed
	}
	// The runtime hasher only works on uintptr. For 64-bit
	// architectures, we use the hasher directly. Otherwise,
	// we use two parallel hashers on the lower and upper 32 bits.
	if unsafe.Sizeof(uintptr(0)) == 8 {
		return uint64(runtime_memhash(unsafe.Pointer(&b[0]), uintptr(seed), uintptr(len(b))))
	}
	lo := runtime_memhash(unsafe.Pointer(&b[0]), uintptr(seed), uintptr(len(b)))
	hi := runtime_memhash(unsafe.Pointer(&b[0]), uintptr(seed>>32), uintptr(len(b)))
	return uint64(hi)<<32 | uint64(lo)
}

//go:linkname runtime_memhash runtime.memhash
//go:noescape
func runtime_memhash(p unsafe.Pointer, seed, s uintptr) uintptr

// Sum appends the hash's current 64-bit value to b.
// It exists for implementing hash.Hash.
// For direct calls, it is more efficient to use Sum64.
func (h *Hash) Sum(b []byte) []byte {
	x := h.Sum64()
	return append(b,
		byte(x>>0),
		byte(x>>8),
		byte(x>>16),
		byte(x>>24),
		byte(x>>32),
		byte(x>>40),
		byte(x>>48),
		byte(x>>56))
}

// Size returns h's hash value size, 8 bytes.
func (h *Hash) Size() int { return 8 }

// BlockSize returns h's block size.
func (h *Hash) BlockSize() int { return len(h.buf) }
<commit_msg>hash/maphash: mention the results are 64-bit integers<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package maphash provides hash functions on byte sequences.
// These hash functions are intended to be used to implement hash tables or
// other data structures that need to map arbitrary strings or byte
// sequences to a uniform distribution on unsigned 64-bit integers.
//
// The hash functions are collision-resistant but not cryptographically secure.
// (See crypto/sha256 and crypto/sha512 for cryptographic use.)
//
// The hash value of a given byte sequence is consistent within a
// single process, but will be different in different processes.
package maphash

import "unsafe"

// A Seed is a random value that selects the specific hash function
// computed by a Hash. If two Hashes use the same Seeds, they
// will compute the same hash values for any given input.
// If two Hashes use different Seeds, they are very likely to compute
// distinct hash values for any given input.
//
// A Seed must be initialized by calling MakeSeed.
// The zero seed is uninitialized and not valid for use with Hash's SetSeed method.
//
// Each Seed value is local to a single process and cannot be serialized
// or otherwise recreated in a different process.
type Seed struct {
	s uint64
}

// A Hash computes a seeded hash of a byte sequence.
//
// The zero Hash is a valid Hash ready to use.
// A zero Hash chooses a random seed for itself during
// the first call to a Reset, Write, Seed, Sum64, or Seed method.
// For control over the seed, use SetSeed.
//
// The computed hash values depend only on the initial seed and
// the sequence of bytes provided to the Hash object, not on the way
// in which the bytes are provided. For example, the three sequences
//
//     h.Write([]byte{'f','o','o'})
//     h.WriteByte('f'); h.WriteByte('o'); h.WriteByte('o')
//     h.WriteString("foo")
//
// all have the same effect.
//
// Hashes are intended to be collision-resistant, even for situations
// where an adversary controls the byte sequences being hashed.
//
// A Hash is not safe for concurrent use by multiple goroutines, but a Seed is.
// If multiple goroutines must compute the same seeded hash,
// each can declare its own Hash and call SetSeed with a common Seed.
type Hash struct {
	_     [0]func() // not comparable
	seed  Seed      // initial seed used for this hash
	state Seed      // current hash of all flushed bytes
	buf   [64]byte  // unflushed byte buffer
	n     int       // number of unflushed bytes
}

// initSeed seeds the hash if necessary.
// initSeed is called lazily before any operation that actually uses h.seed/h.state.
// Note that this does not include Write/WriteByte/WriteString in the case
// where they only add to h.buf. (If they write too much, they call h.flush,
// which does call h.initSeed.)
func (h *Hash) initSeed() {
	if h.seed.s == 0 {
		h.SetSeed(MakeSeed())
	}
}

// WriteByte adds b to the sequence of bytes hashed by h.
// It never fails; the error result is for implementing io.ByteWriter.
func (h *Hash) WriteByte(b byte) error {
	if h.n == len(h.buf) {
		h.flush()
	}
	h.buf[h.n] = b
	h.n++
	return nil
}

// Write adds b to the sequence of bytes hashed by h.
// It always writes all of b and never fails; the count and error result are for implementing io.Writer.
func (h *Hash) Write(b []byte) (int, error) {
	size := len(b)
	for h.n+len(b) > len(h.buf) {
		k := copy(h.buf[h.n:], b)
		h.n = len(h.buf)
		b = b[k:]
		h.flush()
	}
	h.n += copy(h.buf[h.n:], b)
	return size, nil
}

// WriteString adds the bytes of s to the sequence of bytes hashed by h.
// It always writes all of s and never fails; the count and error result are for implementing io.StringWriter.
func (h *Hash) WriteString(s string) (int, error) {
	size := len(s)
	for h.n+len(s) > len(h.buf) {
		k := copy(h.buf[h.n:], s)
		h.n = len(h.buf)
		s = s[k:]
		h.flush()
	}
	h.n += copy(h.buf[h.n:], s)
	return size, nil
}

// Seed returns h's seed value.
func (h *Hash) Seed() Seed {
	h.initSeed()
	return h.seed
}

// SetSeed sets h to use seed, which must have been returned by MakeSeed
// or by another Hash's Seed method.
// Two Hash objects with the same seed behave identically.
// Two Hash objects with different seeds will very likely behave differently.
// Any bytes added to h before this call will be discarded.
func (h *Hash) SetSeed(seed Seed) {
	if seed.s == 0 {
		panic("maphash: use of uninitialized Seed")
	}
	h.seed = seed
	h.state = seed
	h.n = 0
}

// Reset discards all bytes added to h.
// (The seed remains the same.)
func (h *Hash) Reset() {
	h.initSeed()
	h.state = h.seed
	h.n = 0
}

// precondition: buffer is full.
func (h *Hash) flush() {
	if h.n != len(h.buf) {
		panic("maphash: flush of partially full buffer")
	}
	h.initSeed()
	h.state.s = rthash(h.buf[:], h.state.s)
	h.n = 0
}

// Sum64 returns h's current 64-bit value, which depends on
// h's seed and the sequence of bytes added to h since the
// last call to Reset or SetSeed.
//
// All bits of the Sum64 result are close to uniformly and
// independently distributed, so it can be safely reduced
// by using bit masking, shifting, or modular arithmetic.
func (h *Hash) Sum64() uint64 {
	h.initSeed()
	return rthash(h.buf[:h.n], h.state.s)
}

// MakeSeed returns a new random seed.
func MakeSeed() Seed {
	var s1, s2 uint64
	for {
		s1 = uint64(runtime_fastrand())
		s2 = uint64(runtime_fastrand())
		// We use seed 0 to indicate an uninitialized seed/hash,
		// so keep trying until we get a non-zero seed.
		if s1|s2 != 0 {
			break
		}
	}
	return Seed{s: s1<<32 + s2}
}

//go:linkname runtime_fastrand runtime.fastrand
func runtime_fastrand() uint32

func rthash(b []byte, seed uint64) uint64 {
	if len(b) == 0 {
		return seed
	}
	// The runtime hasher only works on uintptr. For 64-bit
	// architectures, we use the hasher directly. Otherwise,
	// we use two parallel hashers on the lower and upper 32 bits.
	if unsafe.Sizeof(uintptr(0)) == 8 {
		return uint64(runtime_memhash(unsafe.Pointer(&b[0]), uintptr(seed), uintptr(len(b))))
	}
	lo := runtime_memhash(unsafe.Pointer(&b[0]), uintptr(seed), uintptr(len(b)))
	hi := runtime_memhash(unsafe.Pointer(&b[0]), uintptr(seed>>32), uintptr(len(b)))
	return uint64(hi)<<32 | uint64(lo)
}

//go:linkname runtime_memhash runtime.memhash
//go:noescape
func runtime_memhash(p unsafe.Pointer, seed, s uintptr) uintptr

// Sum appends the hash's current 64-bit value to b.
// It exists for implementing hash.Hash.
// For direct calls, it is more efficient to use Sum64.
func (h *Hash) Sum(b []byte) []byte {
	x := h.Sum64()
	return append(b,
		byte(x>>0),
		byte(x>>8),
		byte(x>>16),
		byte(x>>24),
		byte(x>>32),
		byte(x>>40),
		byte(x>>48),
		byte(x>>56))
}

// Size returns h's hash value size, 8 bytes.
func (h *Hash) Size() int { return 8 }

// BlockSize returns h's block size.
func (h *Hash) BlockSize() int { return len(h.buf) }
<|endoftext|>


<commit_before>package test_helpers_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/cloudfoundry-incubator/lattice/ltc/test_helpers"
	"github.com/codegangsta/cli"
)

var _ = Describe("CommandExecutor", func() {

	var (
		commandRan bool
		cliCommand cli.Command
	)

	BeforeEach(func() {
		commandRan = false
		cliCommand = cli.Command{
			Name: "exec",
			Action: func(*cli.Context) {
				commandRan = true
			},
		}
	})

	AfterEach(func() {
		Expect(commandRan).To(BeTrue())
	})

	Describe("ExecuteCommandWithArgs", func() {
		It("executes the command", func() {
			test_helpers.ExecuteCommandWithArgs(cliCommand, []string{})
		})
	})

	Describe("AsyncExecuteCommandWithArgs", func() {
		It("executes the command", func(done Done) {
			done <- test_helpers.AsyncExecuteCommandWithArgs(cliCommand, []string{})
		})
	})
})
<commit_msg>Fix race conditions in command_executor_test.<commit_after>package test_helpers_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/cloudfoundry-incubator/lattice/ltc/test_helpers"
	"github.com/codegangsta/cli"
)

var _ = Describe("CommandExecutor", func() {

	var (
		commandRan bool
		cliCommand cli.Command
	)

	BeforeEach(func() {
		commandRan = false

		cliCommand = cli.Command{
			Name: "exec",
			Action: func(*cli.Context) {
				commandRan = true
			},
		}
	})

	Describe("ExecuteCommandWithArgs", func() {
		It("executes the command", func() {
			test_helpers.ExecuteCommandWithArgs(cliCommand, []string{})

			Expect(commandRan).To(BeTrue())
		})
	})

	Describe("AsyncExecuteCommandWithArgs", func() {
		It("executes the command", func() {
			doneChan := test_helpers.AsyncExecuteCommandWithArgs(cliCommand, []string{})

			Eventually(doneChan).Should(BeClosed())
			Expect(commandRan).To(BeTrue())
		})
	})
})
<|endoftext|>