<commit_before>package azurerm

import (
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"log"
	"reflect"
	"strings"
	"sync"

	"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/terraform/helper/mutexkv"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	riviera "github.com/jen20/riviera/azure"
)

// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
	var p *schema.Provider
	p = &schema.Provider{
		Schema: map[string]*schema.Schema{
			"subscription_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_SUBSCRIPTION_ID", ""),
			},

			"client_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_ID", ""),
			},

			"client_secret": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_SECRET", ""),
			},

			"tenant_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_TENANT_ID", ""),
			},

			"environment": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_ENVIRONMENT", "public"),
			},

			"skip_provider_registration": {
				Type:        schema.TypeBool,
				Optional:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_SKIP_PROVIDER_REGISTRATION", false),
			},
		},

		DataSourcesMap: map[string]*schema.Resource{
			"azurerm_client_config":  dataSourceArmClientConfig(),
			"azurerm_resource_group": dataSourceArmResourceGroup(),
			"azurerm_public_ip":      dataSourceArmPublicIP(),
			"azurerm_managed_disk":   dataSourceArmManagedDisk(),
		},

		ResourcesMap: map[string]*schema.Resource{
			// These resources use the Azure ARM SDK
			"azurerm_application_insights": resourceArmApplicationInsights(),
			"azurerm_availability_set":   resourceArmAvailabilitySet(),
			"azurerm_cdn_endpoint":       resourceArmCdnEndpoint(),
			"azurerm_cdn_profile":        resourceArmCdnProfile(),
			"azurerm_container_registry": resourceArmContainerRegistry(),
			"azurerm_container_service":  resourceArmContainerService(),
			"azurerm_cosmosdb_account":   resourceArmCosmosDBAccount(),

			"azurerm_dns_a_record":      resourceArmDnsARecord(),
			"azurerm_dns_aaaa_record":   resourceArmDnsAAAARecord(),
			"azurerm_dns_cname_record":  resourceArmDnsCNameRecord(),
			"azurerm_dns_mx_record":     resourceArmDnsMxRecord(),
			"azurerm_dns_ns_record":     resourceArmDnsNsRecord(),
			"azurerm_dns_ptr_record":     resourceArmDnsPtrRecord(),
			"azurerm_dns_srv_record":    resourceArmDnsSrvRecord(),
			"azurerm_dns_txt_record":    resourceArmDnsTxtRecord(),
			"azurerm_dns_zone":          resourceArmDnsZone(),

			"azurerm_eventhub":                    resourceArmEventHub(),
			"azurerm_eventhub_authorization_rule": resourceArmEventHubAuthorizationRule(),
			"azurerm_eventhub_consumer_group":     resourceArmEventHubConsumerGroup(),
			"azurerm_eventhub_namespace":          resourceArmEventHubNamespace(),
			"azurerm_express_route_circuit": resourceArmExpressRouteCircuit(),
			"azurerm_image":        resourceArmImage(),
			"azurerm_key_vault":                 resourceArmKeyVault(),

			"azurerm_lb":                      resourceArmLoadBalancer(),
			"azurerm_lb_backend_address_pool": resourceArmLoadBalancerBackendAddressPool(),
			"azurerm_lb_nat_rule":             resourceArmLoadBalancerNatRule(),
			"azurerm_lb_nat_pool":             resourceArmLoadBalancerNatPool(),
			"azurerm_lb_probe":                resourceArmLoadBalancerProbe(),
			"azurerm_lb_rule":                 resourceArmLoadBalancerRule(),
			"azurerm_local_network_gateway":     resourceArmLocalNetworkGateway(),

			"azurerm_managed_disk": resourceArmManagedDisk(),
			"azurerm_network_interface":         resourceArmNetworkInterface(),
			"azurerm_network_security_group":    resourceArmNetworkSecurityGroup(),
			"azurerm_network_security_rule":     resourceArmNetworkSecurityRule(),
			"azurerm_public_ip":                 resourceArmPublicIp(),

			"azurerm_redis_cache":               resourceArmRedisCache(),
			"azurerm_route":                     resourceArmRoute(),
			"azurerm_route_table":               resourceArmRouteTable(),

			"azurerm_servicebus_namespace":      resourceArmServiceBusNamespace(),
			"azurerm_servicebus_queue":          resourceArmServiceBusQueue(),
			"azurerm_servicebus_subscription":   resourceArmServiceBusSubscription(),
			"azurerm_servicebus_topic":          resourceArmServiceBusTopic(),
			"azurerm_sql_elasticpool":           resourceArmSqlElasticPool(),
			"azurerm_storage_account":           resourceArmStorageAccount(),
			"azurerm_storage_blob":              resourceArmStorageBlob(),
			"azurerm_storage_container":         resourceArmStorageContainer(),
			"azurerm_storage_share":             resourceArmStorageShare(),
			"azurerm_storage_queue":             resourceArmStorageQueue(),
			"azurerm_storage_table":             resourceArmStorageTable(),
			"azurerm_subnet":                    resourceArmSubnet(),

			"azurerm_template_deployment":       resourceArmTemplateDeployment(),
			"azurerm_traffic_manager_endpoint":  resourceArmTrafficManagerEndpoint(),
			"azurerm_traffic_manager_profile":   resourceArmTrafficManagerProfile(),
			"azurerm_virtual_machine_extension": resourceArmVirtualMachineExtensions(),
			"azurerm_virtual_machine":           resourceArmVirtualMachine(),
			"azurerm_virtual_machine_scale_set": resourceArmVirtualMachineScaleSet(),
			"azurerm_virtual_network":           resourceArmVirtualNetwork(),
			"azurerm_virtual_network_peering":   resourceArmVirtualNetworkPeering(),

			// These resources use the Riviera SDK
			"azurerm_resource_group":    resourceArmResourceGroup(),
			"azurerm_search_service":    resourceArmSearchService(),
			"azurerm_sql_database":      resourceArmSqlDatabase(),
			"azurerm_sql_firewall_rule": resourceArmSqlFirewallRule(),
			"azurerm_sql_server":        resourceArmSqlServer(),
		},
	}

	p.ConfigureFunc = providerConfigure(p)

	return p
}

// Config is the configuration structure used to instantiate a
// new Azure management client.
type Config struct {
	ManagementURL string

	SubscriptionID           string
	ClientID                 string
	ClientSecret             string
	TenantID                 string
	Environment              string
	SkipProviderRegistration bool

	validateCredentialsOnce sync.Once
}

func (c *Config) validate() error {
	var err *multierror.Error

	if c.SubscriptionID == "" {
		err = multierror.Append(err, fmt.Errorf("Subscription ID must be configured for the AzureRM provider"))
	}
	if c.ClientID == "" {
		err = multierror.Append(err, fmt.Errorf("Client ID must be configured for the AzureRM provider"))
	}
	if c.ClientSecret == "" {
		err = multierror.Append(err, fmt.Errorf("Client Secret must be configured for the AzureRM provider"))
	}
	if c.TenantID == "" {
		err = multierror.Append(err, fmt.Errorf("Tenant ID must be configured for the AzureRM provider"))
	}
	if c.Environment == "" {
		err = multierror.Append(err, fmt.Errorf("Environment must be configured for the AzureRM provider"))
	}

	return err.ErrorOrNil()
}

func providerConfigure(p *schema.Provider) schema.ConfigureFunc {
	return func(d *schema.ResourceData) (interface{}, error) {
		config := &Config{
			SubscriptionID:           d.Get("subscription_id").(string),
			ClientID:                 d.Get("client_id").(string),
			ClientSecret:             d.Get("client_secret").(string),
			TenantID:                 d.Get("tenant_id").(string),
			Environment:              d.Get("environment").(string),
			SkipProviderRegistration: d.Get("skip_provider_registration").(bool),
		}

		if err := config.validate(); err != nil {
			return nil, err
		}

		client, err := config.getArmClient()
		if err != nil {
			return nil, err
		}

		client.StopContext = p.StopContext()

		// replaces the context between tests
		p.MetaReset = func() error {
			client.StopContext = p.StopContext()
			return nil
		}

		// List all the available providers and their registration state to avoid unnecessary
		// requests. This also lets us check if the provider credentials are correct.
		providerList, err := client.providers.List(nil, "")
		if err != nil {
			return nil, fmt.Errorf("Unable to list provider registration status, it is possible that this is due to invalid "+
				"credentials or the service principal does not have permission to use the Resource Manager API, Azure "+
				"error: %s", err)
		}

		if !config.SkipProviderRegistration {
			err = registerAzureResourceProvidersWithSubscription(*providerList.Value, client.providers)
			if err != nil {
				return nil, err
			}
		}

		return client, nil
	}
}

func registerProviderWithSubscription(providerName string, client resources.ProvidersClient) error {
	_, err := client.Register(providerName)
	if err != nil {
		return fmt.Errorf("Cannot register provider %s with Azure Resource Manager: %s.", providerName, err)
	}

	return nil
}

var providerRegistrationOnce sync.Once

// registerAzureResourceProvidersWithSubscription uses the providers client to register
// all Azure resource providers which the Terraform provider may require (regardless of
// whether they are actually used by the configuration or not). It was confirmed by Microsoft
// that this is the approach their own internal tools also take.
func registerAzureResourceProvidersWithSubscription(providerList []resources.Provider, client resources.ProvidersClient) error {
	var err error
	providerRegistrationOnce.Do(func() {
		providers := map[string]struct{}{
			"Microsoft.Compute":           struct{}{},
			"Microsoft.Cache":             struct{}{},
			"Microsoft.ContainerRegistry": struct{}{},
			"Microsoft.ContainerService":  struct{}{},
			"Microsoft.Network":           struct{}{},
			"Microsoft.Cdn":               struct{}{},
			"Microsoft.Storage":           struct{}{},
			"Microsoft.Sql":               struct{}{},
			"Microsoft.Search":            struct{}{},
			"Microsoft.Resources":         struct{}{},
			"Microsoft.ServiceBus":        struct{}{},
			"Microsoft.KeyVault":          struct{}{},
			"Microsoft.EventHub":          struct{}{},
		}

		// filter out any providers already registered
		for _, p := range providerList {
			if _, ok := providers[*p.Namespace]; !ok {
				continue
			}

			if strings.ToLower(*p.RegistrationState) == "registered" {
				log.Printf("[DEBUG] Skipping provider registration for namespace %s\n", *p.Namespace)
				delete(providers, *p.Namespace)
			}
		}

		var wg sync.WaitGroup
		wg.Add(len(providers))
		for providerName := range providers {
			go func(p string) {
				defer wg.Done()
				log.Printf("[DEBUG] Registering provider with namespace %s\n", p)
				if innerErr := registerProviderWithSubscription(p, client); err != nil {
					err = innerErr
				}
			}(providerName)
		}
		wg.Wait()
	})

	return err
}

// armMutexKV is the instance of MutexKV for ARM resources
var armMutexKV = mutexkv.NewMutexKV()

func azureStateRefreshFunc(resourceURI string, client *ArmClient, command riviera.APICall) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		req := client.rivieraClient.NewRequestForURI(resourceURI)
		req.Command = command

		res, err := req.Execute()
		if err != nil {
			return nil, "", fmt.Errorf("Error executing %T command in azureStateRefreshFunc", req.Command)
		}

		var value reflect.Value
		if reflect.ValueOf(res.Parsed).Kind() == reflect.Ptr {
			value = reflect.ValueOf(res.Parsed).Elem()
		} else {
			value = reflect.ValueOf(res.Parsed)
		}

		for i := 0; i < value.NumField(); i++ { // iterates through every struct type field
			tag := value.Type().Field(i).Tag // returns the tag string
			tagValue := tag.Get("mapstructure")
			if tagValue == "provisioningState" {
				return res.Parsed, value.Field(i).Elem().String(), nil
			}
		}

		panic(fmt.Errorf("azureStateRefreshFunc called on structure %T with no mapstructure:provisioningState tag. This is a bug", res.Parsed))
	}
}

