<commit_before>package core

import (
	"sync"

	"github.com/af83/edwig/model"
	"github.com/af83/edwig/siri"
)

type StopMonitoringSubscriptionBroadcaster interface {
	model.Stopable
	model.Startable

	HandleStopMonitoringBroadcastEvent(*model.StopMonitoringBroadcastEvent)
	HandleSubscriptionRequest([]*siri.XMLStopMonitoringSubscriptionRequestEntry)
}

type SIRIStopMonitoringSubscriptionBroadcaster struct {
	model.ClockConsumer
	model.UUIDConsumer

	siriConnector

	stopMonitoringBroadcaster SIRIStopMonitoringBroadcaster
	toBroadcast               map[SubscriptionId][]model.StopVisitId
	mutex                     *sync.Mutex //protect the map
}

type SIRIStopMonitoringSubscriptionBroadcasterFactory struct{}

func (factory *SIRIStopMonitoringSubscriptionBroadcasterFactory) CreateConnector(partner *Partner) Connector {
	if _, ok := partner.Connector(SIRI_SUBSCRIPTION_REQUEST_DISPATCHER); !ok {
		partner.CreateSubscriptionRequestDispatcher()
	}
	return newSIRIStopMonitoringSubscriptionBroadcaster(partner)
}

func (factory *SIRIStopMonitoringSubscriptionBroadcasterFactory) Validate(apiPartner *APIPartner) bool {
	ok := apiPartner.ValidatePresenceOfSetting("remote_objectid_kind")
	ok = ok && apiPartner.ValidatePresenceOfSetting("remote_url")
	ok = ok && apiPartner.ValidatePresenceOfSetting("remote_credential")
	return ok
}

func newSIRIStopMonitoringSubscriptionBroadcaster(partner *Partner) *SIRIStopMonitoringSubscriptionBroadcaster {
	siriStopMonitoringSubscriptionBroadcaster := &SIRIStopMonitoringSubscriptionBroadcaster{}
	siriStopMonitoringSubscriptionBroadcaster.partner = partner
	siriStopMonitoringSubscriptionBroadcaster.mutex = &sync.Mutex{}
	siriStopMonitoringSubscriptionBroadcaster.toBroadcast = make(map[SubscriptionId][]model.StopVisitId)

	siriStopMonitoringSubscriptionBroadcaster.stopMonitoringBroadcaster = NewSIRIStopMonitoringBroadcaster(siriStopMonitoringSubscriptionBroadcaster)

	return siriStopMonitoringSubscriptionBroadcaster
}

func (connector *SIRIStopMonitoringSubscriptionBroadcaster) Stop() {
	connector.stopMonitoringBroadcaster.Stop()
}

func (connector *SIRIStopMonitoringSubscriptionBroadcaster) Start() {
	connector.stopMonitoringBroadcaster.Start()
}

func (connector *SIRIStopMonitoringSubscriptionBroadcaster) HandleStopMonitoringBroadcastEvent(event *model.StopMonitoringBroadcastEvent) {
	tx := connector.Partner().Referential().NewTransaction()
	defer tx.Close()

	switch event.ModelType {
	case "StopVisit":
		sv, ok := tx.Model().StopVisits().Find(model.StopVisitId(event.ModelId))
		subId, ok := connector.checkEvent(sv, tx)
		if ok {
			connector.addStopVisit(subId, sv.Id())
		}
	case "VehicleJourney":
		for _, sv := range tx.Model().StopVisits().FindFollowingByVehicleJourneyId(model.VehicleJourneyId(event.ModelId)) {
			subId, ok := connector.checkEvent(sv, tx)
			if ok {
				connector.addStopVisit(subId, sv.Id())
			}
		}
	default:
		return
	}
}

func (connector *SIRIStopMonitoringSubscriptionBroadcaster) addStopVisit(subId SubscriptionId, svId model.StopVisitId) {
	connector.mutex.Lock()
	connector.toBroadcast[SubscriptionId(subId)] = append(connector.toBroadcast[SubscriptionId(subId)], svId)
	connector.mutex.Unlock()
}

func (connector *SIRIStopMonitoringSubscriptionBroadcaster) checkEvent(sv model.StopVisit, tx *model.Transaction) (SubscriptionId, bool) {
	subId := SubscriptionId(0) //just to return a correct type for errors

	stopArea, ok := tx.Model().StopAreas().Find(sv.StopAreaId)
	if !ok {
		return subId, false
	}

	obj, ok := stopArea.ObjectID(connector.partner.RemoteObjectIDKind(SIRI_STOP_MONITORING_SUBSCRIPTION_BROADCASTER))
	if !ok {
		return subId, false
	}

	sub, ok := connector.partner.Subscriptions().FindByRessourceId(obj.String())
	if !ok {
		return subId, false
	}

	resources := sub.ResourcesByObjectID()

	resource, ok := resources[obj.String()]

	if !ok {
		return subId, false
	}

	lastState, ok := resource.LastStates[string(sv.Id())]

	if ok && !lastState.(*stopMonitoringLastChange).Haschanged(sv) {
		return subId, false
	}

	if !ok {
		smlc := &stopMonitoringLastChange{}
		smlc.SetSubscription(sub)
		resource.LastStates[string(sv.Id())] = smlc
	}

	return sub.Id(), true
}

func (connector *SIRIStopMonitoringSubscriptionBroadcaster) HandleSubscriptionRequest(request *siri.XMLSubscriptionRequest) []siri.SIRIResponseStatus {
	sms := request.XMLSubscriptionSMEntries()

	tx := connector.Partner().Referential().NewTransaction()
	defer tx.Close()

	resps := []siri.SIRIResponseStatus{}

	for _, sm := range sms {

		rs := siri.SIRIResponseStatus{
			RequestMessageRef: sm.MessageIdentifier(),
			SubscriberRef:     sm.SubscriberRef(),
			SubscriptionRef:   sm.SubscriptionIdentifier(),
			ResponseTimestamp: connector.Clock().Now(),
		}

		objectid := model.NewObjectID(connector.partner.RemoteObjectIDKind(SIRI_STOP_MONITORING_SUBSCRIPTION_BROADCASTER), sm.MonitoringRef())
		sa, ok := tx.Model().StopAreas().FindByObjectId(objectid)
		if !ok {
			resps = append(resps, rs)
			continue
		}

		sub, ok := connector.Partner().Subscriptions().FindByExternalId(sm.SubscriptionIdentifier())
		if !ok {
			sub = connector.Partner().Subscriptions().New("StopArea")
			sub.SetExternalId(sm.SubscriptionIdentifier())
		}

		ref := model.Reference{
			ObjectId: &objectid,
			Id:       string(sa.Id()),
			Type:     "StopArea",
		}

		r := sub.CreateAddNewResource(ref)
		r.SubscribedUntil = sm.InitialTerminationTime()

		connector.fillOptions(sub, r, request, sm)

		rs.Status = true
		rs.ValidUntil = sm.InitialTerminationTime()
		resps = append(resps, rs)

		connector.AddStopAreaStopVisits(sa, sub, r)
	}
	return resps
}

func (connector *SIRIStopMonitoringSubscriptionBroadcaster) AddStopAreaStopVisits(sa model.StopArea, sub *Subscription, res *SubscribedResource) {
	tx := connector.Partner().Referential().NewTransaction()
	defer tx.Close()

	svs := tx.Model().StopVisits().FindFollowingByStopAreaId(sa.Id())
	for _, sv := range svs {
		_, ok := sv.ObjectID(connector.partner.RemoteObjectIDKind(SIRI_STOP_MONITORING_SUBSCRIPTION_BROADCASTER))
		if !ok {
			continue
		}
		smlc := &stopMonitoringLastChange{}
		smlc.SetSubscription(sub)
		res.LastStates[string(sv.Id())] = smlc
		connector.addStopVisit(sub.Id(), sv.Id())
	}
}

func (smsb *SIRIStopMonitoringSubscriptionBroadcaster) fillOptions(s *Subscription, r *SubscribedResource, request *siri.XMLSubscriptionRequest, sm *siri.XMLStopMonitoringSubscriptionRequestEntry) {
	ro := r.ResourcesOptions()
	ro["StopVisitTypes"] = sm.StopVisitTypes()

	so := s.SubscriptionOptions()

	so["IncrementalUpdates"] = request.IncrementalUpdates()
	so["MaximumStopVisits"] = request.MaximumStopVisits()
	so["ChangeBeforeUpdates"] = request.ChangeBeforeUpdates()
}

// START TEST

type TestSIRIStopMonitoringSubscriptionBroadcasterFactory struct{}

type TestStopMonitoringSubscriptionBroadcaster struct {
	model.UUIDConsumer

	events                    []*model.StopMonitoringBroadcastEvent
	stopMonitoringBroadcaster SIRIStopMonitoringBroadcaster
}

func NewTestStopMonitoringSubscriptionBroadcaster() *TestStopMonitoringSubscriptionBroadcaster {
	connector := &TestStopMonitoringSubscriptionBroadcaster{}
	return connector
}

func (connector *TestStopMonitoringSubscriptionBroadcaster) HandleStopMonitoringBroadcastEvent(event *model.StopMonitoringBroadcastEvent) {
	connector.events = append(connector.events, event)
}

func (factory *TestSIRIStopMonitoringSubscriptionBroadcasterFactory) Validate(apiPartner *APIPartner) bool {
	return true
}

func (factory *TestSIRIStopMonitoringSubscriptionBroadcasterFactory) CreateConnector(partner *Partner) Connector {
	return NewTestStopMonitoringSubscriptionBroadcaster()
}

// END TEST
<commit_msg>Ignoring subscription with initial time passed<commit_after>package core

import (
	"sync"

	"github.com/af83/edwig/model"
	"github.com/af83/edwig/siri"
)

type StopMonitoringSubscriptionBroadcaster interface {
	model.Stopable
	model.Startable

	HandleStopMonitoringBroadcastEvent(*model.StopMonitoringBroadcastEvent)
	HandleSubscriptionRequest([]*siri.XMLStopMonitoringSubscriptionRequestEntry)
}

type SIRIStopMonitoringSubscriptionBroadcaster struct {
	model.ClockConsumer
	model.UUIDConsumer

	siriConnector

	stopMonitoringBroadcaster SIRIStopMonitoringBroadcaster
	toBroadcast               map[SubscriptionId][]model.StopVisitId
	mutex                     *sync.Mutex //protect the map
}

type SIRIStopMonitoringSubscriptionBroadcasterFactory struct{}

func (factory *SIRIStopMonitoringSubscriptionBroadcasterFactory) CreateConnector(partner *Partner) Connector {
	if _, ok := partner.Connector(SIRI_SUBSCRIPTION_REQUEST_DISPATCHER); !ok {
		partner.CreateSubscriptionRequestDispatcher()
	}
	return newSIRIStopMonitoringSubscriptionBroadcaster(partner)
}

func (factory *SIRIStopMonitoringSubscriptionBroadcasterFactory) Validate(apiPartner *APIPartner) bool {
	ok := apiPartner.ValidatePresenceOfSetting("remote_objectid_kind")
	ok = ok && apiPartner.ValidatePresenceOfSetting("remote_url")
	ok = ok && apiPartner.ValidatePresenceOfSetting("remote_credential")
	return ok
}

func newSIRIStopMonitoringSubscriptionBroadcaster(partner *Partner) *SIRIStopMonitoringSubscriptionBroadcaster {
	siriStopMonitoringSubscriptionBroadcaster := &SIRIStopMonitoringSubscriptionBroadcaster{}
	siriStopMonitoringSubscriptionBroadcaster.partner = partner
	siriStopMonitoringSubscriptionBroadcaster.mutex = &sync.Mutex{}
	siriStopMonitoringSubscriptionBroadcaster.toBroadcast = make(map[SubscriptionId][]model.StopVisitId)

	siriStopMonitoringSubscriptionBroadcaster.stopMonitoringBroadcaster = NewSIRIStopMonitoringBroadcaster(siriStopMonitoringSubscriptionBroadcaster)

	return siriStopMonitoringSubscriptionBroadcaster
}