// Resource group names can be capitalised, but we store them in lowercase.
// Use a custom diff function to avoid creation of new resources.
func resourceAzurermResourceGroupNameDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
	return strings.ToLower(old) == strings.ToLower(new)
}

// ignoreCaseDiffSuppressFunc is a DiffSuppressFunc from helper/schema that is
// used to ignore any case-changes in a return value.
func ignoreCaseDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool {
	return strings.ToLower(old) == strings.ToLower(new)
}

// ignoreCaseStateFunc is a StateFunc from helper/schema that converts the
// supplied value to lower before saving to state for consistency.
func ignoreCaseStateFunc(val interface{}) string {
	return strings.ToLower(val.(string))
}

func userDataStateFunc(v interface{}) string {
	switch s := v.(type) {
	case string:
		s = base64Encode(s)
		hash := sha1.Sum([]byte(s))
		return hex.EncodeToString(hash[:])
	default:
		return ""
	}
}

// base64Encode encodes data if the input isn't already encoded using
// base64.StdEncoding.EncodeToString. If the input is already base64 encoded,
// return the original input unchanged.
func base64Encode(data string) string {
	// Check whether the data is already Base64 encoded; don't double-encode
	if isBase64Encoded(data) {
		return data
	}
	// data has not been encoded encode and return
	return base64.StdEncoding.EncodeToString([]byte(data))
}

func isBase64Encoded(data string) bool {
	_, err := base64.StdEncoding.DecodeString(data)
	return err == nil
}
<commit_msg>Linting<commit_after>package azurerm

import (
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"log"
	"reflect"
	"strings"
	"sync"

	"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/terraform/helper/mutexkv"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	riviera "github.com/jen20/riviera/azure"
)

// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
	var p *schema.Provider
	p = &schema.Provider{
		Schema: map[string]*schema.Schema{
			"subscription_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_SUBSCRIPTION_ID", ""),
			},

			"client_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_ID", ""),
			},

			"client_secret": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_SECRET", ""),
			},

			"tenant_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_TENANT_ID", ""),
			},

			"environment": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_ENVIRONMENT", "public"),
			},

			"skip_provider_registration": {
				Type:        schema.TypeBool,
				Optional:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_SKIP_PROVIDER_REGISTRATION", false),
			},
		},

		DataSourcesMap: map[string]*schema.Resource{
			"azurerm_client_config":  dataSourceArmClientConfig(),
			"azurerm_resource_group": dataSourceArmResourceGroup(),
			"azurerm_public_ip":      dataSourceArmPublicIP(),
			"azurerm_managed_disk":   dataSourceArmManagedDisk(),
		},

		ResourcesMap: map[string]*schema.Resource{
			// These resources use the Azure ARM SDK
			"azurerm_application_insights": resourceArmApplicationInsights(),
			"azurerm_availability_set":     resourceArmAvailabilitySet(),
			"azurerm_cdn_endpoint":         resourceArmCdnEndpoint(),
			"azurerm_cdn_profile":          resourceArmCdnProfile(),
			"azurerm_container_registry":   resourceArmContainerRegistry(),
			"azurerm_container_service":    resourceArmContainerService(),
			"azurerm_cosmosdb_account":     resourceArmCosmosDBAccount(),

			"azurerm_dns_a_record":     resourceArmDnsARecord(),
			"azurerm_dns_aaaa_record":  resourceArmDnsAAAARecord(),
			"azurerm_dns_cname_record": resourceArmDnsCNameRecord(),
			"azurerm_dns_mx_record":    resourceArmDnsMxRecord(),
			"azurerm_dns_ns_record":    resourceArmDnsNsRecord(),
			"azurerm_dns_ptr_record":   resourceArmDnsPtrRecord(),
			"azurerm_dns_srv_record":   resourceArmDnsSrvRecord(),
			"azurerm_dns_txt_record":   resourceArmDnsTxtRecord(),
			"azurerm_dns_zone":         resourceArmDnsZone(),

			"azurerm_eventhub":                    resourceArmEventHub(),
			"azurerm_eventhub_authorization_rule": resourceArmEventHubAuthorizationRule(),
			"azurerm_eventhub_consumer_group":     resourceArmEventHubConsumerGroup(),
			"azurerm_eventhub_namespace":          resourceArmEventHubNamespace(),
			"azurerm_express_route_circuit":       resourceArmExpressRouteCircuit(),
			"azurerm_image":                       resourceArmImage(),
			"azurerm_key_vault":                   resourceArmKeyVault(),

			"azurerm_lb":                      resourceArmLoadBalancer(),
			"azurerm_lb_backend_address_pool": resourceArmLoadBalancerBackendAddressPool(),
			"azurerm_lb_nat_rule":             resourceArmLoadBalancerNatRule(),
			"azurerm_lb_nat_pool":             resourceArmLoadBalancerNatPool(),
			"azurerm_lb_probe":                resourceArmLoadBalancerProbe(),
			"azurerm_lb_rule":                 resourceArmLoadBalancerRule(),
			"azurerm_local_network_gateway":   resourceArmLocalNetworkGateway(),

			"azurerm_managed_disk":           resourceArmManagedDisk(),
			"azurerm_network_interface":      resourceArmNetworkInterface(),
			"azurerm_network_security_group": resourceArmNetworkSecurityGroup(),
			"azurerm_network_security_rule":  resourceArmNetworkSecurityRule(),
			"azurerm_public_ip":              resourceArmPublicIp(),

			"azurerm_redis_cache": resourceArmRedisCache(),
			"azurerm_route":       resourceArmRoute(),
			"azurerm_route_table": resourceArmRouteTable(),

			"azurerm_servicebus_namespace":    resourceArmServiceBusNamespace(),
			"azurerm_servicebus_queue":        resourceArmServiceBusQueue(),
			"azurerm_servicebus_subscription": resourceArmServiceBusSubscription(),
			"azurerm_servicebus_topic":        resourceArmServiceBusTopic(),
			"azurerm_sql_elasticpool":         resourceArmSqlElasticPool(),
			"azurerm_storage_account":         resourceArmStorageAccount(),
			"azurerm_storage_blob":            resourceArmStorageBlob(),
			"azurerm_storage_container":       resourceArmStorageContainer(),
			"azurerm_storage_share":           resourceArmStorageShare(),
			"azurerm_storage_queue":           resourceArmStorageQueue(),
			"azurerm_storage_table":           resourceArmStorageTable(),
			"azurerm_subnet":                  resourceArmSubnet(),

			"azurerm_template_deployment":       resourceArmTemplateDeployment(),
			"azurerm_traffic_manager_endpoint":  resourceArmTrafficManagerEndpoint(),
			"azurerm_traffic_manager_profile":   resourceArmTrafficManagerProfile(),
			"azurerm_virtual_machine_extension": resourceArmVirtualMachineExtensions(),
			"azurerm_virtual_machine":           resourceArmVirtualMachine(),
			"azurerm_virtual_machine_scale_set": resourceArmVirtualMachineScaleSet(),
			"azurerm_virtual_network":           resourceArmVirtualNetwork(),
			"azurerm_virtual_network_peering":   resourceArmVirtualNetworkPeering(),

			// These resources use the Riviera SDK
			"azurerm_resource_group":    resourceArmResourceGroup(),
			"azurerm_search_service":    resourceArmSearchService(),
			"azurerm_sql_database":      resourceArmSqlDatabase(),
			"azurerm_sql_firewall_rule": resourceArmSqlFirewallRule(),
			"azurerm_sql_server":        resourceArmSqlServer(),
		},
	}

	p.ConfigureFunc = providerConfigure(p)

	return p
}

// Config is the configuration structure used to instantiate a
// new Azure management client.
type Config struct {
	ManagementURL string

	SubscriptionID           string
	ClientID                 string
	ClientSecret             string
	TenantID                 string
	Environment              string
	SkipProviderRegistration bool

	validateCredentialsOnce sync.Once
}

func (c *Config) validate() error {
	var err *multierror.Error

	if c.SubscriptionID == "" {
		err = multierror.Append(err, fmt.Errorf("Subscription ID must be configured for the AzureRM provider"))
	}
	if c.ClientID == "" {
		err = multierror.Append(err, fmt.Errorf("Client ID must be configured for the AzureRM provider"))
	}
	if c.ClientSecret == "" {
		err = multierror.Append(err, fmt.Errorf("Client Secret must be configured for the AzureRM provider"))
	}
	if c.TenantID == "" {
		err = multierror.Append(err, fmt.Errorf("Tenant ID must be configured for the AzureRM provider"))
	}
	if c.Environment == "" {
		err = multierror.Append(err, fmt.Errorf("Environment must be configured for the AzureRM provider"))
	}

	return err.ErrorOrNil()
}

func providerConfigure(p *schema.Provider) schema.ConfigureFunc {
	return func(d *schema.ResourceData) (interface{}, error) {
		config := &Config{
			SubscriptionID:           d.Get("subscription_id").(string),
			ClientID:                 d.Get("client_id").(string),
			ClientSecret:             d.Get("client_secret").(string),
			TenantID:                 d.Get("tenant_id").(string),
			Environment:              d.Get("environment").(string),
			SkipProviderRegistration: d.Get("skip_provider_registration").(bool),
		}

		if err := config.validate(); err != nil {
			return nil, err
		}

		client, err := config.getArmClient()
		if err != nil {
			return nil, err
		}

		client.StopContext = p.StopContext()

		// replaces the context between tests
		p.MetaReset = func() error {
			client.StopContext = p.StopContext()
			return nil
		}

		// List all the available providers and their registration state to avoid unnecessary
		// requests. This also lets us check if the provider credentials are correct.
		providerList, err := client.providers.List(nil, "")
		if err != nil {
			return nil, fmt.Errorf("Unable to list provider registration status, it is possible that this is due to invalid "+
				"credentials or the service principal does not have permission to use the Resource Manager API, Azure "+
				"error: %s", err)
		}

		if !config.SkipProviderRegistration {
			err = registerAzureResourceProvidersWithSubscription(*providerList.Value, client.providers)
			if err != nil {
				return nil, err
			}
		}

		return client, nil
	}
}

func registerProviderWithSubscription(providerName string, client resources.ProvidersClient) error {
	_, err := client.Register(providerName)
	if err != nil {
		return fmt.Errorf("Cannot register provider %s with Azure Resource Manager: %s.", providerName, err)
	}

	return nil
}

var providerRegistrationOnce sync.Once

// registerAzureResourceProvidersWithSubscription uses the providers client to register
// all Azure resource providers which the Terraform provider may require (regardless of
// whether they are actually used by the configuration or not). It was confirmed by Microsoft
// that this is the approach their own internal tools also take.
func registerAzureResourceProvidersWithSubscription(providerList []resources.Provider, client resources.ProvidersClient) error {
	var err error
	providerRegistrationOnce.Do(func() {
		providers := map[string]struct{}{
			"Microsoft.Compute":           struct{}{},
			"Microsoft.Cache":             struct{}{},
			"Microsoft.ContainerRegistry": struct{}{},
			"Microsoft.ContainerService":  struct{}{},
			"Microsoft.Network":           struct{}{},
			"Microsoft.Cdn":               struct{}{},
			"Microsoft.Storage":           struct{}{},
			"Microsoft.Sql":               struct{}{},
			"Microsoft.Search":            struct{}{},
			"Microsoft.Resources":         struct{}{},
			"Microsoft.ServiceBus":        struct{}{},
			"Microsoft.KeyVault":          struct{}{},
			"Microsoft.EventHub":          struct{}{},
		}

		// filter out any providers already registered
		for _, p := range providerList {
			if _, ok := providers[*p.Namespace]; !ok {
				continue
			}

			if strings.ToLower(*p.RegistrationState) == "registered" {
				log.Printf("[DEBUG] Skipping provider registration for namespace %s\n", *p.Namespace)
				delete(providers, *p.Namespace)
			}
		}

		var wg sync.WaitGroup
		wg.Add(len(providers))
		for providerName := range providers {
			go func(p string) {
				defer wg.Done()
				log.Printf("[DEBUG] Registering provider with namespace %s\n", p)
				if innerErr := registerProviderWithSubscription(p, client); err != nil {
					err = innerErr
				}
			}(providerName)
		}
		wg.Wait()
	})

	return err
}

// armMutexKV is the instance of MutexKV for ARM resources
var armMutexKV = mutexkv.NewMutexKV()

func azureStateRefreshFunc(resourceURI string, client *ArmClient, command riviera.APICall) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		req := client.rivieraClient.NewRequestForURI(resourceURI)
		req.Command = command

		res, err := req.Execute()
		if err != nil {
			return nil, "", fmt.Errorf("Error executing %T command in azureStateRefreshFunc", req.Command)
		}

		var value reflect.Value
		if reflect.ValueOf(res.Parsed).Kind() == reflect.Ptr {
			value = reflect.ValueOf(res.Parsed).Elem()
		} else {
			value = reflect.ValueOf(res.Parsed)
		}

		for i := 0; i < value.NumField(); i++ { // iterates through every struct type field
			tag := value.Type().Field(i).Tag // returns the tag string
			tagValue := tag.Get("mapstructure")
			if tagValue == "provisioningState" {
				return res.Parsed, value.Field(i).Elem().String(), nil
			}
		}

		panic(fmt.Errorf("azureStateRefreshFunc called on structure %T with no mapstructure:provisioningState tag. This is a bug", res.Parsed))
	}
}

// Resource group names can be capitalised, but we store them in lowercase.
// Use a custom diff function to avoid creation of new resources.
func resourceAzurermResourceGroupNameDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
	return strings.ToLower(old) == strings.ToLower(new)
}

// ignoreCaseDiffSuppressFunc is a DiffSuppressFunc from helper/schema that is
// used to ignore any case-changes in a return value.
func ignoreCaseDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool {
	return strings.ToLower(old) == strings.ToLower(new)
}

// ignoreCaseStateFunc is a StateFunc from helper/schema that converts the
// supplied value to lower before saving to state for consistency.
func ignoreCaseStateFunc(val interface{}) string {
	return strings.ToLower(val.(string))
}

func userDataStateFunc(v interface{}) string {
	switch s := v.(type) {
	case string:
		s = base64Encode(s)
		hash := sha1.Sum([]byte(s))
		return hex.EncodeToString(hash[:])
	default:
		return ""
	}
}

// base64Encode encodes data if the input isn't already encoded using
// base64.StdEncoding.EncodeToString. If the input is already base64 encoded,
// return the original input unchanged.
func base64Encode(data string) string {
	// Check whether the data is already Base64 encoded; don't double-encode
	if isBase64Encoded(data) {
		return data
	}
	// data has not been encoded encode and return
	return base64.StdEncoding.EncodeToString([]byte(data))
}

func isBase64Encoded(data string) bool {
	_, err := base64.StdEncoding.DecodeString(data)
	return err == nil
}
<|endoftext|>


<commit_before>package fuse

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/pkg/require"
	"github.com/pachyderm/pachyderm/src/server/pfs/server"
)

const (
	MB = 1024 * 1024
	GB = 1024 * 1024 * 1024
)

func TestBasic(t *testing.T) {
	c := server.GetPachClient(t)
	require.NoError(t, c.CreateRepo("repo"))
	_, err := c.PutFile("repo", "master", "file", strings.NewReader("foo"))
	require.NoError(t, err)
	mount(t, c, nil, func(mountPoint string) {
		repos, err := ioutil.ReadDir(mountPoint)
		require.NoError(t, err)
		require.Equal(t, 1, len(repos))
		require.Equal(t, "repo", filepath.Base(repos[0].Name()))

		files, err := ioutil.ReadDir(filepath.Join(mountPoint, "repo"))
		require.NoError(t, err)
		require.Equal(t, 1, len(files))
		require.Equal(t, "file", filepath.Base(files[0].Name()))

		data, err := ioutil.ReadFile(filepath.Join(mountPoint, "repo", "file"))
		require.NoError(t, err)
		require.Equal(t, "foo", string(data))
	})
}

func TestLargeFile(t *testing.T) {
	c := server.GetPachClient(t)
	require.NoError(t, c.CreateRepo("repo"))
	_, err := c.PutFile("repo", "master", "file", strings.NewReader(strings.Repeat("p", GB)))
	require.NoError(t, err)
	mount(t, c, nil, func(mountPoint string) {
		data, err := ioutil.ReadFile(filepath.Join(mountPoint, "repo", "file"))
		require.NoError(t, err)
		require.Equal(t, GB, len(data))
	})
}

func TestSeek(t *testing.T) {
	c := server.GetPachClient(t)
	require.NoError(t, c.CreateRepo("repo"))
	data := strings.Repeat("foo", MB)
	_, err := c.PutFile("repo", "master", "file", strings.NewReader(data))
	require.NoError(t, err)
	mount(t, c, nil, func(mountPoint string) {
		f, err := os.Open(filepath.Join(mountPoint, "repo", "file"))
		require.NoError(t, err)
		defer func() {
			require.NoError(t, f.Close())
		}()

		testSeek := func(offset int64) {
			_, err = f.Seek(offset, 0)
			require.NoError(t, err)
			d, err := ioutil.ReadAll(f)
			require.NoError(t, err)
			require.Equal(t, data[offset:], string(d))
		}

		testSeek(0)
		testSeek(MB)
		testSeek(2 * MB)
		testSeek(3 * MB)
	})
}

func mount(t *testing.T, c *client.APIClient, commits map[string]string, f func(mountPoint string)) {
	dir, err := ioutil.TempDir("", "pfs")
	require.NoError(t, err)
	defer os.RemoveAll(dir)
	opts := &Options{
		Commits: commits,
		Unmount: make(chan struct{}),
	}
	defer func() {
		close(opts.Unmount)
	}()
	go func() {
		Mount(c, dir, opts)
	}()
	// Gotta give the fuse mount time to come up.
	time.Sleep(2 * time.Second)
	f(dir)
}
<commit_msg>Expands fuse test. Adds benchmark.<commit_after>package fuse

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/pfs"
	"github.com/pachyderm/pachyderm/src/client/pkg/require"
	"github.com/pachyderm/pachyderm/src/server/pfs/server"
)

const (
	MB = 1024 * 1024
	GB = 1024 * 1024 * 1024
)

func TestBasic(t *testing.T) {
	c := server.GetPachClient(t)
	require.NoError(t, c.CreateRepo("repo"))
	_, err := c.PutFile("repo", "master", "file", strings.NewReader("foo"))
	require.NoError(t, err)
	mount(t, c, nil, func(mountPoint string) {
		repos, err := ioutil.ReadDir(mountPoint)
		require.NoError(t, err)
		require.Equal(t, 1, len(repos))
		require.Equal(t, "repo", filepath.Base(repos[0].Name()))

		files, err := ioutil.ReadDir(filepath.Join(mountPoint, "repo"))
		require.NoError(t, err)
		require.Equal(t, 1, len(files))
		require.Equal(t, "file", filepath.Base(files[0].Name()))

		data, err := ioutil.ReadFile(filepath.Join(mountPoint, "repo", "file"))
		require.NoError(t, err)
		require.Equal(t, "foo", string(data))
	})
}

func TestChunkSize(t *testing.T) {
	c := server.GetPachClient(t)
	require.NoError(t, c.CreateRepo("repo"))
	_, err := c.PutFile("repo", "master", "file", strings.NewReader(strings.Repeat("p", int(pfs.ChunkSize))))
	require.NoError(t, err)
	mount(t, c, nil, func(mountPoint string) {
		data, err := ioutil.ReadFile(filepath.Join(mountPoint, "repo", "file"))
		require.NoError(t, err)
		require.Equal(t, int(pfs.ChunkSize), len(data))
	})
}

func TestLargeFile(t *testing.T) {
	c := server.GetPachClient(t)
	require.NoError(t, c.CreateRepo("repo"))
	_, err := c.PutFile("repo", "master", "file", strings.NewReader(strings.Repeat("p", GB)))
	require.NoError(t, err)
	mount(t, c, nil, func(mountPoint string) {
		data, err := ioutil.ReadFile(filepath.Join(mountPoint, "repo", "file"))
		require.NoError(t, err)
		require.Equal(t, GB, len(data))
	})
}

func BenchmarkLargeFile(b *testing.B) {
	c := server.GetPachClient(b)
	require.NoError(b, c.CreateRepo("repo"))
	_, err := c.PutFile("repo", "master", "file", strings.NewReader(strings.Repeat("p", GB)))
	require.NoError(b, err)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		mount(b, c, nil, func(mountPoint string) {
			data, err := ioutil.ReadFile(filepath.Join(mountPoint, "repo", "file"))
			require.NoError(b, err)
			require.Equal(b, GB, len(data))
		})
	}
}

func TestSeek(t *testing.T) {
	c := server.GetPachClient(t)
	require.NoError(t, c.CreateRepo("repo"))
	data := strings.Repeat("foo", MB)
	_, err := c.PutFile("repo", "master", "file", strings.NewReader(data))
	require.NoError(t, err)
	mount(t, c, nil, func(mountPoint string) {
		f, err := os.Open(filepath.Join(mountPoint, "repo", "file"))
		require.NoError(t, err)
		defer func() {
			require.NoError(t, f.Close())
		}()

		testSeek := func(offset int64) {
			_, err = f.Seek(offset, 0)
			require.NoError(t, err)
			d, err := ioutil.ReadAll(f)
			require.NoError(t, err)
			require.Equal(t, data[offset:], string(d))
		}

		testSeek(0)
		testSeek(MB)
		testSeek(2 * MB)
		testSeek(3 * MB)
	})
}

func mount(tb testing.TB, c *client.APIClient, commits map[string]string, f func(mountPoint string)) {
	dir, err := ioutil.TempDir("", "pfs")
	require.NoError(tb, err)
	defer os.RemoveAll(dir)
	opts := &Options{
		Commits: commits,
		Unmount: make(chan struct{}),
	}
	defer func() {
		close(opts.Unmount)
	}()
	go func() {
		Mount(c, dir, opts)
	}()
	// Gotta give the fuse mount time to come up.
	time.Sleep(2 * time.Second)
	f(dir)
}
<|endoftext|>


<commit_before>package lib

import (
	"fmt"
	"net/url"
)