func (connector *SIRIStopMonitoringSubscriptionBroadcaster) Stop() {
	connector.stopMonitoringBroadcaster.Stop()
}

func (connector *SIRIStopMonitoringSubscriptionBroadcaster) Start() {
	connector.stopMonitoringBroadcaster.Start()
}

func (connector *SIRIStopMonitoringSubscriptionBroadcaster) HandleStopMonitoringBroadcastEvent(event *model.StopMonitoringBroadcastEvent) {
	tx := connector.Partner().Referential().NewTransaction()
	defer tx.Close()

	switch event.ModelType {
	case "StopVisit":
		sv, ok := tx.Model().StopVisits().Find(model.StopVisitId(event.ModelId))
		subId, ok := connector.checkEvent(sv, tx)
		if ok {
			connector.addStopVisit(subId, sv.Id())
		}
	case "VehicleJourney":
		for _, sv := range tx.Model().StopVisits().FindFollowingByVehicleJourneyId(model.VehicleJourneyId(event.ModelId)) {
			subId, ok := connector.checkEvent(sv, tx)
			if ok {
				connector.addStopVisit(subId, sv.Id())
			}
		}
	default:
		return
	}
}

func (connector *SIRIStopMonitoringSubscriptionBroadcaster) addStopVisit(subId SubscriptionId, svId model.StopVisitId) {
	connector.mutex.Lock()
	connector.toBroadcast[SubscriptionId(subId)] = append(connector.toBroadcast[SubscriptionId(subId)], svId)
	connector.mutex.Unlock()
}

func (connector *SIRIStopMonitoringSubscriptionBroadcaster) checkEvent(sv model.StopVisit, tx *model.Transaction) (SubscriptionId, bool) {
	subId := SubscriptionId(0) //just to return a correct type for errors

	stopArea, ok := tx.Model().StopAreas().Find(sv.StopAreaId)
	if !ok {
		return subId, false
	}

	obj, ok := stopArea.ObjectID(connector.partner.RemoteObjectIDKind(SIRI_STOP_MONITORING_SUBSCRIPTION_BROADCASTER))
	if !ok {
		return subId, false
	}

	_, ok = stopArea.ObjectID(connector.Partner().Setting("remote_objectid_kind"))

	sub, ok := connector.partner.Subscriptions().FindByRessourceId(obj.String())
	if !ok {
		return subId, false
	}

	resources := sub.ResourcesByObjectID()

	resource, ok := resources[obj.String()]

	if !ok || resource.SubscribedUntil.Before(connector.Clock().Now()) {
		return subId, false
	}

	lastState, ok := resource.LastStates[string(sv.Id())]

	if ok && !lastState.(*stopMonitoringLastChange).Haschanged(sv) {
		return subId, false
	}

	if !ok {
		smlc := &stopMonitoringLastChange{}
		smlc.SetSubscription(sub)
		resource.LastStates[string(sv.Id())] = smlc
	}

	return sub.Id(), true
}

func (connector *SIRIStopMonitoringSubscriptionBroadcaster) HandleSubscriptionRequest(request *siri.XMLSubscriptionRequest) []siri.SIRIResponseStatus {
	sms := request.XMLSubscriptionSMEntries()

	tx := connector.Partner().Referential().NewTransaction()
	defer tx.Close()

	resps := []siri.SIRIResponseStatus{}

	for _, sm := range sms {

		rs := siri.SIRIResponseStatus{
			RequestMessageRef: sm.MessageIdentifier(),
			SubscriberRef:     sm.SubscriberRef(),
			SubscriptionRef:   sm.SubscriptionIdentifier(),
			ResponseTimestamp: connector.Clock().Now(),
		}

		objectid := model.NewObjectID(connector.partner.RemoteObjectIDKind(SIRI_STOP_MONITORING_SUBSCRIPTION_BROADCASTER), sm.MonitoringRef())
		sa, ok := tx.Model().StopAreas().FindByObjectId(objectid)
		if !ok {
			resps = append(resps, rs)
			continue
		}

		sub, ok := connector.Partner().Subscriptions().FindByExternalId(sm.SubscriptionIdentifier())
		if !ok {
			sub = connector.Partner().Subscriptions().New("StopArea")
			sub.SetExternalId(sm.SubscriptionIdentifier())
		}

		ref := model.Reference{
			ObjectId: &objectid,
			Id:       string(sa.Id()),
			Type:     "StopArea",
		}

		r := sub.CreateAddNewResource(ref)
		r.SubscribedUntil = sm.InitialTerminationTime()

		connector.fillOptions(sub, r, request, sm)

		rs.Status = true
		rs.ValidUntil = sm.InitialTerminationTime()
		resps = append(resps, rs)

		connector.AddStopAreaStopVisits(sa, sub, r)
	}
	return resps
}

func (connector *SIRIStopMonitoringSubscriptionBroadcaster) AddStopAreaStopVisits(sa model.StopArea, sub *Subscription, res *SubscribedResource) {
	tx := connector.Partner().Referential().NewTransaction()
	defer tx.Close()

	svs := tx.Model().StopVisits().FindFollowingByStopAreaId(sa.Id())
	for _, sv := range svs {
		_, ok := sv.ObjectID(connector.partner.RemoteObjectIDKind(SIRI_STOP_MONITORING_SUBSCRIPTION_BROADCASTER))
		if !ok {
			continue
		}
		smlc := &stopMonitoringLastChange{}
		smlc.SetSubscription(sub)
		res.LastStates[string(sv.Id())] = smlc
		connector.addStopVisit(sub.Id(), sv.Id())
	}
}

func (smsb *SIRIStopMonitoringSubscriptionBroadcaster) fillOptions(s *Subscription, r *SubscribedResource, request *siri.XMLSubscriptionRequest, sm *siri.XMLStopMonitoringSubscriptionRequestEntry) {
	ro := r.ResourcesOptions()
	ro["StopVisitTypes"] = sm.StopVisitTypes()

	so := s.SubscriptionOptions()

	so["IncrementalUpdates"] = request.IncrementalUpdates()
	so["MaximumStopVisits"] = request.MaximumStopVisits()
	so["ChangeBeforeUpdates"] = request.ChangeBeforeUpdates()
}

// START TEST

type TestSIRIStopMonitoringSubscriptionBroadcasterFactory struct{}

type TestStopMonitoringSubscriptionBroadcaster struct {
	model.UUIDConsumer

	events                    []*model.StopMonitoringBroadcastEvent
	stopMonitoringBroadcaster SIRIStopMonitoringBroadcaster
}

func NewTestStopMonitoringSubscriptionBroadcaster() *TestStopMonitoringSubscriptionBroadcaster {
	connector := &TestStopMonitoringSubscriptionBroadcaster{}
	return connector
}

func (connector *TestStopMonitoringSubscriptionBroadcaster) HandleStopMonitoringBroadcastEvent(event *model.StopMonitoringBroadcastEvent) {
	connector.events = append(connector.events, event)
}

func (factory *TestSIRIStopMonitoringSubscriptionBroadcasterFactory) Validate(apiPartner *APIPartner) bool {
	return true
}

func (factory *TestSIRIStopMonitoringSubscriptionBroadcasterFactory) CreateConnector(partner *Partner) Connector {
	return NewTestStopMonitoringSubscriptionBroadcaster()
}

// END TEST
<|endoftext|>


<commit_before>package awsauth

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/hashicorp/vault/api"
	"github.com/hashicorp/vault/helper/awsutil"
)

type CLIHandler struct{}

func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
	mount, ok := m["mount"]
	if !ok {
		mount = "aws"
	}

	role, ok := m["role"]
	if !ok {
		role = ""
	}

	headerValue, ok := m["header_value"]
	if !ok {
		headerValue = ""
	}

	// Grab any supplied credentials off the command line
	// Ensure we're able to fall back to the SDK default credential providers
	credConfig := &awsutil.CredentialsConfig{
		AccessKey:    m["aws_access_key_id"],
		SecretKey:    m["aws_secret_access_key"],
		SessionToken: m["aws_security_token"],
	}
	creds, err := credConfig.GenerateCredentialChain()
	if err != nil {
		return "", err
	}
	if creds == nil {
		return "", fmt.Errorf("could not compile valid credential providers from static config, environemnt, shared, or instance metadata")
	}

	// Use the credentials we've found to construct an STS session
	stsSession, err := session.NewSessionWithOptions(session.Options{
		Config: aws.Config{Credentials: creds},
	})
	if err != nil {
		return "", err
	}

	var params *sts.GetCallerIdentityInput
	svc := sts.New(stsSession)
	stsRequest, _ := svc.GetCallerIdentityRequest(params)

	// Inject the required auth header value, if suplied, and then sign the request including that header
	if headerValue != "" {
		stsRequest.HTTPRequest.Header.Add(iamServerIdHeader, headerValue)
	}
	stsRequest.Sign()

	// Now extract out the relevant parts of the request
	headersJson, err := json.Marshal(stsRequest.HTTPRequest.Header)
	if err != nil {
		return "", err
	}
	requestBody, err := ioutil.ReadAll(stsRequest.HTTPRequest.Body)
	if err != nil {
		return "", err
	}
	method := stsRequest.HTTPRequest.Method
	targetUrl := base64.StdEncoding.EncodeToString([]byte(stsRequest.HTTPRequest.URL.String()))
	headers := base64.StdEncoding.EncodeToString(headersJson)
	body := base64.StdEncoding.EncodeToString(requestBody)

	// And pass them on to the Vault server
	path := fmt.Sprintf("auth/%s/login", mount)
	secret, err := c.Logical().Write(path, map[string]interface{}{
		"iam_http_request_method": method,
		"iam_request_url":         targetUrl,
		"iam_request_headers":     headers,
		"iam_request_body":        body,
		"role":                    role,
	})

	if err != nil {
		return "", err
	}
	if secret == nil {
		return "", fmt.Errorf("empty response from credential provider")
	}

	return secret.Auth.ClientToken, nil
}

func (h *CLIHandler) Help() string {
	help := `
The AWS credential provider allows you to authenticate with
AWS IAM credentials. To use it, you specify valid AWS IAM credentials
in one of a number of ways. They can be specified explicitly on the
command line (which in general you should not do), via the standard AWS
environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and
AWS_SECURITY_TOKEN), via the ~/.aws/credentials file, or via an EC2
instance profile (in that order).

  Example: vault auth -method=aws

If you need to explicitly pass in credentials, you would do it like this:
  Example: vault auth -method=aws aws_access_key_id=<access key> aws_secret_access_key=<secret key> aws_security_token=<token>

Key/Value Pairs:

  mount=aws                           The mountpoint for the AWS credential provider.
                                      Defaults to "aws"
  aws_access_key_id=<access key>      Explicitly specified AWS access key
  aws_secret_access_key=<secret key>  Explicitly specified AWS secret key
  aws_security_token=<token>          Security token for temporary credentials
  header_value                        The Value of the X-Vault-AWS-IAM-Server-ID header.
  role                                The name of the role you're requesting a token for
  `

	return strings.TrimSpace(help)
}
<commit_msg>Fixes typos in error message and comment for AWS auth CLI (#2798)<commit_after>package awsauth

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/hashicorp/vault/api"
	"github.com/hashicorp/vault/helper/awsutil"
)

type CLIHandler struct{}