// DNSDomain represents a DNS domain on Vultr
type DNSDomain struct {
	Domain  string `json:"domain"`
	Created string `json:"date_created"`
}

// DNSRecord represents a DNS record on Vultr
type DNSRecord struct {
	RecordID int    `json:"RECORDID"`
	Type     string `json:"type"`
	Name     string `json:"name"`
	Data     string `json:"data"`
	Priority int    `json:"priority"`
	TTL      int    `json:"ttl"`
}

// GetDNSDomains returns a list of available domains on Vultr account
func (c *Client) GetDNSDomains() (dnsdomains []DNSDomain, err error) {
	if err := c.get(`dns/list`, &dnsdomains); err != nil {
		return nil, err
	}
	return dnsdomains, nil
}

// CreateDNSDomain creates a new DNS domain name on Vultr
func (c *Client) CreateDNSDomain(domain, serverip string) error {
	values := url.Values{
		"domain":   {domain},
		"serverip": {serverip},
	}

	if err := c.post(`dns/create_domain`, values, nil); err != nil {
		return err
	}
	return nil
}

// DeleteDNSDomain deletes an existing DNS domain name
func (c *Client) DeleteDNSDomain(domain string) error {
	values := url.Values{
		"domain": {domain},
	}

	if err := c.post(`dns/delete_domain`, values, nil); err != nil {
		return err
	}
	return nil
}

// GetDNSRecords returns a list of all DNS records of a particular domain
func (c *Client) GetDNSRecords(domain string) (dnsrecords []DNSRecord, err error) {
	if err := c.get(`dns/records?domain=`+domain, &dnsrecords); err != nil {
		return nil, err
	}
	return dnsrecords, nil
}

// CreateDNSRecord creates a new DNS record
func (c *Client) CreateDNSRecord(domain, name, rtype, data string, priority, ttl int) error {
	values := url.Values{
		"domain":   {domain},
		"name":     {name},
		"type":     {rtype},
		"data":     {data},
		"priority": {fmt.Sprintf("%v", priority)},
		"ttl":      {fmt.Sprintf("%v", ttl)},
	}

	if err := c.post(`dns/create_record`, values, nil); err != nil {
		return err
	}
	return nil
}

// UpdateDNSRecord updates an existing DNS record
func (c *Client) UpdateDNSRecord(domain string, dnsrecord DNSRecord) error {
	values := url.Values{
		"domain":   {domain},
		"RECORDID": {fmt.Sprintf("%v", dnsrecord.RecordID)},
	}

	if dnsrecord.Name != "" {
		values.Add("name", dnsrecord.Name)
	}
	if dnsrecord.Data != "" {
		values.Add("data", dnsrecord.Data)
	}
	if dnsrecord.Priority != 0 {
		values.Add("priority", fmt.Sprintf("%v", dnsrecord.Priority))
	}
	if dnsrecord.TTL != 0 {
		values.Add("ttl", fmt.Sprintf("%v", dnsrecord.TTL))
	}

	if err := c.post(`dns/update_record`, values, nil); err != nil {
		return err
	}
	return nil
}

// DeleteDNSRecord deletes an existing DNS record
func (c *Client) DeleteDNSRecord(domain string, recordID int) error {
	values := url.Values{
		"domain":   {domain},
		"RECORDID": {fmt.Sprintf("%v", recordID)},
	}

	if err := c.post(`dns/delete_record`, values, nil); err != nil {
		return err
	}
	return nil
}
<commit_msg>rename parameter<commit_after>package lib

import (
	"fmt"
	"net/url"
)

// DNSDomain represents a DNS domain on Vultr
type DNSDomain struct {
	Domain  string `json:"domain"`
	Created string `json:"date_created"`
}

// DNSRecord represents a DNS record on Vultr
type DNSRecord struct {
	RecordID int    `json:"RECORDID"`
	Type     string `json:"type"`
	Name     string `json:"name"`
	Data     string `json:"data"`
	Priority int    `json:"priority"`
	TTL      int    `json:"ttl"`
}

// GetDNSDomains returns a list of available domains on Vultr account
func (c *Client) GetDNSDomains() (dnsdomains []DNSDomain, err error) {
	if err := c.get(`dns/list`, &dnsdomains); err != nil {
		return nil, err
	}
	return dnsdomains, nil
}

// GetDNSRecords returns a list of all DNS records of a particular domain
func (c *Client) GetDNSRecords(domain string) (dnsrecords []DNSRecord, err error) {
	if err := c.get(`dns/records?domain=`+domain, &dnsrecords); err != nil {
		return nil, err
	}
	return dnsrecords, nil
}

// CreateDNSDomain creates a new DNS domain name on Vultr
func (c *Client) CreateDNSDomain(domain, serverIP string) error {
	values := url.Values{
		"domain":   {domain},
		"serverIP": {serverIP},
	}

	if err := c.post(`dns/create_domain`, values, nil); err != nil {
		return err
	}
	return nil
}

// DeleteDNSDomain deletes an existing DNS domain name
func (c *Client) DeleteDNSDomain(domain string) error {
	values := url.Values{
		"domain": {domain},
	}

	if err := c.post(`dns/delete_domain`, values, nil); err != nil {
		return err
	}
	return nil
}

// CreateDNSRecord creates a new DNS record
func (c *Client) CreateDNSRecord(domain, name, rtype, data string, priority, ttl int) error {
	values := url.Values{
		"domain":   {domain},
		"name":     {name},
		"type":     {rtype},
		"data":     {data},
		"priority": {fmt.Sprintf("%v", priority)},
		"ttl":      {fmt.Sprintf("%v", ttl)},
	}

	if err := c.post(`dns/create_record`, values, nil); err != nil {
		return err
	}
	return nil
}

// UpdateDNSRecord updates an existing DNS record
func (c *Client) UpdateDNSRecord(domain string, dnsrecord DNSRecord) error {
	values := url.Values{
		"domain":   {domain},
		"RECORDID": {fmt.Sprintf("%v", dnsrecord.RecordID)},
	}

	if dnsrecord.Name != "" {
		values.Add("name", dnsrecord.Name)
	}
	if dnsrecord.Data != "" {
		values.Add("data", dnsrecord.Data)
	}
	if dnsrecord.Priority != 0 {
		values.Add("priority", fmt.Sprintf("%v", dnsrecord.Priority))
	}
	if dnsrecord.TTL != 0 {
		values.Add("ttl", fmt.Sprintf("%v", dnsrecord.TTL))
	}

	if err := c.post(`dns/update_record`, values, nil); err != nil {
		return err
	}
	return nil
}

// DeleteDNSRecord deletes an existing DNS record
func (c *Client) DeleteDNSRecord(domain string, recordID int) error {
	values := url.Values{
		"domain":   {domain},
		"RECORDID": {fmt.Sprintf("%v", recordID)},
	}

	if err := c.post(`dns/delete_record`, values, nil); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package token

import (
	"testing"

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

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

	type tokens struct {
		userSource   TokenSource
		user         string
		agent        string
		agentSource  TokenSource
		master       string
		masterSource TokenSource
		repl         string
		replSource   TokenSource
	}

	tests := []struct {
		name      string
		set       tokens
		raw       tokens
		effective tokens
	}{
		{
			name:      "set user - config",
			set:       tokens{user: "U", userSource: TokenSourceConfig},
			raw:       tokens{user: "U", userSource: TokenSourceConfig},
			effective: tokens{user: "U", agent: "U"},
		},
		{
			name:      "set user - api",
			set:       tokens{user: "U", userSource: TokenSourceAPI},
			raw:       tokens{user: "U", userSource: TokenSourceAPI},
			effective: tokens{user: "U", agent: "U"},
		},
		{
			name:      "set agent - config",
			set:       tokens{agent: "A", agentSource: TokenSourceConfig},
			raw:       tokens{agent: "A", agentSource: TokenSourceConfig},
			effective: tokens{agent: "A"},
		},
		{
			name:      "set agent - api",
			set:       tokens{agent: "A", agentSource: TokenSourceAPI},
			raw:       tokens{agent: "A", agentSource: TokenSourceAPI},
			effective: tokens{agent: "A"},
		},
		{
			name:      "set user and agent",
			set:       tokens{agent: "A", user: "U"},
			raw:       tokens{agent: "A", user: "U"},
			effective: tokens{agent: "A", user: "U"},
		},
		{
			name:      "set repl - config",
			set:       tokens{repl: "R", replSource: TokenSourceConfig},
			raw:       tokens{repl: "R", replSource: TokenSourceConfig},
			effective: tokens{repl: "R"},
		},
		{
			name:      "set repl - api",
			set:       tokens{repl: "R", replSource: TokenSourceAPI},
			raw:       tokens{repl: "R", replSource: TokenSourceAPI},
			effective: tokens{repl: "R"},
		},
		{
			name:      "set master - config",
			set:       tokens{master: "M", masterSource: TokenSourceConfig},
			raw:       tokens{master: "M", masterSource: TokenSourceConfig},
			effective: tokens{master: "M"},
		},
		{
			name:      "set master - api",
			set:       tokens{master: "M", masterSource: TokenSourceAPI},
			raw:       tokens{master: "M", masterSource: TokenSourceAPI},
			effective: tokens{master: "M"},
		},
		{
			name:      "set all",
			set:       tokens{user: "U", agent: "A", repl: "R", master: "M"},
			raw:       tokens{user: "U", agent: "A", repl: "R", master: "M"},
			effective: tokens{user: "U", agent: "A", repl: "R", master: "M"},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()

			s := new(Store)
			require.True(t, s.UpdateUserToken(tt.set.user, tt.set.userSource))
			require.True(t, s.UpdateAgentToken(tt.set.agent, tt.set.agentSource))
			require.True(t, s.UpdateReplicationToken(tt.set.repl, tt.set.replSource))
			require.True(t, s.UpdateAgentMasterToken(tt.set.master, tt.set.masterSource))

			// If they don't change then they return false.
			require.False(t, s.UpdateUserToken(tt.set.user, tt.set.userSource))
			require.False(t, s.UpdateAgentToken(tt.set.agent, tt.set.agentSource))
			require.False(t, s.UpdateReplicationToken(tt.set.repl, tt.set.replSource))
			require.False(t, s.UpdateAgentMasterToken(tt.set.master, tt.set.masterSource))

			require.Equal(t, tt.effective.user, s.UserToken())
			require.Equal(t, tt.effective.agent, s.AgentToken())
			require.Equal(t, tt.effective.master, s.AgentMasterToken())
			require.Equal(t, tt.effective.repl, s.ReplicationToken())

			tok, src := s.UserTokenAndSource()
			require.Equal(t, tt.raw.user, tok)
			require.Equal(t, tt.raw.userSource, src)

			tok, src = s.AgentTokenAndSource()
			require.Equal(t, tt.raw.agent, tok)
			require.Equal(t, tt.raw.agentSource, src)

			tok, src = s.AgentMasterTokenAndSource()
			require.Equal(t, tt.raw.master, tok)
			require.Equal(t, tt.raw.masterSource, src)

			tok, src = s.ReplicationTokenAndSource()
			require.Equal(t, tt.raw.repl, tok)
			require.Equal(t, tt.raw.replSource, src)
		})
	}
}

func TestStore_AgentMasterToken(t *testing.T) {
	t.Parallel()
	s := new(Store)

	verify := func(want bool, toks ...string) {
		for _, tok := range toks {
			require.Equal(t, want, s.IsAgentMasterToken(tok))
		}
	}

	verify(false, "", "nope")

	s.UpdateAgentMasterToken("master", TokenSourceConfig)
	verify(true, "master")
	verify(false, "", "nope")

	s.UpdateAgentMasterToken("another", TokenSourceConfig)
	verify(true, "another")
	verify(false, "", "nope", "master")

	s.UpdateAgentMasterToken("", TokenSourceConfig)
	verify(false, "", "nope", "master", "another")
}

func TestStore_Notify(t *testing.T) {
	t.Parallel()
	s := new(Store)

	newNotification := func(t *testing.T, s *Store, kind TokenKind) Notifier {
		n := s.Notify(kind)
		require.NotNil(t, n.Ch)
		return n
	}

	requireNotNotified := func(t *testing.T, ch <-chan struct{}) {
		require.Empty(t, ch)
	}

	requireNotifiedOnce := func(t *testing.T, ch <-chan struct{}) {
		require.Len(t, ch, 1)
		// drain the channel
		<-ch
		// just to be safe
		require.Empty(t, ch)
	}

	agentNotifier := newNotification(t, s, TokenKindAgent)
	userNotifier := newNotification(t, s, TokenKindUser)
	agentMasterNotifier := newNotification(t, s, TokenKindAgentMaster)
	replicationNotifier := newNotification(t, s, TokenKindReplication)
	replicationNotifier2 := newNotification(t, s, TokenKindReplication)

	// perform an update of the user token
	require.True(t, s.UpdateUserToken("edcae2a2-3b51-4864-b412-c7a568f49cb1", TokenSourceConfig))
	// do it again to ensure it doesn't block even though nothing has read from the 1 buffered chan yet
	require.True(t, s.UpdateUserToken("47788919-f944-476a-bda5-446d64be1df8", TokenSourceAPI))

	// ensure notifications were sent to the user and all notifiers
	requireNotNotified(t, agentNotifier.Ch)
	requireNotifiedOnce(t, userNotifier.Ch)
	requireNotNotified(t, replicationNotifier.Ch)
	requireNotNotified(t, agentMasterNotifier.Ch)
	requireNotNotified(t, replicationNotifier2.Ch)

	// now update the agent token which should send notificaitons to the agent and all notifier
	require.True(t, s.UpdateAgentToken("5d748ec2-d536-461f-8e2a-1f7eae98d559", TokenSourceAPI))

	requireNotifiedOnce(t, agentNotifier.Ch)
	requireNotNotified(t, userNotifier.Ch)
	requireNotNotified(t, replicationNotifier.Ch)
	requireNotNotified(t, agentMasterNotifier.Ch)
	requireNotNotified(t, replicationNotifier2.Ch)

	// now update the agent master token which should send notificaitons to the agent master and all notifier
	require.True(t, s.UpdateAgentMasterToken("789badc8-f850-43e1-8742-9b9f484957cc", TokenSourceAPI))

	requireNotNotified(t, agentNotifier.Ch)
	requireNotNotified(t, userNotifier.Ch)
	requireNotNotified(t, replicationNotifier.Ch)
	requireNotifiedOnce(t, agentMasterNotifier.Ch)
	requireNotNotified(t, replicationNotifier2.Ch)

	// now update the replication token which should send notificaitons to the replication and all notifier
	require.True(t, s.UpdateReplicationToken("789badc8-f850-43e1-8742-9b9f484957cc", TokenSourceAPI))

	requireNotNotified(t, agentNotifier.Ch)
	requireNotNotified(t, userNotifier.Ch)
	requireNotifiedOnce(t, replicationNotifier.Ch)
	requireNotNotified(t, agentMasterNotifier.Ch)
	requireNotifiedOnce(t, replicationNotifier2.Ch)

	s.StopNotify(replicationNotifier2)

	// now update the replication token which should send notificaitons to the replication and all notifier
	require.True(t, s.UpdateReplicationToken("eb0b56b9-fa65-4ae1-902a-c64457c62ac6", TokenSourceAPI))

	requireNotNotified(t, agentNotifier.Ch)
	requireNotNotified(t, userNotifier.Ch)
	requireNotifiedOnce(t, replicationNotifier.Ch)
	requireNotNotified(t, agentMasterNotifier.Ch)
	requireNotNotified(t, replicationNotifier2.Ch)

	// request updates but that are not changes
	require.False(t, s.UpdateAgentToken("5d748ec2-d536-461f-8e2a-1f7eae98d559", TokenSourceAPI))
	require.False(t, s.UpdateAgentMasterToken("789badc8-f850-43e1-8742-9b9f484957cc", TokenSourceAPI))
	require.False(t, s.UpdateUserToken("47788919-f944-476a-bda5-446d64be1df8", TokenSourceAPI))
	require.False(t, s.UpdateReplicationToken("eb0b56b9-fa65-4ae1-902a-c64457c62ac6", TokenSourceAPI))

	// ensure that notifications were not sent
	requireNotNotified(t, agentNotifier.Ch)
	requireNotNotified(t, userNotifier.Ch)
	requireNotNotified(t, replicationNotifier.Ch)
	requireNotNotified(t, agentMasterNotifier.Ch)
}
<commit_msg>fix TestStore_RegularTokens<commit_after>package token

import (
	"testing"

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

func TestStore_RegularTokens(t *testing.T) {
	type tokens struct {
		userSource   TokenSource
		user         string
		agent        string
		agentSource  TokenSource
		master       string
		masterSource TokenSource
		repl         string
		replSource   TokenSource
	}

	tests := []struct {
		name      string
		set       tokens
		raw       tokens
		effective tokens
	}{
		{
			name:      "set user - config",
			set:       tokens{user: "U", userSource: TokenSourceConfig},
			raw:       tokens{user: "U", userSource: TokenSourceConfig},
			effective: tokens{user: "U", agent: "U"},
		},
		{
			name:      "set user - api",
			set:       tokens{user: "U", userSource: TokenSourceAPI},
			raw:       tokens{user: "U", userSource: TokenSourceAPI},
			effective: tokens{user: "U", agent: "U"},
		},
		{
			name:      "set agent - config",
			set:       tokens{agent: "A", agentSource: TokenSourceConfig},
			raw:       tokens{agent: "A", agentSource: TokenSourceConfig},
			effective: tokens{agent: "A"},
		},
		{
			name:      "set agent - api",
			set:       tokens{agent: "A", agentSource: TokenSourceAPI},
			raw:       tokens{agent: "A", agentSource: TokenSourceAPI},
			effective: tokens{agent: "A"},
		},
		{
			name:      "set user and agent",
			set:       tokens{agent: "A", user: "U"},
			raw:       tokens{agent: "A", user: "U"},
			effective: tokens{agent: "A", user: "U"},
		},
		{
			name:      "set repl - config",
			set:       tokens{repl: "R", replSource: TokenSourceConfig},
			raw:       tokens{repl: "R", replSource: TokenSourceConfig},
			effective: tokens{repl: "R"},
		},
		{
			name:      "set repl - api",
			set:       tokens{repl: "R", replSource: TokenSourceAPI},
			raw:       tokens{repl: "R", replSource: TokenSourceAPI},
			effective: tokens{repl: "R"},
		},
		{
			name:      "set master - config",
			set:       tokens{master: "M", masterSource: TokenSourceConfig},
			raw:       tokens{master: "M", masterSource: TokenSourceConfig},
			effective: tokens{master: "M"},
		},
		{
			name:      "set master - api",
			set:       tokens{master: "M", masterSource: TokenSourceAPI},
			raw:       tokens{master: "M", masterSource: TokenSourceAPI},
			effective: tokens{master: "M"},
		},
		{
			name:      "set all",
			set:       tokens{user: "U", agent: "A", repl: "R", master: "M"},
			raw:       tokens{user: "U", agent: "A", repl: "R", master: "M"},
			effective: tokens{user: "U", agent: "A", repl: "R", master: "M"},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			s := new(Store)
			if tt.set.user != "" {
				require.True(t, s.UpdateUserToken(tt.set.user, tt.set.userSource))
			}

			if tt.set.agent != "" {
				require.True(t, s.UpdateAgentToken(tt.set.agent, tt.set.agentSource))
			}

			if tt.set.repl != "" {
				require.True(t, s.UpdateReplicationToken(tt.set.repl, tt.set.replSource))
			}

			if tt.set.master != "" {
				require.True(t, s.UpdateAgentMasterToken(tt.set.master, tt.set.masterSource))
			}

			// If they don't change then they return false.
			require.False(t, s.UpdateUserToken(tt.set.user, tt.set.userSource))
			require.False(t, s.UpdateAgentToken(tt.set.agent, tt.set.agentSource))
			require.False(t, s.UpdateReplicationToken(tt.set.repl, tt.set.replSource))
			require.False(t, s.UpdateAgentMasterToken(tt.set.master, tt.set.masterSource))

			require.Equal(t, tt.effective.user, s.UserToken())
			require.Equal(t, tt.effective.agent, s.AgentToken())
			require.Equal(t, tt.effective.master, s.AgentMasterToken())
			require.Equal(t, tt.effective.repl, s.ReplicationToken())

			tok, src := s.UserTokenAndSource()
			require.Equal(t, tt.raw.user, tok)
			require.Equal(t, tt.raw.userSource, src)

			tok, src = s.AgentTokenAndSource()
			require.Equal(t, tt.raw.agent, tok)
			require.Equal(t, tt.raw.agentSource, src)

			tok, src = s.AgentMasterTokenAndSource()
			require.Equal(t, tt.raw.master, tok)
			require.Equal(t, tt.raw.masterSource, src)

			tok, src = s.ReplicationTokenAndSource()
			require.Equal(t, tt.raw.repl, tok)
			require.Equal(t, tt.raw.replSource, src)
		})
	}
}

func TestStore_AgentMasterToken(t *testing.T) {
	s := new(Store)

	verify := func(want bool, toks ...string) {
		for _, tok := range toks {
			require.Equal(t, want, s.IsAgentMasterToken(tok))
		}
	}

	verify(false, "", "nope")

	s.UpdateAgentMasterToken("master", TokenSourceConfig)
	verify(true, "master")
	verify(false, "", "nope")

	s.UpdateAgentMasterToken("another", TokenSourceConfig)
	verify(true, "another")
	verify(false, "", "nope", "master")

	s.UpdateAgentMasterToken("", TokenSourceConfig)
	verify(false, "", "nope", "master", "another")
}