func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
	mount, ok := m["mount"]
	if !ok {
		mount = "aws"
	}

	role, ok := m["role"]
	if !ok {
		role = ""
	}

	headerValue, ok := m["header_value"]
	if !ok {
		headerValue = ""
	}

	// Grab any supplied credentials off the command line
	// Ensure we're able to fall back to the SDK default credential providers
	credConfig := &awsutil.CredentialsConfig{
		AccessKey:    m["aws_access_key_id"],
		SecretKey:    m["aws_secret_access_key"],
		SessionToken: m["aws_security_token"],
	}
	creds, err := credConfig.GenerateCredentialChain()
	if err != nil {
		return "", err
	}
	if creds == nil {
		return "", fmt.Errorf("could not compile valid credential providers from static config, environment, shared, or instance metadata")
	}

	// Use the credentials we've found to construct an STS session
	stsSession, err := session.NewSessionWithOptions(session.Options{
		Config: aws.Config{Credentials: creds},
	})
	if err != nil {
		return "", err
	}

	var params *sts.GetCallerIdentityInput
	svc := sts.New(stsSession)
	stsRequest, _ := svc.GetCallerIdentityRequest(params)

	// Inject the required auth header value, if supplied, and then sign the request including that header
	if headerValue != "" {
		stsRequest.HTTPRequest.Header.Add(iamServerIdHeader, headerValue)
	}
	stsRequest.Sign()

	// Now extract out the relevant parts of the request
	headersJson, err := json.Marshal(stsRequest.HTTPRequest.Header)
	if err != nil {
		return "", err
	}
	requestBody, err := ioutil.ReadAll(stsRequest.HTTPRequest.Body)
	if err != nil {
		return "", err
	}
	method := stsRequest.HTTPRequest.Method
	targetUrl := base64.StdEncoding.EncodeToString([]byte(stsRequest.HTTPRequest.URL.String()))
	headers := base64.StdEncoding.EncodeToString(headersJson)
	body := base64.StdEncoding.EncodeToString(requestBody)

	// And pass them on to the Vault server
	path := fmt.Sprintf("auth/%s/login", mount)
	secret, err := c.Logical().Write(path, map[string]interface{}{
		"iam_http_request_method": method,
		"iam_request_url":         targetUrl,
		"iam_request_headers":     headers,
		"iam_request_body":        body,
		"role":                    role,
	})

	if err != nil {
		return "", err
	}
	if secret == nil {
		return "", fmt.Errorf("empty response from credential provider")
	}

	return secret.Auth.ClientToken, nil
}

func (h *CLIHandler) Help() string {
	help := `
The AWS credential provider allows you to authenticate with
AWS IAM credentials. To use it, you specify valid AWS IAM credentials
in one of a number of ways. They can be specified explicitly on the
command line (which in general you should not do), via the standard AWS
environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and
AWS_SECURITY_TOKEN), via the ~/.aws/credentials file, or via an EC2
instance profile (in that order).

  Example: vault auth -method=aws

If you need to explicitly pass in credentials, you would do it like this:
  Example: vault auth -method=aws aws_access_key_id=<access key> aws_secret_access_key=<secret key> aws_security_token=<token>

Key/Value Pairs:

  mount=aws                           The mountpoint for the AWS credential provider.
                                      Defaults to "aws"
  aws_access_key_id=<access key>      Explicitly specified AWS access key
  aws_secret_access_key=<secret key>  Explicitly specified AWS secret key
  aws_security_token=<token>          Security token for temporary credentials
  header_value                        The Value of the X-Vault-AWS-IAM-Server-ID header.
  role                                The name of the role you're requesting a token for
  `

	return strings.TrimSpace(help)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/rand"
	"encoding/json"
	"log"
	"os"

	"github.com/cloudfoundry/bosh-bootloader/application"
	"github.com/cloudfoundry/bosh-bootloader/aws"
	"github.com/cloudfoundry/bosh-bootloader/azure"
	"github.com/cloudfoundry/bosh-bootloader/bosh"
	"github.com/cloudfoundry/bosh-bootloader/certs"
	"github.com/cloudfoundry/bosh-bootloader/cloudconfig"
	"github.com/cloudfoundry/bosh-bootloader/commands"
	"github.com/cloudfoundry/bosh-bootloader/config"
	"github.com/cloudfoundry/bosh-bootloader/gcp"
	"github.com/cloudfoundry/bosh-bootloader/helpers"
	"github.com/cloudfoundry/bosh-bootloader/storage"
	"github.com/cloudfoundry/bosh-bootloader/terraform"
	proxy "github.com/cloudfoundry/socks5-proxy"
	"github.com/spf13/afero"

	awscloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/aws"
	azurecloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/azure"
	gcpcloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/gcp"
	vspherecloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/vsphere"
	awsterraform "github.com/cloudfoundry/bosh-bootloader/terraform/aws"
	azureterraform "github.com/cloudfoundry/bosh-bootloader/terraform/azure"
	gcpterraform "github.com/cloudfoundry/bosh-bootloader/terraform/gcp"
	vsphereterraform "github.com/cloudfoundry/bosh-bootloader/terraform/vsphere"
)

var Version = "dev"

func main() {
	logger := application.NewLogger(os.Stdout, os.Stdin)
	stderrLogger := application.NewLogger(os.Stderr, os.Stdin)
	stateBootstrap := storage.NewStateBootstrap(stderrLogger, Version)

	globals, _, err := config.ParseArgs(os.Args)
	log.SetFlags(0)
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}

	// File IO
	fs := afero.NewOsFs()
	afs := &afero.Afero{Fs: fs}

	stateStore := storage.NewStore(globals.StateDir, afs)
	stateMigrator := storage.NewMigrator(stateStore, afs)
	newConfig := config.NewConfig(stateBootstrap, stateMigrator, stderrLogger, afs)

	appConfig, err := newConfig.Bootstrap(os.Args)
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}

	needsIAASCreds := config.NeedsIAASCreds(appConfig.Command) && !appConfig.ShowCommandHelp
	if needsIAASCreds {
		err = config.ValidateIAAS(appConfig.State)
		if err != nil {
			log.Fatalf("\n\n%s\n", err)
		}
	}

	// Utilities
	envIDGenerator := helpers.NewEnvIDGenerator(rand.Reader)
	stateValidator := application.NewStateValidator(appConfig.Global.StateDir)
	certificateValidator := certs.NewValidator()
	lbArgsHandler := commands.NewLBArgsHandler(certificateValidator)

	// Terraform
	terraformOutputBuffer := bytes.NewBuffer([]byte{})
	terraformCmd := terraform.NewCmd(os.Stderr, terraformOutputBuffer)
	terraformExecutor := terraform.NewExecutor(terraformCmd, stateStore, afs, appConfig.Global.Debug)

	var (
		networkClient            helpers.NetworkClient
		networkDeletionValidator commands.NetworkDeletionValidator

		gcpClient                 gcp.Client
		availabilityZoneRetriever aws.AvailabilityZoneRetriever
	)
	if appConfig.State.IAAS == "aws" && needsIAASCreds {
		awsClient := aws.NewClient(appConfig.State.AWS, logger)

		availabilityZoneRetriever = awsClient
		networkDeletionValidator = awsClient
		networkClient = awsClient
	} else if appConfig.State.IAAS == "gcp" && needsIAASCreds {
		gcpClient, err = gcp.NewClient(appConfig.State.GCP, "")
		if err != nil {
			log.Fatalf("\n\n%s\n", err)
		}

		networkDeletionValidator = gcpClient
		networkClient = gcpClient

		gcpZonerHack := config.NewGCPZonerHack(gcpClient)
		stateWithZones, err := gcpZonerHack.SetZones(appConfig.State)
		if err != nil {
			log.Fatalf("\n\n%s\n", err)
		}
		appConfig.State = stateWithZones
	} else if appConfig.State.IAAS == "azure" && needsIAASCreds {
		azureClient, err := azure.NewClient(appConfig.State.Azure)
		if err != nil {
			log.Fatalf("\n\n%s\n", err)
		}

		networkDeletionValidator = azureClient
		networkClient = azureClient
	}

	var (
		inputGenerator    terraform.InputGenerator
		templateGenerator terraform.TemplateGenerator
	)
	switch appConfig.State.IAAS {
	case "aws":
		templateGenerator = awsterraform.NewTemplateGenerator()
		inputGenerator = awsterraform.NewInputGenerator(availabilityZoneRetriever)
	case "azure":
		templateGenerator = azureterraform.NewTemplateGenerator()
		inputGenerator = azureterraform.NewInputGenerator()
	case "gcp":
		templateGenerator = gcpterraform.NewTemplateGenerator()
		inputGenerator = gcpterraform.NewInputGenerator()
	case "vsphere":
		templateGenerator = vsphereterraform.NewTemplateGenerator()
		inputGenerator = vsphereterraform.NewInputGenerator()
	}

	terraformManager := terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

	// BOSH
	hostKeyGetter := proxy.NewHostKeyGetter()
	socks5Proxy := proxy.NewSocks5Proxy(hostKeyGetter)
	boshCommand := bosh.NewCmd(os.Stderr)
	boshExecutor := bosh.NewExecutor(boshCommand, afs, json.Unmarshal, json.Marshal)
	sshKeyGetter := bosh.NewSSHKeyGetter(stateStore, afs)
	allProxyGetter := bosh.NewAllProxyGetter(sshKeyGetter, afs)
	credhubGetter := bosh.NewCredhubGetter(stateStore, afs)
	boshManager := bosh.NewManager(boshExecutor, logger, stateStore, sshKeyGetter, afs)
	boshClientProvider := bosh.NewClientProvider(socks5Proxy, sshKeyGetter)

	var cloudConfigOpsGenerator cloudconfig.OpsGenerator
	switch appConfig.State.IAAS {
	case "aws":
		cloudConfigOpsGenerator = awscloudconfig.NewOpsGenerator(terraformManager, availabilityZoneRetriever)
	case "azure":
		cloudConfigOpsGenerator = azurecloudconfig.NewOpsGenerator(terraformManager)
	case "gcp":
		cloudConfigOpsGenerator = gcpcloudconfig.NewOpsGenerator(terraformManager)
	case "vsphere":
		cloudConfigOpsGenerator = vspherecloudconfig.NewOpsGenerator(terraformManager)
	}
	cloudConfigManager := cloudconfig.NewManager(logger, boshCommand, stateStore, cloudConfigOpsGenerator, boshClientProvider, terraformManager, sshKeyGetter, afs)

	// Subcommands
	var lbsCmd commands.LBsCmd

	switch appConfig.State.IAAS {
	case "aws":
		lbsCmd = commands.NewAWSLBs(terraformManager, logger)
	case "gcp":
		lbsCmd = commands.NewGCPLBs(terraformManager, logger)
	case "azure":
		lbsCmd = commands.NewAzureLBs(terraformManager, logger)
	}

	// Commands
	var envIDManager helpers.EnvIDManager
	if appConfig.State.IAAS != "" {
		envIDManager = helpers.NewEnvIDManager(envIDGenerator, networkClient)
	}
	plan := commands.NewPlan(boshManager, cloudConfigManager, stateStore, envIDManager, terraformManager, lbArgsHandler, stderrLogger, Version)
	up := commands.NewUp(plan, boshManager, cloudConfigManager, stateStore, terraformManager)
	usage := commands.NewUsage(logger)

	commandSet := application.CommandSet{}
	commandSet["help"] = usage
	commandSet["version"] = commands.NewVersion(Version, logger)
	commandSet["up"] = up
	commandSet["plan"] = plan
	sshKeyDeleter := bosh.NewSSHKeyDeleter(stateStore, afs)
	commandSet["rotate"] = commands.NewRotate(stateValidator, sshKeyDeleter, up)
	commandSet["destroy"] = commands.NewDestroy(plan, logger, boshManager, stateStore, stateValidator, terraformManager, networkDeletionValidator)
	commandSet["down"] = commandSet["destroy"]
	commandSet["lbs"] = commands.NewLBs(lbsCmd, stateValidator)
	commandSet["jumpbox-address"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.JumpboxAddressPropertyName)
	commandSet["director-address"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorAddressPropertyName)
	commandSet["director-username"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorUsernamePropertyName)
	commandSet["director-password"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorPasswordPropertyName)
	commandSet["director-ca-cert"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorCACertPropertyName)
	commandSet["ssh-key"] = commands.NewSSHKey(logger, stateValidator, sshKeyGetter)
	commandSet["director-ssh-key"] = commands.NewDirectorSSHKey(logger, stateValidator, sshKeyGetter)
	commandSet["env-id"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.EnvIDPropertyName)
	commandSet["latest-error"] = commands.NewLatestError(logger, stateValidator)
	commandSet["print-env"] = commands.NewPrintEnv(logger, stderrLogger, stateValidator, allProxyGetter, credhubGetter, terraformManager, afs)

	app := application.New(commandSet, appConfig, usage)

	err = app.Run()
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}
}
<commit_msg>Group object creation for needs iaas creds vs doesnt.<commit_after>package main

import (
	"bytes"
	"crypto/rand"
	"encoding/json"
	"log"
	"os"

	"github.com/cloudfoundry/bosh-bootloader/application"
	"github.com/cloudfoundry/bosh-bootloader/aws"
	"github.com/cloudfoundry/bosh-bootloader/azure"
	"github.com/cloudfoundry/bosh-bootloader/bosh"
	"github.com/cloudfoundry/bosh-bootloader/certs"
	"github.com/cloudfoundry/bosh-bootloader/cloudconfig"
	"github.com/cloudfoundry/bosh-bootloader/commands"
	"github.com/cloudfoundry/bosh-bootloader/config"
	"github.com/cloudfoundry/bosh-bootloader/gcp"
	"github.com/cloudfoundry/bosh-bootloader/helpers"
	"github.com/cloudfoundry/bosh-bootloader/storage"
	"github.com/cloudfoundry/bosh-bootloader/terraform"
	proxy "github.com/cloudfoundry/socks5-proxy"
	"github.com/spf13/afero"

	awscloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/aws"
	azurecloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/azure"
	gcpcloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/gcp"
	vspherecloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/vsphere"
	awsterraform "github.com/cloudfoundry/bosh-bootloader/terraform/aws"
	azureterraform "github.com/cloudfoundry/bosh-bootloader/terraform/azure"
	gcpterraform "github.com/cloudfoundry/bosh-bootloader/terraform/gcp"
	vsphereterraform "github.com/cloudfoundry/bosh-bootloader/terraform/vsphere"
)

var Version = "dev"

func main() {
	logger := application.NewLogger(os.Stdout, os.Stdin)
	stderrLogger := application.NewLogger(os.Stderr, os.Stdin)
	stateBootstrap := storage.NewStateBootstrap(stderrLogger, Version)

	globals, _, err := config.ParseArgs(os.Args)
	log.SetFlags(0)
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}

	// File IO
	fs := afero.NewOsFs()
	afs := &afero.Afero{Fs: fs}

	//App Configuration
	stateStore := storage.NewStore(globals.StateDir, afs)
	stateMigrator := storage.NewMigrator(stateStore, afs)
	newConfig := config.NewConfig(stateBootstrap, stateMigrator, stderrLogger, afs)

	appConfig, err := newConfig.Bootstrap(os.Args)
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}

	needsIAASCreds := config.NeedsIAASCreds(appConfig.Command) && !appConfig.ShowCommandHelp
	if needsIAASCreds {
		err = config.ValidateIAAS(appConfig.State)
		if err != nil {
			log.Fatalf("\n\n%s\n", err)
		}
	}

	// Utilities
	envIDGenerator := helpers.NewEnvIDGenerator(rand.Reader)
	stateValidator := application.NewStateValidator(appConfig.Global.StateDir)
	certificateValidator := certs.NewValidator()
	lbArgsHandler := commands.NewLBArgsHandler(certificateValidator)

	// Terraform
	terraformOutputBuffer := bytes.NewBuffer([]byte{})
	terraformCmd := terraform.NewCmd(os.Stderr, terraformOutputBuffer)
	terraformExecutor := terraform.NewExecutor(terraformCmd, stateStore, afs, appConfig.Global.Debug)

	// BOSH
	hostKeyGetter := proxy.NewHostKeyGetter()
	socks5Proxy := proxy.NewSocks5Proxy(hostKeyGetter)
	boshCommand := bosh.NewCmd(os.Stderr)
	boshExecutor := bosh.NewExecutor(boshCommand, afs, json.Unmarshal, json.Marshal)
	sshKeyGetter := bosh.NewSSHKeyGetter(stateStore, afs)
	allProxyGetter := bosh.NewAllProxyGetter(sshKeyGetter, afs)
	credhubGetter := bosh.NewCredhubGetter(stateStore, afs)
	boshManager := bosh.NewManager(boshExecutor, logger, stateStore, sshKeyGetter, afs)
	boshClientProvider := bosh.NewClientProvider(socks5Proxy, sshKeyGetter)

	//Clients that require IAAS credentials.
	var (
		networkClient            helpers.NetworkClient
		networkDeletionValidator commands.NetworkDeletionValidator

		gcpClient                 gcp.Client
		availabilityZoneRetriever aws.AvailabilityZoneRetriever
	)
	if needsIAASCreds {
		switch appConfig.State.IAAS {
		case "aws":
			awsClient := aws.NewClient(appConfig.State.AWS, logger)

			availabilityZoneRetriever = awsClient
			networkDeletionValidator = awsClient
			networkClient = awsClient
		case "gcp":
			gcpClient, err = gcp.NewClient(appConfig.State.GCP, "")
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}

			networkDeletionValidator = gcpClient
			networkClient = gcpClient

			gcpZonerHack := config.NewGCPZonerHack(gcpClient)
			stateWithZones, err := gcpZonerHack.SetZones(appConfig.State)
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}
			appConfig.State = stateWithZones
		case "azure":
			azureClient, err := azure.NewClient(appConfig.State.Azure)
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}

			networkDeletionValidator = azureClient
			networkClient = azureClient
		}
	}

	var (
		inputGenerator    terraform.InputGenerator
		templateGenerator terraform.TemplateGenerator

		terraformManager        terraform.Manager
		cloudConfigOpsGenerator cloudconfig.OpsGenerator

		lbsCmd commands.LBsCmd
	)
	switch appConfig.State.IAAS {
	case "aws":
		templateGenerator = awsterraform.NewTemplateGenerator()
		inputGenerator = awsterraform.NewInputGenerator(availabilityZoneRetriever)

		terraformManager = terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

		cloudConfigOpsGenerator = awscloudconfig.NewOpsGenerator(terraformManager, availabilityZoneRetriever)

		lbsCmd = commands.NewAWSLBs(terraformManager, logger)
	case "azure":
		templateGenerator = azureterraform.NewTemplateGenerator()
		inputGenerator = azureterraform.NewInputGenerator()

		terraformManager = terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

		cloudConfigOpsGenerator = azurecloudconfig.NewOpsGenerator(terraformManager)

		lbsCmd = commands.NewAzureLBs(terraformManager, logger)
	case "gcp":
		templateGenerator = gcpterraform.NewTemplateGenerator()
		inputGenerator = gcpterraform.NewInputGenerator()

		terraformManager = terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

		cloudConfigOpsGenerator = gcpcloudconfig.NewOpsGenerator(terraformManager)

		lbsCmd = commands.NewGCPLBs(terraformManager, logger)
	case "vsphere":
		templateGenerator = vsphereterraform.NewTemplateGenerator()
		inputGenerator = vsphereterraform.NewInputGenerator()

		terraformManager = terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

		cloudConfigOpsGenerator = vspherecloudconfig.NewOpsGenerator(terraformManager)
	}

	cloudConfigManager := cloudconfig.NewManager(logger, boshCommand, stateStore, cloudConfigOpsGenerator, boshClientProvider, terraformManager, sshKeyGetter, afs)

	// Commands
	var envIDManager helpers.EnvIDManager
	if appConfig.State.IAAS != "" {
		envIDManager = helpers.NewEnvIDManager(envIDGenerator, networkClient)
	}
	plan := commands.NewPlan(boshManager, cloudConfigManager, stateStore, envIDManager, terraformManager, lbArgsHandler, stderrLogger, Version)
	up := commands.NewUp(plan, boshManager, cloudConfigManager, stateStore, terraformManager)
	usage := commands.NewUsage(logger)

	commandSet := application.CommandSet{}
	commandSet["help"] = usage
	commandSet["version"] = commands.NewVersion(Version, logger)
	commandSet["up"] = up
	commandSet["plan"] = plan
	sshKeyDeleter := bosh.NewSSHKeyDeleter(stateStore, afs)
	commandSet["rotate"] = commands.NewRotate(stateValidator, sshKeyDeleter, up)
	commandSet["destroy"] = commands.NewDestroy(plan, logger, boshManager, stateStore, stateValidator, terraformManager, networkDeletionValidator)
	commandSet["down"] = commandSet["destroy"]
	commandSet["lbs"] = commands.NewLBs(lbsCmd, stateValidator)
	commandSet["jumpbox-address"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.JumpboxAddressPropertyName)
	commandSet["director-address"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorAddressPropertyName)
	commandSet["director-username"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorUsernamePropertyName)
	commandSet["director-password"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorPasswordPropertyName)
	commandSet["director-ca-cert"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorCACertPropertyName)
	commandSet["ssh-key"] = commands.NewSSHKey(logger, stateValidator, sshKeyGetter)
	commandSet["director-ssh-key"] = commands.NewDirectorSSHKey(logger, stateValidator, sshKeyGetter)
	commandSet["env-id"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.EnvIDPropertyName)
	commandSet["latest-error"] = commands.NewLatestError(logger, stateValidator)
	commandSet["print-env"] = commands.NewPrintEnv(logger, stderrLogger, stateValidator, allProxyGetter, credhubGetter, terraformManager, afs)

	app := application.New(commandSet, appConfig, usage)

	err = app.Run()
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}
}
<|endoftext|>


<commit_before>package bytebuffer

import "testing"

func TestWriteInt32(t *testing.T) {
	cases := []int32{0, 10, 100, 200, 1000, 10000, 10000000, 1000000000, 2147483647}

	for _, val := range cases {
		b := NewByteBuffer(4)

		err := b.WriteInt32(val)
		if err != nil {
			t.Error(err)
			return
		}

		if b.Pos() != 4 {
			t.Error("Not Writing 4 bytes for int32")
			return
		}

		e := []byte{
			byte(val & 0xFF),
			byte((val >> 8) & 0xFF),
			byte((val >> 16) & 0xFF),
			byte(val >> 24),
		}

		for i := 0; i < 4; i++ {
			if b.buffer[i] != e[i] {
				t.Errorf("pos: %v, expected: %v, got %v", i, e[i], b.buffer[i])
			}
		}
	}
}

func TestWriteInt64(t *testing.T) {
	cases := []int64{0, 10, 100, 200, 1000, 10000, 10000000, 1000000000, 2147483647,
		4294967295, 10000000000000, 100000000000000000, 9223372036854775807}

	for _, val := range cases {
		b := NewByteBuffer(8)

		err := b.WriteInt64(val)
		if err != nil {
			t.Error(err)
			return
		}

		if b.Pos() != 8 {
			t.Error("Not Writing 8 bytes for int32")
			return
		}

		e := []byte{
			byte(val & 0xFF),
			byte((val >> 8) & 0xFF),
			byte((val >> 16) & 0xFF),
			byte((val >> 24) & 0xFF),
			byte((val >> 32) & 0xFF),
			byte((val >> 40) & 0xFF),
			byte((val >> 48) & 0xFF),
			byte(val >> 56),
		}

		for i := 0; i < 8; i++ {
			if b.buffer[i] != e[i] {
				t.Errorf("pos: %v, expected: %v, got %v", i, e[i], b.buffer[i])
			}
		}
	}
}