func TestStore_Notify(t *testing.T) {
	s := new(Store)

	newNotification := func(t *testing.T, s *Store, kind TokenKind) Notifier {
		n := s.Notify(kind)
		require.NotNil(t, n.Ch)
		return n
	}

	requireNotNotified := func(t *testing.T, ch <-chan struct{}) {
		require.Empty(t, ch)
	}

	requireNotifiedOnce := func(t *testing.T, ch <-chan struct{}) {
		require.Len(t, ch, 1)
		// drain the channel
		<-ch
		// just to be safe
		require.Empty(t, ch)
	}

	agentNotifier := newNotification(t, s, TokenKindAgent)
	userNotifier := newNotification(t, s, TokenKindUser)
	agentMasterNotifier := newNotification(t, s, TokenKindAgentMaster)
	replicationNotifier := newNotification(t, s, TokenKindReplication)
	replicationNotifier2 := newNotification(t, s, TokenKindReplication)

	// perform an update of the user token
	require.True(t, s.UpdateUserToken("edcae2a2-3b51-4864-b412-c7a568f49cb1", TokenSourceConfig))
	// do it again to ensure it doesn't block even though nothing has read from the 1 buffered chan yet
	require.True(t, s.UpdateUserToken("47788919-f944-476a-bda5-446d64be1df8", TokenSourceAPI))

	// ensure notifications were sent to the user and all notifiers
	requireNotNotified(t, agentNotifier.Ch)
	requireNotifiedOnce(t, userNotifier.Ch)
	requireNotNotified(t, replicationNotifier.Ch)
	requireNotNotified(t, agentMasterNotifier.Ch)
	requireNotNotified(t, replicationNotifier2.Ch)

	// now update the agent token which should send notificaitons to the agent and all notifier
	require.True(t, s.UpdateAgentToken("5d748ec2-d536-461f-8e2a-1f7eae98d559", TokenSourceAPI))

	requireNotifiedOnce(t, agentNotifier.Ch)
	requireNotNotified(t, userNotifier.Ch)
	requireNotNotified(t, replicationNotifier.Ch)
	requireNotNotified(t, agentMasterNotifier.Ch)
	requireNotNotified(t, replicationNotifier2.Ch)

	// now update the agent master token which should send notificaitons to the agent master and all notifier
	require.True(t, s.UpdateAgentMasterToken("789badc8-f850-43e1-8742-9b9f484957cc", TokenSourceAPI))

	requireNotNotified(t, agentNotifier.Ch)
	requireNotNotified(t, userNotifier.Ch)
	requireNotNotified(t, replicationNotifier.Ch)
	requireNotifiedOnce(t, agentMasterNotifier.Ch)
	requireNotNotified(t, replicationNotifier2.Ch)

	// now update the replication token which should send notificaitons to the replication and all notifier
	require.True(t, s.UpdateReplicationToken("789badc8-f850-43e1-8742-9b9f484957cc", TokenSourceAPI))

	requireNotNotified(t, agentNotifier.Ch)
	requireNotNotified(t, userNotifier.Ch)
	requireNotifiedOnce(t, replicationNotifier.Ch)
	requireNotNotified(t, agentMasterNotifier.Ch)
	requireNotifiedOnce(t, replicationNotifier2.Ch)

	s.StopNotify(replicationNotifier2)

	// now update the replication token which should send notificaitons to the replication and all notifier
	require.True(t, s.UpdateReplicationToken("eb0b56b9-fa65-4ae1-902a-c64457c62ac6", TokenSourceAPI))

	requireNotNotified(t, agentNotifier.Ch)
	requireNotNotified(t, userNotifier.Ch)
	requireNotifiedOnce(t, replicationNotifier.Ch)
	requireNotNotified(t, agentMasterNotifier.Ch)
	requireNotNotified(t, replicationNotifier2.Ch)

	// request updates but that are not changes
	require.False(t, s.UpdateAgentToken("5d748ec2-d536-461f-8e2a-1f7eae98d559", TokenSourceAPI))
	require.False(t, s.UpdateAgentMasterToken("789badc8-f850-43e1-8742-9b9f484957cc", TokenSourceAPI))
	require.False(t, s.UpdateUserToken("47788919-f944-476a-bda5-446d64be1df8", TokenSourceAPI))
	require.False(t, s.UpdateReplicationToken("eb0b56b9-fa65-4ae1-902a-c64457c62ac6", TokenSourceAPI))

	// ensure that notifications were not sent
	requireNotNotified(t, agentNotifier.Ch)
	requireNotNotified(t, userNotifier.Ch)
	requireNotNotified(t, replicationNotifier.Ch)
	requireNotNotified(t, agentMasterNotifier.Ch)
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcchain

import (
	"fmt"
	"github.com/conformal/btcutil"
	"github.com/conformal/btcwire"
)

// RuleError identifies a rule violation.  It is used to indicate that
// processing of a block or transaction failed due to one of the many validation
// rules.  The caller can use type assertions to determine if a failure was
// specifically due to a rule violation.
type RuleError string

// Error satisfies the error interface to print human-readable errors.
func (e RuleError) Error() string {
	return string(e)
}

// blockExists determines whether a block with the given hash exists either in
// the main chain or any side chains.
func (b *BlockChain) blockExists(hash *btcwire.ShaHash) bool {
	// Check memory chain first (could be main chain or side chain blocks).
	if _, ok := b.index[*hash]; ok {
		return true
	}

	// Check in database (rest of main chain not in memory).
	return b.db.ExistsSha(hash)
}

// processOrphans determines if there are any orphans which depend on the passed
// block hash (they are no longer orphans if true) and potentially accepts them.
// It repeats the process for the newly accepted blocks (to detect further
// orphans which may no longer be orphans) until there are no more.
func (b *BlockChain) processOrphans(hash *btcwire.ShaHash) error {
	// Start with processing at least the passed hash.  Leave a little room
	// for additional orphan blocks that need to be processed without
	// needing to grow the array in the common case.
	processHashes := make([]*btcwire.ShaHash, 0, 10)
	processHashes = append(processHashes, hash)
	for len(processHashes) > 0 {
		// Pop the first hash to process from the slice.
		processHash := processHashes[0]
		processHashes[0] = nil // Prevent GC leak.
		processHashes = processHashes[1:]

		// Look up all orphans that are parented by the block we just
		// accepted.  This will typically only be one, but it could
		// be multiple if multiple blocks are mined and broadcast
		// around the same time.  The one with the most proof of work
		// will eventually win out.
		for _, orphan := range b.prevOrphans[*processHash] {
			// Remove the orphan from the orphan pool.
			// It's safe to ignore the error on Sha since the hash
			// is already cached.
			orphanHash, _ := orphan.block.Sha()
			b.removeOrphanBlock(orphan)

			// Potentially accept the block into the block chain.
			err := b.maybeAcceptBlock(orphan.block)
			if err != nil {
				return err
			}

			// Add this block to the list of blocks to process so
			// any orphan blocks that depend on this block are
			// handled too.
			processHashes = append(processHashes, orphanHash)
		}
	}
	return nil
}

// ProcessBlock is the main workhorse for handling insertion of new blocks into
// the block chain.  It includes functionality such as rejecting duplicate
// blocks, ensuring blocks follow all rules, orphan handling, and insertion into
// the block chain along with best chain selection and reorganization.
func (b *BlockChain) ProcessBlock(block *btcutil.Block) error {
	blockHash, err := block.Sha()
	if err != nil {
		return err
	}
	log.Tracef("Processing block %v", blockHash)

	// The block must not already exist in the main chain or side chains.
	if b.blockExists(blockHash) {
		str := fmt.Sprintf("already have block %v", blockHash)
		return RuleError(str)
	}

	// The block must not already exist as an orphan.
	if _, exists := b.orphans[*blockHash]; exists {
		str := fmt.Sprintf("already have block (orphan) %v", blockHash)
		return RuleError(str)
	}

	// Perform preliminary sanity checks on the block and its transactions.
	err = b.checkBlockSanity(block)
	if err != nil {
		return err
	}

	// Find the latest known checkpoint and perform some additional checks
	// based on the checkpoint.  This provides a few nice properties such as
	// preventing forks from blocks before the last checkpoint, rejecting
	// easy to mine, but otherwise bogus, blocks that could be used to eat
	// memory, and ensuring expected (versus claimed) proof of work
	// requirements since the last checkpoint are met.
	blockHeader := block.MsgBlock().Header
	checkpointBlock, err := b.findLatestKnownCheckpoint()
	if err != nil {
		return err
	}
	if checkpointBlock != nil {
		// Ensure the block timestamp is after the checkpoint timestamp.
		checkpointHeader := checkpointBlock.MsgBlock().Header
		checkpointTime := checkpointHeader.Timestamp
		if blockHeader.Timestamp.Before(checkpointTime) {
			str := fmt.Sprintf("block %v has timestamp %v before "+
				"last checkpoint timestamp %v", blockHash,
				blockHeader.Timestamp, checkpointTime)
			return RuleError(str)
		}

		// Even though the checks prior to now have already ensured the
		// proof of work exceeds the claimed amount, the claimed amount
		// is a field in the block header which could be forged.  This
		// check ensures the proof of work is at least the minimum
		// expected based on elapsed time since the last checkpoint and
		// maximum adjustment allowed by the retarget rules.
		duration := blockHeader.Timestamp.Sub(checkpointTime)
		requiredTarget := CompactToBig(b.calcEasiestDifficulty(
			checkpointHeader.Bits, duration))
		currentTarget := CompactToBig(blockHeader.Bits)
		if currentTarget.Cmp(requiredTarget) > 0 {
			str := fmt.Sprintf("block target difficulty of %064x "+
				"is too low when compared to the previous "+
				"checkpoint", currentTarget)
			return RuleError(str)
		}
	}

	// Handle orphan blocks.
	prevHash := &blockHeader.PrevBlock
	if !prevHash.IsEqual(zeroHash) && !b.blockExists(prevHash) {
		// Add the orphan block to the orphan pool.
		log.Infof("Adding orphan block %v with parent %v", blockHash,
			prevHash)
		b.addOrphanBlock(block)

		// Notify the caller so it can request missing blocks.
		b.sendNotification(NTOrphanBlock, blockHash)
		return nil
	}

	// The block has passed all context independent checks and appears sane
	// enough to potentially accept it into the block chain.
	err = b.maybeAcceptBlock(block)
	if err != nil {
		return err
	}

	// Accept any orphan blocks that depend on this block (they are no
	// longer orphans) and repeat for those accepted blocks until there are
	// no more.
	err = b.processOrphans(blockHash)
	if err != nil {
		return err
	}

	log.Debugf("Accepted block %v", blockHash)
	return nil
}
<commit_msg>Fix potential issue with dependent orphans.<commit_after>// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcchain

import (
	"fmt"
	"github.com/conformal/btcutil"
	"github.com/conformal/btcwire"
)

// RuleError identifies a rule violation.  It is used to indicate that
// processing of a block or transaction failed due to one of the many validation
// rules.  The caller can use type assertions to determine if a failure was
// specifically due to a rule violation.
type RuleError string

// Error satisfies the error interface to print human-readable errors.
func (e RuleError) Error() string {
	return string(e)
}

// blockExists determines whether a block with the given hash exists either in
// the main chain or any side chains.
func (b *BlockChain) blockExists(hash *btcwire.ShaHash) bool {
	// Check memory chain first (could be main chain or side chain blocks).
	if _, ok := b.index[*hash]; ok {
		return true
	}

	// Check in database (rest of main chain not in memory).
	return b.db.ExistsSha(hash)
}

// processOrphans determines if there are any orphans which depend on the passed
// block hash (they are no longer orphans if true) and potentially accepts them.
// It repeats the process for the newly accepted blocks (to detect further
// orphans which may no longer be orphans) until there are no more.
func (b *BlockChain) processOrphans(hash *btcwire.ShaHash) error {
	// Start with processing at least the passed hash.  Leave a little room
	// for additional orphan blocks that need to be processed without
	// needing to grow the array in the common case.
	processHashes := make([]*btcwire.ShaHash, 0, 10)
	processHashes = append(processHashes, hash)
	for len(processHashes) > 0 {
		// Pop the first hash to process from the slice.
		processHash := processHashes[0]
		processHashes[0] = nil // Prevent GC leak.
		processHashes = processHashes[1:]

		// Look up all orphans that are parented by the block we just
		// accepted.  This will typically only be one, but it could
		// be multiple if multiple blocks are mined and broadcast
		// around the same time.  The one with the most proof of work
		// will eventually win out.  An indexing for loop is
		// intentionally used over a range here as range does not
		// reevaluate the slice on each iteration nor does it adjust the
		// index for the modified slice.
		for i := 0; i < len(b.prevOrphans[*processHash]); i++ {
			orphan := b.prevOrphans[*processHash][i]
			if orphan == nil {
				log.Warnf("Found a nil entry at index %d in the "+
					"orphan dependency list for block %v", i,
					processHash)
				continue
			}

			// Remove the orphan from the orphan pool.
			// It's safe to ignore the error on Sha since the hash
			// is already cached.
			orphanHash, _ := orphan.block.Sha()
			b.removeOrphanBlock(orphan)
			i--

			// Potentially accept the block into the block chain.
			err := b.maybeAcceptBlock(orphan.block)
			if err != nil {
				return err
			}

			// Add this block to the list of blocks to process so
			// any orphan blocks that depend on this block are
			// handled too.
			processHashes = append(processHashes, orphanHash)
		}
	}
	return nil
}

// ProcessBlock is the main workhorse for handling insertion of new blocks into
// the block chain.  It includes functionality such as rejecting duplicate
// blocks, ensuring blocks follow all rules, orphan handling, and insertion into
// the block chain along with best chain selection and reorganization.
func (b *BlockChain) ProcessBlock(block *btcutil.Block) error {
	blockHash, err := block.Sha()
	if err != nil {
		return err
	}
	log.Tracef("Processing block %v", blockHash)

	// The block must not already exist in the main chain or side chains.
	if b.blockExists(blockHash) {
		str := fmt.Sprintf("already have block %v", blockHash)
		return RuleError(str)
	}

	// The block must not already exist as an orphan.
	if _, exists := b.orphans[*blockHash]; exists {
		str := fmt.Sprintf("already have block (orphan) %v", blockHash)
		return RuleError(str)
	}

	// Perform preliminary sanity checks on the block and its transactions.
	err = b.checkBlockSanity(block)
	if err != nil {
		return err
	}

	// Find the latest known checkpoint and perform some additional checks
	// based on the checkpoint.  This provides a few nice properties such as
	// preventing forks from blocks before the last checkpoint, rejecting
	// easy to mine, but otherwise bogus, blocks that could be used to eat
	// memory, and ensuring expected (versus claimed) proof of work
	// requirements since the last checkpoint are met.
	blockHeader := block.MsgBlock().Header
	checkpointBlock, err := b.findLatestKnownCheckpoint()
	if err != nil {
		return err
	}
	if checkpointBlock != nil {
		// Ensure the block timestamp is after the checkpoint timestamp.
		checkpointHeader := checkpointBlock.MsgBlock().Header
		checkpointTime := checkpointHeader.Timestamp
		if blockHeader.Timestamp.Before(checkpointTime) {
			str := fmt.Sprintf("block %v has timestamp %v before "+
				"last checkpoint timestamp %v", blockHash,
				blockHeader.Timestamp, checkpointTime)
			return RuleError(str)
		}

		// Even though the checks prior to now have already ensured the
		// proof of work exceeds the claimed amount, the claimed amount
		// is a field in the block header which could be forged.  This
		// check ensures the proof of work is at least the minimum
		// expected based on elapsed time since the last checkpoint and
		// maximum adjustment allowed by the retarget rules.
		duration := blockHeader.Timestamp.Sub(checkpointTime)
		requiredTarget := CompactToBig(b.calcEasiestDifficulty(
			checkpointHeader.Bits, duration))
		currentTarget := CompactToBig(blockHeader.Bits)
		if currentTarget.Cmp(requiredTarget) > 0 {
			str := fmt.Sprintf("block target difficulty of %064x "+
				"is too low when compared to the previous "+
				"checkpoint", currentTarget)
			return RuleError(str)
		}
	}

	// Handle orphan blocks.
	prevHash := &blockHeader.PrevBlock
	if !prevHash.IsEqual(zeroHash) && !b.blockExists(prevHash) {
		// Add the orphan block to the orphan pool.
		log.Infof("Adding orphan block %v with parent %v", blockHash,
			prevHash)
		b.addOrphanBlock(block)

		// Notify the caller so it can request missing blocks.
		b.sendNotification(NTOrphanBlock, blockHash)
		return nil
	}

	// The block has passed all context independent checks and appears sane
	// enough to potentially accept it into the block chain.
	err = b.maybeAcceptBlock(block)
	if err != nil {
		return err
	}

	// Accept any orphan blocks that depend on this block (they are no
	// longer orphans) and repeat for those accepted blocks until there are
	// no more.
	err = b.processOrphans(blockHash)
	if err != nil {
		return err
	}

	log.Debugf("Accepted block %v", blockHash)
	return nil
}
<|endoftext|>


<commit_before>package xbl

import (
	"fmt"
	"strconv"
)

// Profile describe's a gamer's Xbox Live account.
type Profile struct {
	ID             string `json:"-"`
	Gamertag       string `json:"Gamertag"`
	Gamerscore     int    `json:"Gamerscore"`
	GamerPicture   string `json:"GameDisplayPicRaw"`
	AccountTier    string `json:"AccountTier"`
	Reputation     string `json:"XboxOneRep"`
	PreferredColor string `json:"PreferredColor"`
	Tenure         int    `json:"TenureLevel"`
}

// Profile retrieves the profile for a user with the provided ID.
func (c *Client) Profile(userID string) (*Profile, error) {
	const url = "https://profile.xboxlive.com/users/batch/profile/settings"

	req := struct {
		Settings []string `json:"settings"`
		UserIDs  []string `json:"userIds"`
	}{
		Settings: []string{
			"Gamerscore", "Gamertag", "GameDisplayPicRaw", "AccountTier",
			"XboxOneRep", "PreferredColor", "TenureLevel",
		},
		UserIDs: []string{userID},
	}

	var resp struct {
		ProfileUsers []struct {
			ID       string              `json:"id"`
			Settings []map[string]string `json:"settings"`
		} `json:"profileUsers"`
	}
	err := c.post(url, vXboxOne, req, &resp)
	if err != nil {
		return nil, err
	}
	if len(resp.ProfileUsers) == 0 {
		return nil, fmt.Errorf("user id %s not found", userID)
	}
	m := map[string]string{}
	for _, setting := range resp.ProfileUsers[0].Settings {
		m[setting["id"]] = setting["value"]
	}
	tenure, err := strconv.Atoi(m["TenureLevel"])
	if err != nil {
		return nil, err
	}
	gamerscore, err := strconv.Atoi(m["Gamerscore"])
	if err != nil {
		return nil, err
	}

	return &Profile{
		ID:             userID,
		Gamertag:       m["Gamertag"],
		Gamerscore:     gamerscore,
		GamerPicture:   m["GameDisplayPicRaw"],
		AccountTier:    m["AccountTier"],
		Reputation:     m["XboxOneRep"],
		PreferredColor: m["PreferredColor"],
		Tenure:         tenure,
	}, nil
}
<commit_msg>fix json tags<commit_after>package xbl

import (
	"fmt"
	"strconv"
)

// Profile describe's a gamer's Xbox Live account.
type Profile struct {
	ID             string `json:"-"`
	Gamertag       string `json:"gamertag"`
	Gamerscore     int    `json:"gamerscore"`
	GamerPicture   string `json:"gamer_picture"`
	AccountTier    string `json:"account_tier"`
	Reputation     string `json:"reputation"`
	PreferredColor string `json:"preferred_color"`
	Tenure         int    `json:"tenure_level"`
}

// Profile retrieves the profile for a user with the provided ID.
func (c *Client) Profile(userID string) (*Profile, error) {
	const url = "https://profile.xboxlive.com/users/batch/profile/settings"

	req := struct {
		Settings []string `json:"settings"`
		UserIDs  []string `json:"userIds"`
	}{
		Settings: []string{
			"Gamerscore", "Gamertag", "GameDisplayPicRaw", "AccountTier",
			"XboxOneRep", "PreferredColor", "TenureLevel",
		},
		UserIDs: []string{userID},
	}

	var resp struct {
		ProfileUsers []struct {
			ID       string              `json:"id"`
			Settings []map[string]string `json:"settings"`
		} `json:"profileUsers"`
	}
	err := c.post(url, vXboxOne, req, &resp)
	if err != nil {
		return nil, err
	}
	if len(resp.ProfileUsers) == 0 {
		return nil, fmt.Errorf("user id %s not found", userID)
	}
	m := map[string]string{}
	for _, setting := range resp.ProfileUsers[0].Settings {
		m[setting["id"]] = setting["value"]
	}
	tenure, err := strconv.Atoi(m["TenureLevel"])
	if err != nil {
		return nil, err
	}
	gamerscore, err := strconv.Atoi(m["Gamerscore"])
	if err != nil {
		return nil, err
	}

	return &Profile{
		ID:             userID,
		Gamertag:       m["Gamertag"],
		Gamerscore:     gamerscore,
		GamerPicture:   m["GameDisplayPicRaw"],
		AccountTier:    m["AccountTier"],
		Reputation:     m["XboxOneRep"],
		PreferredColor: m["PreferredColor"],
		Tenure:         tenure,
	}, nil
}
<|endoftext|>


<commit_before>package histogram

import (
	"testing"
	"math/rand"
)

func BenchmarkInsert10Bins(b *testing.B) {
	b.StopTimer()
	h := New(10)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		f := rand.ExpFloat64()
		h.Insert(f)
	}
}