func TestWriteString(t *testing.T) {
	cases := []string{"MMV", "Suyash", "This is a little long string"}
	for _, val := range cases {
		b := NewByteBuffer(len(val))

		err := b.WriteString(val)
		if err != nil {
			t.Error(err)
			return
		}

		if b.Pos() != len(val) {
			t.Errorf("Expected to write %v bytes, writing %v bytes", len(val), b.Pos())
			return
		}

		e := []byte(val)
		for i := 0; i < len(val); i++ {
			if b.buffer[i] != e[i] {
				t.Errorf("pos: %v, expected: %v, got %v", i, e[i], b.buffer[i])
			}
		}
	}
}
<commit_msg>bytebuffer: add test for SetPos<commit_after>package bytebuffer

import "testing"

func TestWriteInt32(t *testing.T) {
	cases := []int32{0, 10, 100, 200, 1000, 10000, 10000000, 1000000000, 2147483647}

	for _, val := range cases {
		b := NewByteBuffer(4)

		err := b.WriteInt32(val)
		if err != nil {
			t.Error(err)
			return
		}

		if b.Pos() != 4 {
			t.Error("Not Writing 4 bytes for int32")
			return
		}

		e := []byte{
			byte(val & 0xFF),
			byte((val >> 8) & 0xFF),
			byte((val >> 16) & 0xFF),
			byte(val >> 24),
		}

		for i := 0; i < 4; i++ {
			if b.buffer[i] != e[i] {
				t.Errorf("pos: %v, expected: %v, got %v", i, e[i], b.buffer[i])
			}
		}
	}
}

func TestWriteInt64(t *testing.T) {
	cases := []int64{0, 10, 100, 200, 1000, 10000, 10000000, 1000000000, 2147483647,
		4294967295, 10000000000000, 100000000000000000, 9223372036854775807}

	for _, val := range cases {
		b := NewByteBuffer(8)

		err := b.WriteInt64(val)
		if err != nil {
			t.Error(err)
			return
		}

		if b.Pos() != 8 {
			t.Error("Not Writing 8 bytes for int32")
			return
		}

		e := []byte{
			byte(val & 0xFF),
			byte((val >> 8) & 0xFF),
			byte((val >> 16) & 0xFF),
			byte((val >> 24) & 0xFF),
			byte((val >> 32) & 0xFF),
			byte((val >> 40) & 0xFF),
			byte((val >> 48) & 0xFF),
			byte(val >> 56),
		}

		for i := 0; i < 8; i++ {
			if b.buffer[i] != e[i] {
				t.Errorf("pos: %v, expected: %v, got %v", i, e[i], b.buffer[i])
			}
		}
	}
}

func TestWriteString(t *testing.T) {
	cases := []string{"MMV", "Suyash", "This is a little long string"}
	for _, val := range cases {
		b := NewByteBuffer(len(val))

		err := b.WriteString(val)
		if err != nil {
			t.Error(err)
			return
		}

		if b.Pos() != len(val) {
			t.Errorf("Expected to write %v bytes, writing %v bytes", len(val), b.Pos())
			return
		}

		e := []byte(val)
		for i := 0; i < len(val); i++ {
			if b.buffer[i] != e[i] {
				t.Errorf("pos: %v, expected: %v, got %v", i, e[i], b.buffer[i])
			}
		}
	}
}

func TestSetPos(t *testing.T) {
	b := NewByteBuffer(4)
	err := b.SetPos(4)
	if err == nil {
		t.Error("Expected error at setting a bytebuffer to a position outside its range")
	}

	b.SetPos(2)
	b.WriteString("a")

	if b.Pos() != 3 {
		t.Error("Position not changing as expected")
		return
	}

	if b.Bytes()[2] != 'a' {
		t.Error("Value was not written at the expected position")
		return
	}

	b.SetPos(2)
	err = b.WriteInt32(10)

	if err == nil {
		t.Error("Expected error in writing a value guaranteed to overflow")
		return
	}

	if b.Pos() != 2 {
		t.Error("Position changing despite a write failure")
		return
	}
}
<|endoftext|>


<commit_before>package bcsgo

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

var ak = "zaTGAk9k6qoRaVoVcTCRGbjZ"
var sk = "r7ay1xOM12s4afPUqRZ9f53su8OF6lwj"
var bcs = NewBCS(ak, sk)

var sessionBucketName = randomGlobalBucketName(0)

func randomGlobalBucketName(index int) string {
	return ak[:2] + "-sdk-" + strconv.FormatInt(time.Now().Unix(), 10)[5:] + "-" + strconv.Itoa(index)
}

func init() {
	// DEBUG = true
}

// test function must starts with "Test"
func TestSign(t *testing.T) {
	// url := bcs.Sign("GET", "", "/", "", "", "")
	// url_ex := "http://bcs.duapp.com//?sign=MBO:vYlphQiwbhVz67jjW48ddY3C:yf27Oy6JVtK6nxRtIASKX6H%2BR4I%3D"
	// if url != url_ex {
	// 	t.Fail()
	// }
}

func TestSimpleCreateBucket(t *testing.T) {
	newBucket := bcs.Bucket(sessionBucketName)
	err := newBucket.Create()
	if err != nil {
		fmt.Println(err)
		t.Fail()
	}
}

func TestNewAndDeleteBucketAndACL(t *testing.T) {
	bucketName := randomGlobalBucketName(1)
	newBucket := bcs.Bucket(bucketName)
	bucketErr := newBucket.CreateWithACL(ACL_PUBLIC_READ)
	if bucketErr != nil {
		fmt.Println(bucketErr)
		t.Fail()
	}

	// bucketACL, bucketACLErr := newBucket.GetACL()
	// expectedBucketACL := fmt.Sprintf(`{"statements":[{"action":["*"],"effect":"allow","resource":["testsml2\/"],"user":["psp:egg90"]},{"action":["get_object"],"effect":"allow","resource":["%s\/"],"user":["*"]}]}`, bucketName)
	// if bucketACLErr != nil {
	// 	fmt.Println(bucketACLErr)
	// 	t.Fail()
	// }
	// if bucketACL != expectedBucketACL {
	// 	fmt.Println(bucketACL)
	// 	fmt.Println(expectedBucketACL)
	// 	t.Fail()
	// }

	bucketErr = newBucket.Delete()
	if bucketErr != nil {
		fmt.Println(bucketErr)
		t.Fail()
	}
}

func TestNewBucketWithInvalidName(t *testing.T) {
	newBucket := bcs.Bucket("testErrorBucket")
	bucketErr := newBucket.Create()
	// It shall be failed.
	if bucketErr == nil {
		t.Fail()
	}
}

func TestListBuckets(t *testing.T) {
	buckets, e := bcs.ListBuckets()
	if e != nil {
		t.Fail()
	}
	if buckets == nil {
		t.Fail()
	}
}

func TestListObjects(t *testing.T) {
	// todo prefix
	bucket := bcs.Bucket(sessionBucketName)
	objects, e := bucket.ListObjects("", 0, 5)
	if e != nil {
		t.Fail()
	}
	for _, pObject := range objects.Objects {
		if pObject == nil {
			t.Fail()
		}
	}
}

func TestBucketACL(t *testing.T) {
	bucket := bcs.Bucket(sessionBucketName)
	acl, aclErr := bucket.GetACL()
	if aclErr != nil || acl == "" {
		t.Fail()
	}
	putErr := bucket.SetACL(ACL_PUBLIC_READ)
	if putErr != nil {
		t.Fail()
	}
}

func TestPutAndDeleteObject(t *testing.T) {
	bucket := bcs.Bucket(sessionBucketName)
	path := "/testDir/test.txt"
	testObj := bucket.Object(path)
	testObj, err := testObj.PutFile("test.txt", ACL_PUBLIC_READ)
	if (err != nil) || testObj.AbsolutePath != path {
		t.Fail()
	}

	deleteErr := testObj.Delete()
	if deleteErr != nil {
		t.Fail()
	}
}

func TestFinallyDeleteSessionBucket(t *testing.T) {
	bucket := bcs.Bucket(sessionBucketName)
	err := bucket.Delete()
	if err != nil {
		t.Fail()
	}
}
<commit_msg>test can print error: t.Error<commit_after>package bcsgo

import (
	// "fmt"
	"strconv"
	"testing"
	"time"
)

var ak = "zaTGAk9k6qoRaVoVcTCRGbjZ"
var sk = "r7ay1xOM12s4afPUqRZ9f53su8OF6lwj"
var bcs = NewBCS(ak, sk)

var sessionBucketName = randomGlobalBucketName(0)

func randomGlobalBucketName(index int) string {
	return ak[:2] + "-sdk-" + strconv.FormatInt(time.Now().Unix(), 10)[5:] + "-" + strconv.Itoa(index)
}

func init() {
	// DEBUG = true
}

// test function must starts with "Test"
func TestSign(t *testing.T) {
	// url := bcs.Sign("GET", "", "/", "", "", "")
	// url_ex := "http://bcs.duapp.com//?sign=MBO:vYlphQiwbhVz67jjW48ddY3C:yf27Oy6JVtK6nxRtIASKX6H%2BR4I%3D"
	// if url != url_ex {
	// 	t.Fail()
	// }
}

func TestSimpleCreateBucket(t *testing.T) {
	newBucket := bcs.Bucket(sessionBucketName)
	err := newBucket.Create()
	if err != nil {
		t.Error(err)
	}
}

func TestNewAndDeleteBucketAndACL(t *testing.T) {
	bucketName := randomGlobalBucketName(1)
	newBucket := bcs.Bucket(bucketName)
	bucketErr := newBucket.CreateWithACL(ACL_PUBLIC_READ)
	if bucketErr != nil {
		t.Error(bucketErr)
	}

	// bucketACL, bucketACLErr := newBucket.GetACL()
	// expectedBucketACL := fmt.Sprintf(`{"statements":[{"action":["*"],"effect":"allow","resource":["testsml2\/"],"user":["psp:egg90"]},{"action":["get_object"],"effect":"allow","resource":["%s\/"],"user":["*"]}]}`, bucketName)
	// if bucketACLErr != nil {
	// 	fmt.Println(bucketACLErr)
	// 	t.Fail()
	// }
	// if bucketACL != expectedBucketACL {
	// 	fmt.Println(bucketACL)
	// 	fmt.Println(expectedBucketACL)
	// 	t.Fail()
	// }

	bucketErr = newBucket.Delete()
	if bucketErr != nil {
		t.Error(bucketErr)
	}
}

func TestNewBucketWithInvalidName(t *testing.T) {
	newBucket := bcs.Bucket("testErrorBucket")
	bucketErr := newBucket.Create()
	// It shall be failed.
	if bucketErr == nil {
		t.Error("create bucket with invaid name should failed")
	}
}

func TestListBuckets(t *testing.T) {
	buckets, e := bcs.ListBuckets()
	if e != nil {
		t.Error(e)
	}
	if buckets == nil {
		t.Error("buckets list is nil")
	}
}

func TestListObjects(t *testing.T) {
	// todo prefix
	bucket := bcs.Bucket(sessionBucketName)
	objects, e := bucket.ListObjects("", 0, 5)
	if e != nil {
		t.Error("object list shouldn't be nil")
	}
	for _, pObject := range objects.Objects {
		if pObject == nil {
			t.Error("object should not be nil")
		}
	}
}

func TestBucketACL(t *testing.T) {
	bucket := bcs.Bucket(sessionBucketName)
	acl, aclErr := bucket.GetACL()
	if aclErr != nil {
		t.Error(aclErr)
	}
	if acl == "" {
		t.Error("acl string shouldn't be nil")
	}
	putErr := bucket.SetACL(ACL_PUBLIC_READ)
	if putErr != nil {
		t.Error(putErr)
	}
}

func TestPutAndDeleteObject(t *testing.T) {
	bucket := bcs.Bucket(sessionBucketName)
	path := "/testDir/test.txt"
	testObj := bucket.Object(path)
	testObj, err := testObj.PutFile("test.txt", ACL_PUBLIC_READ)
	if err != nil {
		t.Error(err)
	}
	if testObj.AbsolutePath != path {
		t.Error("testObj.AbsolutePath != path", testObj.AbsolutePath, path)
	}

	deleteErr := testObj.Delete()
	if deleteErr != nil {
		t.Error(deleteErr)
	}
}

func TestFinallyDeleteSessionBucket(t *testing.T) {
	bucket := bcs.Bucket(sessionBucketName)
	err := bucket.Delete()
	if err != nil {
		t.Error(err)
	}
}
<|endoftext|>


<commit_before>package categories

import (
	"errors"
	"testing"

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

type repositoryMock struct {
	mock.Mock
}

func (m *repositoryMock) Save(c *Category) error {
	args := m.Called(c)
	return args.Error(0)
}

func TestNewCategory(t *testing.T) {
	if !testing.Short() {
		t.Skip()
	}

	m := new(repositoryMock)
	i := new(Interactor)
	i.Repository = m
	categoryName := "testCategory"

	name := "Fails to create a new category due to repository failure"
	m.On("Save", &Category{name: categoryName}).Return(errors.New("Failed to create category due to repository failure"))
	c, err := i.NewCategory(categoryName)
	m.AssertExpectations(t)
	assert.Error(t, err)
	assert.Equal(t, c, &Category{}, name)

	name = "Fails to create category if repository is not defined"
	i = new(Interactor)
	_, err = i.NewCategory(categoryName)
	assert.Error(t, err)

	name = "Fails to create category is name is empty"
	i = new(Interactor)
	c, err = i.NewCategory("")
	assert.EqualError(t, err, "Cannot create category whitout a category name")
	assert.Equal(t, c, &Category{}, name)

	name = "Creates category with specified name"
	i = new(Interactor)
	m = new(repositoryMock)
	i.Repository = m
	m.On("Save", &Category{name: categoryName}).Return(nil)
	c, err = i.NewCategory(categoryName)
	m.AssertExpectations(t)
	assert.NoError(t, err)
	assert.Equal(t, categoryName, c.name, name)

}
<commit_msg>Adds TODO<commit_after>package categories

import (
	"errors"
	"testing"

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

type repositoryMock struct {
	mock.Mock
}

func (m *repositoryMock) Save(c *Category) error {
	args := m.Called(c)
	return args.Error(0)
}

func TestNewCategory(t *testing.T) {
	// TODO: Refactor to table tests
	if !testing.Short() {
		t.Skip()
	}

	m := new(repositoryMock)
	i := new(Interactor)
	i.Repository = m
	categoryName := "testCategory"

	name := "Fails to create a new category due to repository failure"
	m.On("Save", &Category{name: categoryName}).Return(errors.New("Failed to create category due to repository failure"))
	c, err := i.NewCategory(categoryName)
	m.AssertExpectations(t)
	assert.Error(t, err)
	assert.Equal(t, c, &Category{}, name)

	name = "Fails to create category if repository is not defined"
	i = new(Interactor)
	_, err = i.NewCategory(categoryName)
	assert.Error(t, err)

	name = "Fails to create category is name is empty"
	i = new(Interactor)
	c, err = i.NewCategory("")
	assert.EqualError(t, err, "Cannot create category whitout a category name")
	assert.Equal(t, c, &Category{}, name)

	name = "Creates category with specified name"
	i = new(Interactor)
	m = new(repositoryMock)
	i.Repository = m
	m.On("Save", &Category{name: categoryName}).Return(nil)
	c, err = i.NewCategory(categoryName)
	m.AssertExpectations(t)
	assert.NoError(t, err)
	assert.Equal(t, categoryName, c.name, name)

}
<|endoftext|>


<commit_before>package sarama

import (
	"fmt"
	"strings"
)

type (
	AclOperation int

	AclPermissionType int

	AclResourceType int

	AclResourcePatternType int
)

// ref: https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/acl/AclOperation.java
const (
	AclOperationUnknown AclOperation = iota
	AclOperationAny
	AclOperationAll
	AclOperationRead
	AclOperationWrite
	AclOperationCreate
	AclOperationDelete
	AclOperationAlter
	AclOperationDescribe
	AclOperationClusterAction
	AclOperationDescribeConfigs
	AclOperationAlterConfigs
	AclOperationIdempotentWrite
)

func (a *AclOperation) String() string {
	mapping := map[AclOperation]string{
		AclOperationUnknown:         "Unknown",
		AclOperationAny:             "Any",
		AclOperationAll:             "All",
		AclOperationRead:            "Read",
		AclOperationWrite:           "Write",
		AclOperationCreate:          "Create",
		AclOperationDelete:          "Delete",
		AclOperationAlter:           "Alter",
		AclOperationDescribe:        "Describe",
		AclOperationClusterAction:   "ClusterAction",
		AclOperationDescribeConfigs: "DescribeConfigs",
		AclOperationAlterConfigs:    "AlterConfigs",
		AclOperationIdempotentWrite: "IdempotentWrite",
	}
	s, ok := mapping[a]
	if !ok {
		s = mapping[AclOperationUnknown]
	}
	return s
}

//MarshalText returns the text form of the AclOperation (name without prefix)
func (a *AclOperation) MarshalText() ([]byte, error) {
	return []byte(a.String()), nil
}

//UnmarshalText takes a text reprentation of the operation and converts it to an AclOperation
func (a *AclOperation) UnmarshalText(text []byte) error {
	normalized := strings.ToLower(string(text))
	mapping := map[string]AclOperation{
		"unknown":         AclOperationUnknown,
		"any":             AclOperationAny,
		"all":             AclOperationAll,
		"read":            AclOperationRead,
		"write":           AclOperationWrite,
		"create":          AclOperationCreate,
		"delete":          AclOperationDelete,
		"alter":           AclOperationAlter,
		"describe":        AclOperationDescribe,
		"clusteraction":   AclOperationClusterAction,
		"describeconfigs": AclOperationDescribeConfigs,
		"alterconfigs":    AclOperationAlterConfigs,
		"idempotentwrite": AclOperationIdempotentWrite,
	}
	ao, ok := mapping[normalized]
	if !ok {
		*a = AclOperationUnknown
		return fmt.Errorf("no acl operation with name %s", normalized)
	}
	*a = ao
	return nil
}

// ref: https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/acl/AclPermissionType.java
const (
	AclPermissionUnknown AclPermissionType = iota
	AclPermissionAny
	AclPermissionDeny
	AclPermissionAllow
)

func (a *AclPermissionType) String() string {
	mapping := map[AclPermissionType]string{
		AclPermissionUnknown: "Unknown",
		AclPermissionAny:     "Any",
		AclPermissionDeny:    "Deny",
		AclPermissionAllow:   "Allow",
	}
	s, ok := mapping[a]
	if !ok {
		s = mapping[AclPermissionUnknown]
	}
	return s
}

//MarshalText returns the text form of the AclPermissionType (name without prefix)
func (a *AclPermissionType) MarshalText() ([]byte, error) {
	return []byte(a.String()), nil
}

//UnmarshalText takes a text reprentation of the permission type and converts it to an AclPermissionType
func (a *AclPermissionType) UnmarshalText(text []byte) error {
	normalized := strings.ToLower(string(text))
	mapping := map[string]AclPermissionType{
		"unknown": AclPermissionUnknown,
		"any":     AclPermissionAny,
		"deny":    AclPermissionDeny,
		"allow":   AclPermissionAllow,
	}

	apt, ok := mapping[normalized]
	if !ok {
		*a = AclPermissionUnknown
		return fmt.Errorf("no acl permission with name %s", normalized)
	}
	*a = apt
	return nil
}

// ref: https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/resource/ResourceType.java
const (
	AclResourceUnknown AclResourceType = iota
	AclResourceAny
	AclResourceTopic
	AclResourceGroup
	AclResourceCluster
	AclResourceTransactionalID
)

func (a *AclResourceType) String() string {
	mapping := map[AclResourceType]string{
		AclResourceUnknown:         "Unknown",
		AclResourceAny:             "Any",
		AclResourceTopic:           "Topic",
		AclResourceGroup:           "Group",
		AclResourceCluster:         "Cluster",
		AclResourceTransactionalID: "TransactionalID",
	}
	s, ok := mapping[a]
	if !ok {
		s = mapping[AclResourceUnknown]
	}
	return s
}

//MarshalText returns the text form of the AclResourceType (name without prefix)
func (a *AclResourceType) MarshalText() ([]byte, error) {
	return []byte(a.String()), nil
}

//UnmarshalText takes a text reprentation of the resource type and converts it to an AclResourceType
func (a *AclResourceType) UnmarshalText(text []byte) error {
	normalized := strings.ToLower(string(text))
	mapping := map[string]AclResourceType{
		"unknown":         AclResourceUnknown,
		"any":             AclResourceAny,
		"topic":           AclResourceTopic,
		"group":           AclResourceGroup,
		"cluster":         AclResourceCluster,
		"transactionalid": AclResourceTransactionalID,
	}

	art, ok := mapping[normalized]
	if !ok {
		*a = AclResourceUnknown
		return fmt.Errorf("no acl resource with name %s", normalized)
	}
	*a = art
	return nil
}

// ref: https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/resource/PatternType.java
const (
	AclPatternUnknown AclResourcePatternType = iota
	AclPatternAny
	AclPatternMatch
	AclPatternLiteral
	AclPatternPrefixed
)

func (a *AclResourcePatternType) String() string {
	mapping := map[AclResourcePatternType]string{
		AclPatternUnknown:  "Unknown",
		AclPatternAny:      "Any",
		AclPatternMatch:    "Match",
		AclPatternLiteral:  "Literal",
		AclPatternPrefixed: "Prefixed",
	}
	s, ok := mapping[a]
	if !ok {
		s = mapping[AclPatternUnknown]
	}
	return s
}

//MarshalText returns the text form of the AclResourcePatternType (name without prefix)
func (a *AclResourcePatternType) MarshalText() ([]byte, error) {
	return []byte(a.String()), nil
}

//UnmarshalText takes a text reprentation of the resource pattern type and converts it to an AclResourcePatternType
func (a *AclResourcePatternType) UnmarshalText(text []byte) error {
	normalized := strings.ToLower(string(text))
	mapping := map[string]AclResourcePatternType{
		"unknown":  AclPatternUnknown,
		"any":      AclPatternAny,
		"match":    AclPatternMatch,
		"literal":  AclPatternLiteral,
		"prefixed": AclPatternPrefixed,
	}

	arpt, ok := mapping[normalized]
	if !ok {
		*a = AclPatternUnknown
		return fmt.Errorf("no acl resource pattern with name %s", normalized)
	}
	*a = arpt
	return nil
}
<commit_msg>dereference pointer for map lookup<commit_after>package sarama

import (
	"fmt"
	"strings"
)

type (
	AclOperation int

	AclPermissionType int

	AclResourceType int

	AclResourcePatternType int
)

// ref: https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/acl/AclOperation.java
const (
	AclOperationUnknown AclOperation = iota
	AclOperationAny
	AclOperationAll
	AclOperationRead
	AclOperationWrite
	AclOperationCreate
	AclOperationDelete
	AclOperationAlter
	AclOperationDescribe
	AclOperationClusterAction
	AclOperationDescribeConfigs
	AclOperationAlterConfigs
	AclOperationIdempotentWrite
)

func (a *AclOperation) String() string {
	mapping := map[AclOperation]string{
		AclOperationUnknown:         "Unknown",
		AclOperationAny:             "Any",
		AclOperationAll:             "All",
		AclOperationRead:            "Read",
		AclOperationWrite:           "Write",
		AclOperationCreate:          "Create",
		AclOperationDelete:          "Delete",
		AclOperationAlter:           "Alter",
		AclOperationDescribe:        "Describe",
		AclOperationClusterAction:   "ClusterAction",
		AclOperationDescribeConfigs: "DescribeConfigs",
		AclOperationAlterConfigs:    "AlterConfigs",
		AclOperationIdempotentWrite: "IdempotentWrite",
	}
	s, ok := mapping[*a]
	if !ok {
		s = mapping[AclOperationUnknown]
	}
	return s
}

//MarshalText returns the text form of the AclOperation (name without prefix)
func (a *AclOperation) MarshalText() ([]byte, error) {
	return []byte(a.String()), nil
}

//UnmarshalText takes a text reprentation of the operation and converts it to an AclOperation
func (a *AclOperation) UnmarshalText(text []byte) error {
	normalized := strings.ToLower(string(text))
	mapping := map[string]AclOperation{
		"unknown":         AclOperationUnknown,
		"any":             AclOperationAny,
		"all":             AclOperationAll,
		"read":            AclOperationRead,
		"write":           AclOperationWrite,
		"create":          AclOperationCreate,
		"delete":          AclOperationDelete,
		"alter":           AclOperationAlter,
		"describe":        AclOperationDescribe,
		"clusteraction":   AclOperationClusterAction,
		"describeconfigs": AclOperationDescribeConfigs,
		"alterconfigs":    AclOperationAlterConfigs,
		"idempotentwrite": AclOperationIdempotentWrite,
	}
	ao, ok := mapping[normalized]
	if !ok {
		*a = AclOperationUnknown
		return fmt.Errorf("no acl operation with name %s", normalized)
	}
	*a = ao
	return nil
}

// ref: https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/acl/AclPermissionType.java
const (
	AclPermissionUnknown AclPermissionType = iota
	AclPermissionAny
	AclPermissionDeny
	AclPermissionAllow
)

func (a *AclPermissionType) String() string {
	mapping := map[AclPermissionType]string{
		AclPermissionUnknown: "Unknown",
		AclPermissionAny:     "Any",
		AclPermissionDeny:    "Deny",
		AclPermissionAllow:   "Allow",
	}
	s, ok := mapping[*a]
	if !ok {
		s = mapping[AclPermissionUnknown]
	}
	return s
}

//MarshalText returns the text form of the AclPermissionType (name without prefix)
func (a *AclPermissionType) MarshalText() ([]byte, error) {
	return []byte(a.String()), nil
}

//UnmarshalText takes a text reprentation of the permission type and converts it to an AclPermissionType
func (a *AclPermissionType) UnmarshalText(text []byte) error {
	normalized := strings.ToLower(string(text))
	mapping := map[string]AclPermissionType{
		"unknown": AclPermissionUnknown,
		"any":     AclPermissionAny,
		"deny":    AclPermissionDeny,
		"allow":   AclPermissionAllow,
	}

	apt, ok := mapping[normalized]
	if !ok {
		*a = AclPermissionUnknown
		return fmt.Errorf("no acl permission with name %s", normalized)
	}
	*a = apt
	return nil
}

// ref: https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/resource/ResourceType.java
const (
	AclResourceUnknown AclResourceType = iota
	AclResourceAny
	AclResourceTopic
	AclResourceGroup
	AclResourceCluster
	AclResourceTransactionalID
)

func (a *AclResourceType) String() string {
	mapping := map[AclResourceType]string{
		AclResourceUnknown:         "Unknown",
		AclResourceAny:             "Any",
		AclResourceTopic:           "Topic",
		AclResourceGroup:           "Group",
		AclResourceCluster:         "Cluster",
		AclResourceTransactionalID: "TransactionalID",
	}
	s, ok := mapping[*a]
	if !ok {
		s = mapping[AclResourceUnknown]
	}
	return s
}

//MarshalText returns the text form of the AclResourceType (name without prefix)
func (a *AclResourceType) MarshalText() ([]byte, error) {
	return []byte(a.String()), nil
}

//UnmarshalText takes a text reprentation of the resource type and converts it to an AclResourceType
func (a *AclResourceType) UnmarshalText(text []byte) error {
	normalized := strings.ToLower(string(text))
	mapping := map[string]AclResourceType{
		"unknown":         AclResourceUnknown,
		"any":             AclResourceAny,
		"topic":           AclResourceTopic,
		"group":           AclResourceGroup,
		"cluster":         AclResourceCluster,
		"transactionalid": AclResourceTransactionalID,
	}

	art, ok := mapping[normalized]
	if !ok {
		*a = AclResourceUnknown
		return fmt.Errorf("no acl resource with name %s", normalized)
	}
	*a = art
	return nil
}

// ref: https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/resource/PatternType.java
const (
	AclPatternUnknown AclResourcePatternType = iota
	AclPatternAny
	AclPatternMatch
	AclPatternLiteral
	AclPatternPrefixed
)

func (a *AclResourcePatternType) String() string {
	mapping := map[AclResourcePatternType]string{
		AclPatternUnknown:  "Unknown",
		AclPatternAny:      "Any",
		AclPatternMatch:    "Match",
		AclPatternLiteral:  "Literal",
		AclPatternPrefixed: "Prefixed",
	}
	s, ok := mapping[*a]
	if !ok {
		s = mapping[AclPatternUnknown]
	}
	return s
}

//MarshalText returns the text form of the AclResourcePatternType (name without prefix)
func (a *AclResourcePatternType) MarshalText() ([]byte, error) {
	return []byte(a.String()), nil
}

//UnmarshalText takes a text reprentation of the resource pattern type and converts it to an AclResourcePatternType
func (a *AclResourcePatternType) UnmarshalText(text []byte) error {
	normalized := strings.ToLower(string(text))
	mapping := map[string]AclResourcePatternType{
		"unknown":  AclPatternUnknown,
		"any":      AclPatternAny,
		"match":    AclPatternMatch,
		"literal":  AclPatternLiteral,
		"prefixed": AclPatternPrefixed,
	}

	arpt, ok := mapping[normalized]
	if !ok {
		*a = AclPatternUnknown
		return fmt.Errorf("no acl resource pattern with name %s", normalized)
	}
	*a = arpt
	return nil
}
<|endoftext|>


<commit_before><commit_msg>Fix REPL handling of blank lines and errors.<commit_after><|endoftext|>


<commit_before><commit_msg>Create type SuitGroup<commit_after><|endoftext|>


<commit_before><commit_msg>storage/dbr: Remove Ping from type Connection<commit_after><|endoftext|>


<commit_before>package analytics

import (
	"io/ioutil"
	"os"

	"bytes"
	"encoding/json"
	"errors"
	"log"
	"net/http"
	"time"

	"github.com/jehiah/go-strftime"
	"github.com/xtgo/uuid"
)

// Version of the client.
const Version = "2.0.0"

// Endpoint for the Segment API.
const Endpoint = "https://api.segment.io"

// DefaultContext of message batches.
var DefaultContext = map[string]interface{}{
	"library": map[string]interface{}{
		"name":    "analytics-go",
		"version": Version,
	},
}

// Message interface.
type message interface {
	setMessageId(string)
	setTimestamp(string)
}

// Message fields common to all.
type Message struct {
	Type      string `json:"type,omitempty"`
	MessageId string `json:"messageId,omitempty"`
	Timestamp string `json:"timestamp,omitempty"`
	SentAt    string `json:"sentAt,omitempty"`
}

// Batch message.
type Batch struct {
	Context  map[string]interface{} `json:"context,omitempty"`
	Messages []interface{}          `json:"batch"`
	Message
}

// Identify message.
type Identify struct {
	Context      map[string]interface{} `json:"context,omitempty"`
	Integrations map[string]interface{} `json:"integrations,omitempty"`
	Traits       map[string]interface{} `json:"traits,omitempty"`
	AnonymousId  string                 `json:"anonymousId,omitempty"`
	UserId       string                 `json:"userId,omitempty"`
	Message
}

// Group message.
type Group struct {
	Context      map[string]interface{} `json:"context,omitempty"`
	Integrations map[string]interface{} `json:"integrations,omitempty"`
	Traits       map[string]interface{} `json:"traits,omitempty"`
	AnonymousId  string                 `json:"anonymousId,omitempty"`
	UserId       string                 `json:"userId,omitempty"`
	GroupId      string                 `json:"groupId"`
	Message
}

// Track message.
type Track struct {
	Context      map[string]interface{} `json:"context,omitempty"`
	Integrations map[string]interface{} `json:"integrations,omitempty"`
	Properties   map[string]interface{} `json:"properties,omitempty"`
	AnonymousId  string                 `json:"anonymousId,omitempty"`
	UserId       string                 `json:"userId,omitempty"`
	Event        string                 `json:"event"`
	Message
}

// Page message.
type Page struct {
	Context      map[string]interface{} `json:"context,omitempty"`
	Integrations map[string]interface{} `json:"integrations,omitempty"`
	Traits       map[string]interface{} `json:"properties,omitempty"`
	AnonymousId  string                 `json:"anonymousId,omitempty"`
	UserId       string                 `json:"userId,omitempty"`
	Category     string                 `json:"category,omitempty"`
	Name         string                 `json:"name,omitempty"`
	Message
}

// Alias message.
type Alias struct {
	PreviousId string `json:"previousId"`
	UserId     string `json:"userId"`
	Message
}

// Client which batches messages and flushes at the given Interval or
// when the Size limit is exceeded. Set Verbose to true to enable
// logging output.
type Client struct {
	Endpoint string
	Interval time.Duration
	Size     int
	Logger   *log.Logger
	Verbose  bool
	Client   http.Client
	key      string
	msgs     chan interface{}
	quit     chan struct{}
	shutdown chan struct{}
	uid      func() string
	now      func() time.Time
}

// New client with write key.
func New(key string) *Client {
	c := &Client{
		Endpoint: Endpoint,
		Interval: 5 * time.Second,
		Size:     250,
		Logger:   log.New(os.Stderr, "segment ", log.LstdFlags),
		Verbose:  false,
		Client:   *http.DefaultClient,
		key:      key,
		msgs:     make(chan interface{}, 100),
		quit:     make(chan struct{}),
		shutdown: make(chan struct{}),
		now:      time.Now,
		uid:      uid,
	}

	go c.loop()

	return c
}

// Alias buffers an "alias" message.
func (c *Client) Alias(msg *Alias) error {
	if msg.UserId == "" {
		return errors.New("You must pass a 'userId'.")
	}

	if msg.PreviousId == "" {
		return errors.New("You must pass a 'previousId'.")
	}

	msg.Type = "alias"
	c.queue(msg)

	return nil
}

// Page buffers an "page" message.
func (c *Client) Page(msg *Page) error {
	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "page"
	c.queue(msg)

	return nil
}

// Group buffers an "group" message.
func (c *Client) Group(msg *Group) error {
	if msg.GroupId == "" {
		return errors.New("You must pass a 'groupId'.")
	}

	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "group"
	c.queue(msg)

	return nil
}

// Identify buffers an "identify" message.
func (c *Client) Identify(msg *Identify) error {
	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "identify"
	c.queue(msg)

	return nil
}

// Track buffers an "track" message.
func (c *Client) Track(msg *Track) error {
	if msg.Event == "" {
		return errors.New("You must pass 'event'.")
	}

	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "track"
	c.queue(msg)

	return nil
}

// Queue message.
func (c *Client) queue(msg message) {
	msg.setMessageId(c.uid())
	msg.setTimestamp(timestamp(c.now()))
	c.msgs <- msg
}

// Close and flush metrics.
func (c *Client) Close() error {
	c.quit <- struct{}{}
	close(c.msgs)
	<-c.shutdown
	return nil
}

// Send batch request.
func (c *Client) send(msgs []interface{}) {
	if len(msgs) == 0 {
		return
	}

	batch := new(Batch)
	batch.Messages = msgs
	batch.MessageId = c.uid()
	batch.SentAt = timestamp(c.now())
	batch.Context = DefaultContext

	b, err := json.Marshal(batch)
	if err != nil {
		c.log("error marshalling msgs: %s", err)
		return
	}

	url := c.Endpoint + "/v1/batch"
	req, err := http.NewRequest("POST", url, bytes.NewReader(b))
	if err != nil {
		c.log("error creating request: %s", err)
		return
	}

	req.Header.Add("User-Agent", "analytics-go (version: "+Version+")")
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Content-Length", string(len(b)))
	req.SetBasicAuth(c.key, "")

	res, err := c.Client.Do(req)
	if err != nil {
		c.log("error sending request: %s", err)
		return
	}
	defer res.Body.Close()

	c.report(res)
}

// Report on response body.
func (c *Client) report(res *http.Response) {
	if res.StatusCode < 400 {
		c.verbose("response %s", res.Status)
		return
	}

	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		c.log("error reading response body: %s", err)
		return
	}

	c.log("response %s: %s – %s", res.Status, res.StatusCode, body)
}

// Batch loop.
func (c *Client) loop() {
	var msgs []interface{}
	tick := time.NewTicker(c.Interval)

	for {
		select {
		case msg := <-c.msgs:
			c.verbose("buffer (%d/%d) %v", len(msgs), c.Size, msg)
			msgs = append(msgs, msg)
			if len(msgs) == c.Size {
				c.verbose("exceeded %d messages – flushing", c.Size)
				c.send(msgs)
				msgs = nil
			}
		case <-tick.C:
			if len(msgs) > 0 {
				c.verbose("interval reached - flushing %d", len(msgs))
				c.send(msgs)
				msgs = nil
			} else {
				c.verbose("interval reached – nothing to send")
			}
		case <-c.quit:
			tick.Stop()
			c.verbose("exit requested – draining msgs")
			// drain the msg channel.
			for msg := range c.msgs {
				c.verbose("buffer (%d/%d) %v", len(msgs), c.Size, msg)
				msgs = append(msgs, msg)
			}
			c.verbose("exit requested – flushing %d", len(msgs))
			c.send(msgs)
			c.verbose("exit")
			c.shutdown <- struct{}{}
			return
		}
	}
}

// Verbose log.
func (c *Client) verbose(msg string, args ...interface{}) {
	if c.Verbose {
		c.Logger.Printf(msg, args...)
	}
}

// Unconditional log.
func (c *Client) log(msg string, args ...interface{}) {
	c.Logger.Printf(msg, args...)
}

// Set message timestamp if one is not already set.
func (m *Message) setTimestamp(s string) {
	if m.Timestamp == "" {
		m.Timestamp = s
	}
}

// Set message id.
func (m *Message) setMessageId(s string) {
	m.MessageId = s
}

// Return formatted timestamp.
func timestamp(t time.Time) string {
	return strftime.Format("%Y-%m-%dT%H:%M:%S%z", t)
}

// Return uuid string.
func uid() string {
	return uuid.NewRandom().String()
}
<commit_msg>Defer starting loop.<commit_after>package analytics

import (
	"io/ioutil"
	"os"
	"sync"

	"bytes"
	"encoding/json"
	"errors"
	"log"
	"net/http"
	"time"

	"github.com/jehiah/go-strftime"
	"github.com/xtgo/uuid"
)

// Version of the client.
const Version = "2.0.0"

// Endpoint for the Segment API.
const Endpoint = "https://api.segment.io"

// DefaultContext of message batches.
var DefaultContext = map[string]interface{}{
	"library": map[string]interface{}{
		"name":    "analytics-go",
		"version": Version,
	},
}

// Message interface.
type message interface {
	setMessageId(string)
	setTimestamp(string)
}

// Message fields common to all.
type Message struct {
	Type      string `json:"type,omitempty"`
	MessageId string `json:"messageId,omitempty"`
	Timestamp string `json:"timestamp,omitempty"`
	SentAt    string `json:"sentAt,omitempty"`
}

// Batch message.
type Batch struct {
	Context  map[string]interface{} `json:"context,omitempty"`
	Messages []interface{}          `json:"batch"`
	Message
}

// Identify message.
type Identify struct {
	Context      map[string]interface{} `json:"context,omitempty"`
	Integrations map[string]interface{} `json:"integrations,omitempty"`
	Traits       map[string]interface{} `json:"traits,omitempty"`
	AnonymousId  string                 `json:"anonymousId,omitempty"`
	UserId       string                 `json:"userId,omitempty"`
	Message
}

// Group message.
type Group struct {
	Context      map[string]interface{} `json:"context,omitempty"`
	Integrations map[string]interface{} `json:"integrations,omitempty"`
	Traits       map[string]interface{} `json:"traits,omitempty"`
	AnonymousId  string                 `json:"anonymousId,omitempty"`
	UserId       string                 `json:"userId,omitempty"`
	GroupId      string                 `json:"groupId"`
	Message
}

// Track message.
type Track struct {
	Context      map[string]interface{} `json:"context,omitempty"`
	Integrations map[string]interface{} `json:"integrations,omitempty"`
	Properties   map[string]interface{} `json:"properties,omitempty"`
	AnonymousId  string                 `json:"anonymousId,omitempty"`
	UserId       string                 `json:"userId,omitempty"`
	Event        string                 `json:"event"`
	Message
}

// Page message.
type Page struct {
	Context      map[string]interface{} `json:"context,omitempty"`
	Integrations map[string]interface{} `json:"integrations,omitempty"`
	Traits       map[string]interface{} `json:"properties,omitempty"`
	AnonymousId  string                 `json:"anonymousId,omitempty"`
	UserId       string                 `json:"userId,omitempty"`
	Category     string                 `json:"category,omitempty"`
	Name         string                 `json:"name,omitempty"`
	Message
}

// Alias message.
type Alias struct {
	PreviousId string `json:"previousId"`
	UserId     string `json:"userId"`
	Message
}

// Client which batches messages and flushes at the given Interval or
// when the Size limit is exceeded. Set Verbose to true to enable
// logging output.
type Client struct {
	Endpoint string
	// Interval represents the duration at which messages are flushed. It may be
	// configured only before any messages are enqueued.
	Interval time.Duration
	Size     int
	Logger   *log.Logger
	Verbose  bool
	Client   http.Client
	key      string
	msgs     chan interface{}
	quit     chan struct{}
	shutdown chan struct{}
	uid      func() string
	now      func() time.Time
	once     sync.Once
}

// New client with write key.
func New(key string) *Client {
	c := &Client{
		Endpoint: Endpoint,
		Interval: 5 * time.Second,
		Size:     250,
		Logger:   log.New(os.Stderr, "segment ", log.LstdFlags),
		Verbose:  false,
		Client:   *http.DefaultClient,
		key:      key,
		msgs:     make(chan interface{}, 100),
		quit:     make(chan struct{}),
		shutdown: make(chan struct{}),
		now:      time.Now,
		uid:      uid,
	}

	return c
}

// Alias buffers an "alias" message.
func (c *Client) Alias(msg *Alias) error {
	if msg.UserId == "" {
		return errors.New("You must pass a 'userId'.")
	}

	if msg.PreviousId == "" {
		return errors.New("You must pass a 'previousId'.")
	}

	msg.Type = "alias"
	c.queue(msg)

	return nil
}

// Page buffers an "page" message.
func (c *Client) Page(msg *Page) error {
	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "page"
	c.queue(msg)

	return nil
}

// Group buffers an "group" message.
func (c *Client) Group(msg *Group) error {
	if msg.GroupId == "" {
		return errors.New("You must pass a 'groupId'.")
	}

	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "group"
	c.queue(msg)

	return nil
}

// Identify buffers an "identify" message.
func (c *Client) Identify(msg *Identify) error {
	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "identify"
	c.queue(msg)

	return nil
}

// Track buffers an "track" message.
func (c *Client) Track(msg *Track) error {
	if msg.Event == "" {
		return errors.New("You must pass 'event'.")
	}

	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "track"
	c.queue(msg)

	return nil
}

func (c *Client) startLoop() {
	go c.loop()
}

// Queue message.
func (c *Client) queue(msg message) {
	c.once.Do(c.startLoop)
	msg.setMessageId(c.uid())
	msg.setTimestamp(timestamp(c.now()))
	c.msgs <- msg
}

// Close and flush metrics.
func (c *Client) Close() error {
	c.quit <- struct{}{}
	close(c.msgs)
	<-c.shutdown
	return nil
}

// Send batch request.
func (c *Client) send(msgs []interface{}) {
	if len(msgs) == 0 {
		return
	}

	batch := new(Batch)
	batch.Messages = msgs
	batch.MessageId = c.uid()
	batch.SentAt = timestamp(c.now())
	batch.Context = DefaultContext

	b, err := json.Marshal(batch)
	if err != nil {
		c.log("error marshalling msgs: %s", err)
		return
	}

	url := c.Endpoint + "/v1/batch"
	req, err := http.NewRequest("POST", url, bytes.NewReader(b))
	if err != nil {
		c.log("error creating request: %s", err)
		return
	}

	req.Header.Add("User-Agent", "analytics-go (version: "+Version+")")
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Content-Length", string(len(b)))
	req.SetBasicAuth(c.key, "")

	res, err := c.Client.Do(req)
	if err != nil {
		c.log("error sending request: %s", err)
		return
	}
	defer res.Body.Close()

	c.report(res)
}

// Report on response body.
func (c *Client) report(res *http.Response) {
	if res.StatusCode < 400 {
		c.verbose("response %s", res.Status)
		return
	}

	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		c.log("error reading response body: %s", err)
		return
	}

	c.log("response %s: %s – %s", res.Status, res.StatusCode, body)
}