func BenchmarkInsert100Bins(b *testing.B) {
	b.StopTimer()
	h := New(100)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		f := rand.ExpFloat64()
		h.Insert(f)
	}
}
<commit_msg>go fmt<commit_after>package histogram

import (
	"math/rand"
	"testing"
)

func BenchmarkInsert10Bins(b *testing.B) {
	b.StopTimer()
	h := New(10)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		f := rand.ExpFloat64()
		h.Insert(f)
	}
}

func BenchmarkInsert100Bins(b *testing.B) {
	b.StopTimer()
	h := New(100)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		f := rand.ExpFloat64()
		h.Insert(f)
	}
}
<|endoftext|>


<commit_before>package history

import (
	"bytes"
	"strings"
	"testing"
)

type history_t struct {
	List []string
}

func (this *history_t) Len() int {
	return len(this.List)
}

func (this *history_t) At(n int) string {
	return this.List[n]
}

func (this *history_t) Push(line string) {
	this.List = append(this.List, line)
}

func TestReplace(t *testing.T) {
	testdata := &history_t{
		List: []string{
			"aaa0 aaa1 aaa2",
			"bbb0 bbb1 bbb2",
			"ccc0 ccc1 ccc2",
		},
	}

	if testdata.Len() != 3 {
		t.Fail()
	}

	if testdata.At(1) != "bbb0 bbb1 bbb2" {
		t.Fail()
	}

	testdata.Push("xxxxx")
	if testdata.At(testdata.Len()-1) != "xxxxx" {
		t.Fail()
	}
	if testdata.Len() != 4 {
		t.Fail()
	}
}

func TestExpandMacro(t *testing.T) {
	var buffer strings.Builder

	ExpandMacro(&buffer, strings.NewReader("^"), "aaa bbb ccc")
	if buffer.String() != "bbb" {
		t.Fail()
		return
	}

	buffer.Reset()
	ExpandMacro(&buffer, strings.NewReader("$"), "aaa bbb ccc ddd")
	if buffer.String() != "ddd" {
		t.Fail()
		return
	}

	buffer.Reset()
	ExpandMacro(&buffer, strings.NewReader(":1"), `aaa "b bb" ccc ddd`)
	if buffer.String() != `"b bb"` {
		t.Fail()
		return
	}
}