// Batch loop.
func (c *Client) loop() {
	var msgs []interface{}
	tick := time.NewTicker(c.Interval)

	for {
		select {
		case msg := <-c.msgs:
			c.verbose("buffer (%d/%d) %v", len(msgs), c.Size, msg)
			msgs = append(msgs, msg)
			if len(msgs) == c.Size {
				c.verbose("exceeded %d messages – flushing", c.Size)
				c.send(msgs)
				msgs = nil
			}
		case <-tick.C:
			if len(msgs) > 0 {
				c.verbose("interval reached - flushing %d", len(msgs))
				c.send(msgs)
				msgs = nil
			} else {
				c.verbose("interval reached – nothing to send")
			}
		case <-c.quit:
			tick.Stop()
			c.verbose("exit requested – draining msgs")
			// drain the msg channel.
			for msg := range c.msgs {
				c.verbose("buffer (%d/%d) %v", len(msgs), c.Size, msg)
				msgs = append(msgs, msg)
			}
			c.verbose("exit requested – flushing %d", len(msgs))
			c.send(msgs)
			c.verbose("exit")
			c.shutdown <- struct{}{}
			return
		}
	}
}

// Verbose log.
func (c *Client) verbose(msg string, args ...interface{}) {
	if c.Verbose {
		c.Logger.Printf(msg, args...)
	}
}

// Unconditional log.
func (c *Client) log(msg string, args ...interface{}) {
	c.Logger.Printf(msg, args...)
}

// Set message timestamp if one is not already set.
func (m *Message) setTimestamp(s string) {
	if m.Timestamp == "" {
		m.Timestamp = s
	}
}

// Set message id.
func (m *Message) setMessageId(s string) {
	m.MessageId = s
}

// Return formatted timestamp.
func timestamp(t time.Time) string {
	return strftime.Format("%Y-%m-%dT%H:%M:%S%z", t)
}

// Return uuid string.
func uid() string {
	return uuid.NewRandom().String()
}
<|endoftext|>