func TestLoadFromReader(t *testing.T) {
	source := `aaaa
aaaa
bbbb
bbbb
cccc`
	hisObj := &history_t{[]string{}}
	LoadFromReader(strings.NewReader(source), hisObj)
	if hisObj.Len() != 3 || hisObj.At(0) != "aaaa" ||
		hisObj.At(1) != "bbbb" || hisObj.At(2) != "cccc" {

		t.Fail()
	}
}

func TestSaveToWriter(t *testing.T) {
	hisObj := &history_t{
		[]string{"aaaa", "bbbb", "aaaa", "dddd", "eeee"},
	}
	var buffer strings.Builder
	SaveToWriter(&buffer, hisObj)
	if buffer.String() != "bbbb\naaaa\ndddd\neeee\n" {
		t.Fail()
	}
}
<commit_msg>Fix: history's test broken.<commit_after>package history

import (
	"strings"
	"testing"
)

type history_t struct {
	List []string
}

func (this *history_t) Len() int {
	return len(this.List)
}

func (this *history_t) At(n int) string {
	return this.List[n]
}

func (this *history_t) Push(line string) {
	this.List = append(this.List, line)
}

func TestReplace(t *testing.T) {
	testdata := &history_t{
		List: []string{
			"aaa0 aaa1 aaa2",
			"bbb0 bbb1 bbb2",
			"ccc0 ccc1 ccc2",
		},
	}

	if testdata.Len() != 3 {
		t.Fail()
	}

	if testdata.At(1) != "bbb0 bbb1 bbb2" {
		t.Fail()
	}

	testdata.Push("xxxxx")
	if testdata.At(testdata.Len()-1) != "xxxxx" {
		t.Fail()
	}
	if testdata.Len() != 4 {
		t.Fail()
	}
}

func TestExpandMacro(t *testing.T) {
	var buffer strings.Builder

	ExpandMacro(&buffer, strings.NewReader("^"), "aaa bbb ccc")
	if buffer.String() != "bbb" {
		t.Fail()
		return
	}

	buffer.Reset()
	ExpandMacro(&buffer, strings.NewReader("$"), "aaa bbb ccc ddd")
	if buffer.String() != "ddd" {
		t.Fail()
		return
	}

	buffer.Reset()
	ExpandMacro(&buffer, strings.NewReader(":1"), `aaa "b bb" ccc ddd`)
	if buffer.String() != `"b bb"` {
		t.Fail()
		return
	}
}

func TestLoadFromReader(t *testing.T) {
	source := `aaaa
aaaa
bbbb
bbbb
cccc`
	hisObj := &Container{}
	hisObj.LoadViaReader(strings.NewReader(source))
	if hisObj.Len() != 3 || hisObj.At(0) != "aaaa" ||
		hisObj.At(1) != "bbbb" || hisObj.At(2) != "cccc" {

		t.Fail()
	}
}

// func TestSaveToWriter(t *testing.T) {
// 	hisObj := &Container{
// 		[]Line{
// 			{ Text:"aaaa" },
// 			{ Text:"bbbb" },
// 			{ Text:"aaaa" },
// 			{ Text:"dddd" },
// 			{ Text:"eeee" },
// 		},
// 	}
// 	var buffer strings.Builder
// 	hisObj.SaveViaWriter(&buffer)
// 	if buffer.String() != "bbbb\naaaa\ndddd\neeee\n" {
// 		println(buffer.String())
// 		t.Fail()
// 	}
// }
<|endoftext|>


<commit_before>package jira

import (
	"fmt"
)

// ProjectService handles projects for the JIRA instance / API.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project
type ProjectService struct {
	client *Client
}

// ProjectList represent a list of Projects
type ProjectList []struct {
	Expand          string          `json:"expand"`
	Self            string          `json:"self"`
	ID              string          `json:"id"`
	Key             string          `json:"key"`
	Name            string          `json:"name"`
	AvatarUrls      AvatarUrls      `json:"avatarUrls"`
	ProjectTypeKey  string          `json:"projectTypeKey"`
	ProjectCategory ProjectCategory `json:"projectCategory,omitempty"`
}

// ProjectCategory represents a single project category
type ProjectCategory struct {
	Self        string `json:"self"`
	ID          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description"`
}

// Project represents a JIRA Project.
type Project struct {
	Expand       string             `json:"expand,omitempty"`
	Self         string             `json:"self,omitempty"`
	ID           string             `json:"id,omitempty"`
	Key          string             `json:"key,omitempty"`
	Description  string             `json:"description,omitempty"`
	Lead         User               `json:"lead,omitempty"`
	Components   []ProjectComponent `json:"components,omitempty"`
	IssueTypes   []IssueType        `json:"issueTypes,omitempty"`
	URL          string             `json:"url,omitempty"`
	Email        string             `json:"email,omitempty"`
	AssigneeType string             `json:"assigneeType,omitempty"`
	Versions     []interface{}      `json:"versions,omitempty"`
	Name         string             `json:"name,omitempty"`
	Roles        struct {
		Developers string `json:"Developers,omitempty"`
	} `json:"roles,omitempty"`
	AvatarUrls      AvatarUrls      `json:"avatarUrls,omitempty"`
	ProjectCategory ProjectCategory `json:"projectCategory,omitempty"`
}

// Version represents a single release version of a project
type Version struct {
	Self            string `json:"self"`
	ID              string `json:"id"`
	Name            string `json:"name"`
	Archived        bool   `json:"archived"`
	Released        bool   `json:"released"`
	ReleaseDate     string `json:"releaseDate"`
	UserReleaseDate string `json:"userReleaseDate"`
	ProjectID       int    `json:"projectId"`  // Unlike other IDs, this is returned as a number
}

// ProjectComponent represents a single component of a project
type ProjectComponent struct {
	Self                string `json:"self"`
	ID                  string `json:"id"`
	Name                string `json:"name"`
	Description         string `json:"description"`
	Lead                User   `json:"lead"`
	AssigneeType        string `json:"assigneeType"`
	Assignee            User   `json:"assignee"`
	RealAssigneeType    string `json:"realAssigneeType"`
	RealAssignee        User   `json:"realAssignee"`
	IsAssigneeTypeValid bool   `json:"isAssigneeTypeValid"`
	Project             string `json:"project"`
	ProjectID           int    `json:"projectId"`
}

// GetList gets all projects form JIRA
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getAllProjects
func (s *ProjectService) GetList() (*ProjectList, *Response, error) {
	apiEndpoint := "rest/api/2/project"
	req, err := s.client.NewRequest("GET", apiEndpoint, nil)
	if err != nil {
		return nil, nil, err
	}

	projectList := new(ProjectList)
	resp, err := s.client.Do(req, projectList)
	if err != nil {
		return nil, resp, err
	}
	return projectList, resp, nil
}

// Get returns a full representation of the project for the given issue key.
// JIRA will attempt to identify the project by the projectIdOrKey path parameter.
// This can be an project id, or an project key.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getProject
func (s *ProjectService) Get(projectID string) (*Project, *Response, error) {
	apiEndpoint := fmt.Sprintf("/rest/api/2/project/%s", projectID)
	req, err := s.client.NewRequest("GET", apiEndpoint, nil)
	if err != nil {
		return nil, nil, err
	}

	project := new(Project)
	resp, err := s.client.Do(req, project)
	if err != nil {
		return nil, resp, err
	}
	return project, resp, nil
}
<commit_msg>And it’s nice if you actually use that structure<commit_after>package jira

import (
	"fmt"
)

// ProjectService handles projects for the JIRA instance / API.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project
type ProjectService struct {
	client *Client
}

// ProjectList represent a list of Projects
type ProjectList []struct {
	Expand          string          `json:"expand"`
	Self            string          `json:"self"`
	ID              string          `json:"id"`
	Key             string          `json:"key"`
	Name            string          `json:"name"`
	AvatarUrls      AvatarUrls      `json:"avatarUrls"`
	ProjectTypeKey  string          `json:"projectTypeKey"`
	ProjectCategory ProjectCategory `json:"projectCategory,omitempty"`
}

// ProjectCategory represents a single project category
type ProjectCategory struct {
	Self        string `json:"self"`
	ID          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description"`
}

// Project represents a JIRA Project.
type Project struct {
	Expand       string             `json:"expand,omitempty"`
	Self         string             `json:"self,omitempty"`
	ID           string             `json:"id,omitempty"`
	Key          string             `json:"key,omitempty"`
	Description  string             `json:"description,omitempty"`
	Lead         User               `json:"lead,omitempty"`
	Components   []ProjectComponent `json:"components,omitempty"`
	IssueTypes   []IssueType        `json:"issueTypes,omitempty"`
	URL          string             `json:"url,omitempty"`
	Email        string             `json:"email,omitempty"`
	AssigneeType string             `json:"assigneeType,omitempty"`
	Versions     []Version      `json:"versions,omitempty"`
	Name         string             `json:"name,omitempty"`
	Roles        struct {
		Developers string `json:"Developers,omitempty"`
	} `json:"roles,omitempty"`
	AvatarUrls      AvatarUrls      `json:"avatarUrls,omitempty"`
	ProjectCategory ProjectCategory `json:"projectCategory,omitempty"`
}

// Version represents a single release version of a project
type Version struct {
	Self            string `json:"self"`
	ID              string `json:"id"`
	Name            string `json:"name"`
	Archived        bool   `json:"archived"`
	Released        bool   `json:"released"`
	ReleaseDate     string `json:"releaseDate"`
	UserReleaseDate string `json:"userReleaseDate"`
	ProjectID       int    `json:"projectId"`  // Unlike other IDs, this is returned as a number
}

// ProjectComponent represents a single component of a project
type ProjectComponent struct {
	Self                string `json:"self"`
	ID                  string `json:"id"`
	Name                string `json:"name"`
	Description         string `json:"description"`
	Lead                User   `json:"lead"`
	AssigneeType        string `json:"assigneeType"`
	Assignee            User   `json:"assignee"`
	RealAssigneeType    string `json:"realAssigneeType"`
	RealAssignee        User   `json:"realAssignee"`
	IsAssigneeTypeValid bool   `json:"isAssigneeTypeValid"`
	Project             string `json:"project"`
	ProjectID           int    `json:"projectId"`
}

// GetList gets all projects form JIRA
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getAllProjects
func (s *ProjectService) GetList() (*ProjectList, *Response, error) {
	apiEndpoint := "rest/api/2/project"
	req, err := s.client.NewRequest("GET", apiEndpoint, nil)
	if err != nil {
		return nil, nil, err
	}

	projectList := new(ProjectList)
	resp, err := s.client.Do(req, projectList)
	if err != nil {
		return nil, resp, err
	}
	return projectList, resp, nil
}

// Get returns a full representation of the project for the given issue key.
// JIRA will attempt to identify the project by the projectIdOrKey path parameter.
// This can be an project id, or an project key.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getProject
func (s *ProjectService) Get(projectID string) (*Project, *Response, error) {
	apiEndpoint := fmt.Sprintf("/rest/api/2/project/%s", projectID)
	req, err := s.client.NewRequest("GET", apiEndpoint, nil)
	if err != nil {
		return nil, nil, err
	}

	project := new(Project)
	resp, err := s.client.Do(req, project)
	if err != nil {
		return nil, resp, err
	}
	return project, resp, nil
}
<|endoftext|>