<commit_before>package customerio

import (
	"bytes"
	"context"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

const DefaultUserAgent = "Customer.io Go Client/" + Version

// CustomerIO wraps the customer.io track API, see: https://customer.io/docs/api/#apitrackintroduction
type CustomerIO struct {
	siteID    string
	apiKey    string
	URL       string
	UserAgent string
	Client    *http.Client
}

// CustomerIOError is returned by any method that fails at the API level
type CustomerIOError struct {
	status int
	url    string
	body   []byte
}

func (e *CustomerIOError) Error() string {
	return fmt.Sprintf("%v: %v %v", e.status, e.url, string(e.body))
}

// ParamError is an error returned if a parameter to the track API is invalid.
type ParamError struct {
	Param string // Param is the name of the parameter.
}

func (e ParamError) Error() string { return e.Param + ": missing" }

// NewTrackClient prepares a client for use with the Customer.io track API, see: https://customer.io/docs/api/#apitrackintroduction
// using a Tracking Site ID and API Key pair from https://fly.customer.io/settings/api_credentials
func NewTrackClient(siteID, apiKey string, opts ...option) *CustomerIO {
	client := &http.Client{
		Transport: &http.Transport{
			MaxIdleConnsPerHost: 100,
		},
	}
	c := &CustomerIO{
		siteID:    siteID,
		apiKey:    apiKey,
		URL:       "https://track.customer.io",
		UserAgent: DefaultUserAgent,
		Client:    client,
	}

	for _, opt := range opts {
		opt.track(c)
	}

	return c
}

// NewCustomerIO prepares a client for use with the Customer.io track API, see: https://customer.io/docs/api/#apitrackintroduction
// deprecated in favour of NewTrackClient
func NewCustomerIO(siteID, apiKey string) *CustomerIO {
	return NewTrackClient(siteID, apiKey)
}

// IdentifyCtx identifies a customer and sets their attributes
func (c *CustomerIO) IdentifyCtx(ctx context.Context, customerID string, attributes map[string]interface{}) error {
	if customerID == "" {
		return ParamError{Param: "customerID"}
	}
	return c.request(ctx, "PUT",
		fmt.Sprintf("%s/api/v1/customers/%s", c.URL, url.PathEscape(customerID)),
		attributes)
}

// Identify identifies a customer and sets their attributes
func (c *CustomerIO) Identify(customerID string, attributes map[string]interface{}) error {
	return c.IdentifyCtx(context.Background(), customerID, attributes)
}

// TrackCtx sends a single event to Customer.io for the supplied user
func (c *CustomerIO) TrackCtx(ctx context.Context, customerID string, eventName string, data map[string]interface{}) error {
	if customerID == "" {
		return ParamError{Param: "customerID"}
	}
	if eventName == "" {
		return ParamError{Param: "eventName"}
	}
	return c.request(ctx, "POST",
		fmt.Sprintf("%s/api/v1/customers/%s/events", c.URL, url.PathEscape(customerID)),
		map[string]interface{}{
			"name": eventName,
			"data": data,
		})
}

// Track sends a single event to Customer.io for the supplied user
func (c *CustomerIO) Track(customerID string, eventName string, data map[string]interface{}) error {
	return c.TrackCtx(context.Background(), customerID, eventName, data)
}

// TrackAnonymousCtx sends a single event to Customer.io for the anonymous user
func (c *CustomerIO) TrackAnonymousCtx(ctx context.Context, anonymousID, eventName string, data map[string]interface{}) error {
	if anonymousID == "" {
		return ParamError{Param: "anonymousID"}
	}
	if eventName == "" {
		return ParamError{Param: "eventName"}
	}
	return c.request(ctx, "POST",
		fmt.Sprintf("%s/api/v1/events", c.URL),
		map[string]interface{}{
			"name":         eventName,
			"anonymous_id": anonymousID,
			"data":         data,
		})
}

// TrackAnonymous sends a single event to Customer.io for the anonymous user
func (c *CustomerIO) TrackAnonymous(anonymousID, eventName string, data map[string]interface{}) error {
	return c.TrackAnonymousCtx(context.Background(), anonymousID, eventName, data)
}

// DeleteCtx deletes a customer
func (c *CustomerIO) DeleteCtx(ctx context.Context, customerID string) error {
	if customerID == "" {
		return ParamError{Param: "customerID"}
	}
	return c.request(ctx, "DELETE",
		fmt.Sprintf("%s/api/v1/customers/%s", c.URL, url.PathEscape(customerID)),
		nil)
}

// Delete deletes a customer
func (c *CustomerIO) Delete(customerID string) error {
	return c.DeleteCtx(context.Background(), customerID)
}

// AddDeviceCtx adds a device for a customer
func (c *CustomerIO) AddDeviceCtx(ctx context.Context, customerID string, deviceID string, platform string, data map[string]interface{}) error {
	if customerID == "" {
		return ParamError{Param: "customerID"}
	}
	if deviceID == "" {
		return ParamError{Param: "deviceID"}
	}
	if platform == "" {
		return ParamError{Param: "platform"}
	}

	body := map[string]map[string]interface{}{
		"device": {
			"id":       deviceID,
			"platform": platform,
		},
	}
	for k, v := range data {
		body["device"][k] = v
	}
	return c.request(ctx, "PUT",
		fmt.Sprintf("%s/api/v1/customers/%s/devices", c.URL, url.PathEscape(customerID)),
		body)
}

// AddDevice adds a device for a customer
func (c *CustomerIO) AddDevice(customerID string, deviceID string, platform string, data map[string]interface{}) error {
	return c.AddDeviceCtx(context.Background(), customerID, deviceID, platform, data)
}

// DeleteDeviceCtx deletes a device for a customer
func (c *CustomerIO) DeleteDeviceCtx(ctx context.Context, customerID string, deviceID string) error {
	if customerID == "" {
		return ParamError{Param: "customerID"}
	}
	if deviceID == "" {
		return ParamError{Param: "deviceID"}
	}
	return c.request(ctx, "DELETE",
		fmt.Sprintf("%s/api/v1/customers/%s/devices/%s", c.URL, url.PathEscape(customerID), url.PathEscape(deviceID)),
		nil)
}

// DeleteDevice deletes a device for a customer
func (c *CustomerIO) DeleteDevice(customerID string, deviceID string) error {
	return c.DeleteDeviceCtx(context.Background(), customerID, deviceID)
}

func (c *CustomerIO) auth() string {
	return base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf("%v:%v", c.siteID, c.apiKey)))
}

func (c *CustomerIO) request(ctx context.Context, method, url string, body interface{}) error {
	var req *http.Request
	if body != nil {
		j, err := json.Marshal(body)
		if err != nil {
			return err
		}

		req, err = http.NewRequest(method, url, bytes.NewBuffer(j))
		if err != nil {
			return err
		}
		req = req.WithContext(ctx)

		req.Header.Add("User-Agent", c.UserAgent)
		req.Header.Add("Content-Type", "application/json")
		req.Header.Add("Content-Length", strconv.Itoa(len(j)))
	} else {
		var err error
		req, err = http.NewRequest(method, url, nil)
		if err != nil {
			return err
		}
	}

	req.Header.Add("Authorization", fmt.Sprintf("Basic %v", c.auth()))

	resp, err := c.Client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode != http.StatusOK {
		return &CustomerIOError{
			status: resp.StatusCode,
			url:    url,
			body:   responseBody,
		}
	}

	return nil
}

type IdentifierType string

const (
	IdentifierTypeID    IdentifierType = "id"
	IdentifierTypeEmail IdentifierType = "email"
	IdentifierTypeCioID IdentifierType = "cio_id"
)

type Identifier struct {
	Type  IdentifierType
	Value string
}

func (id Identifier) kv() map[string]string {
	return map[string]string{
		string(id.Type): id.Value,
	}
}

func (id Identifier) validate() error {
	if !(id.Type == IdentifierTypeID ||
		id.Type == IdentifierTypeEmail ||
		id.Type == IdentifierTypeCioID) {
		return errors.New("invalid id type")
	}

	if strings.TrimSpace(id.Value) == "" {
		return errors.New("invalid id")
	}

	return nil
}

// MergeCustomersCtx sends a request to Customer.io to merge two customer profiles together.
func (c *CustomerIO) MergeCustomersCtx(ctx context.Context, primary Identifier, secondary Identifier) error {
	if primary.validate() != nil {
		return ParamError{Param: "primary"}
	}
	if secondary.validate() != nil {
		return ParamError{Param: "secondary"}
	}

	return c.request(ctx, "POST",
		fmt.Sprintf("%s/api/v1/merge_customers", c.URL),
		map[string]interface{}{
			"primary":   primary.kv(),
			"secondary": secondary.kv(),
		})
}

// MergeCustomers sends a request to Customer.io to merge two customer profiles together.
func (c *CustomerIO) MergeCustomers(primary Identifier, secondary Identifier) error {
	return c.MergeCustomersCtx(context.Background(), primary, secondary)
}
<commit_msg>feat: add support for invite-type anonymous event tracking<commit_after>package customerio

import (
	"bytes"
	"context"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

const DefaultUserAgent = "Customer.io Go Client/" + Version

// CustomerIO wraps the customer.io track API, see: https://customer.io/docs/api/#apitrackintroduction
type CustomerIO struct {
	siteID    string
	apiKey    string
	URL       string
	UserAgent string
	Client    *http.Client
}

// CustomerIOError is returned by any method that fails at the API level
type CustomerIOError struct {
	status int
	url    string
	body   []byte
}

func (e *CustomerIOError) Error() string {
	return fmt.Sprintf("%v: %v %v", e.status, e.url, string(e.body))
}

// ParamError is an error returned if a parameter to the track API is invalid.
type ParamError struct {
	Param string // Param is the name of the parameter.
}

func (e ParamError) Error() string { return e.Param + ": missing" }

// NewTrackClient prepares a client for use with the Customer.io track API, see: https://customer.io/docs/api/#apitrackintroduction
// using a Tracking Site ID and API Key pair from https://fly.customer.io/settings/api_credentials
func NewTrackClient(siteID, apiKey string, opts ...option) *CustomerIO {
	client := &http.Client{
		Transport: &http.Transport{
			MaxIdleConnsPerHost: 100,
		},
	}
	c := &CustomerIO{
		siteID:    siteID,
		apiKey:    apiKey,
		URL:       "https://track.customer.io",
		UserAgent: DefaultUserAgent,
		Client:    client,
	}

	for _, opt := range opts {
		opt.track(c)
	}

	return c
}

// NewCustomerIO prepares a client for use with the Customer.io track API, see: https://customer.io/docs/api/#apitrackintroduction
// deprecated in favour of NewTrackClient
func NewCustomerIO(siteID, apiKey string) *CustomerIO {
	return NewTrackClient(siteID, apiKey)
}

// IdentifyCtx identifies a customer and sets their attributes
func (c *CustomerIO) IdentifyCtx(ctx context.Context, customerID string, attributes map[string]interface{}) error {
	if customerID == "" {
		return ParamError{Param: "customerID"}
	}
	return c.request(ctx, "PUT",
		fmt.Sprintf("%s/api/v1/customers/%s", c.URL, url.PathEscape(customerID)),
		attributes)
}

// Identify identifies a customer and sets their attributes
func (c *CustomerIO) Identify(customerID string, attributes map[string]interface{}) error {
	return c.IdentifyCtx(context.Background(), customerID, attributes)
}

// TrackCtx sends a single event to Customer.io for the supplied user
func (c *CustomerIO) TrackCtx(ctx context.Context, customerID string, eventName string, data map[string]interface{}) error {
	if customerID == "" {
		return ParamError{Param: "customerID"}
	}
	if eventName == "" {
		return ParamError{Param: "eventName"}
	}
	return c.request(ctx, "POST",
		fmt.Sprintf("%s/api/v1/customers/%s/events", c.URL, url.PathEscape(customerID)),
		map[string]interface{}{
			"name": eventName,
			"data": data,
		})
}

// Track sends a single event to Customer.io for the supplied user
func (c *CustomerIO) Track(customerID string, eventName string, data map[string]interface{}) error {
	return c.TrackCtx(context.Background(), customerID, eventName, data)
}

// TrackAnonymousCtx sends a single event to Customer.io for the anonymous user
func (c *CustomerIO) TrackAnonymousCtx(ctx context.Context, anonymousID, eventName string, data map[string]interface{}) error {
	if eventName == "" {
		return ParamError{Param: "eventName"}
	}

	payload := map[string]interface{}{
		"name": eventName,
		"data": data,
	}

	if anonymousID != "" {
		payload["anonymous_id"] = anonymousID
	}

	return c.request(ctx, "POST", fmt.Sprintf("%s/api/v1/events", c.URL), payload)
}

// TrackAnonymous sends a single event to Customer.io for the anonymous user
func (c *CustomerIO) TrackAnonymous(anonymousID, eventName string, data map[string]interface{}) error {
	return c.TrackAnonymousCtx(context.Background(), anonymousID, eventName, data)
}

// DeleteCtx deletes a customer
func (c *CustomerIO) DeleteCtx(ctx context.Context, customerID string) error {
	if customerID == "" {
		return ParamError{Param: "customerID"}
	}
	return c.request(ctx, "DELETE",
		fmt.Sprintf("%s/api/v1/customers/%s", c.URL, url.PathEscape(customerID)),
		nil)
}

// Delete deletes a customer
func (c *CustomerIO) Delete(customerID string) error {
	return c.DeleteCtx(context.Background(), customerID)
}

// AddDeviceCtx adds a device for a customer
func (c *CustomerIO) AddDeviceCtx(ctx context.Context, customerID string, deviceID string, platform string, data map[string]interface{}) error {
	if customerID == "" {
		return ParamError{Param: "customerID"}
	}
	if deviceID == "" {
		return ParamError{Param: "deviceID"}
	}
	if platform == "" {
		return ParamError{Param: "platform"}
	}

	body := map[string]map[string]interface{}{
		"device": {
			"id":       deviceID,
			"platform": platform,
		},
	}
	for k, v := range data {
		body["device"][k] = v
	}
	return c.request(ctx, "PUT",
		fmt.Sprintf("%s/api/v1/customers/%s/devices", c.URL, url.PathEscape(customerID)),
		body)
}

// AddDevice adds a device for a customer
func (c *CustomerIO) AddDevice(customerID string, deviceID string, platform string, data map[string]interface{}) error {
	return c.AddDeviceCtx(context.Background(), customerID, deviceID, platform, data)
}

// DeleteDeviceCtx deletes a device for a customer
func (c *CustomerIO) DeleteDeviceCtx(ctx context.Context, customerID string, deviceID string) error {
	if customerID == "" {
		return ParamError{Param: "customerID"}
	}
	if deviceID == "" {
		return ParamError{Param: "deviceID"}
	}
	return c.request(ctx, "DELETE",
		fmt.Sprintf("%s/api/v1/customers/%s/devices/%s", c.URL, url.PathEscape(customerID), url.PathEscape(deviceID)),
		nil)
}

// DeleteDevice deletes a device for a customer
func (c *CustomerIO) DeleteDevice(customerID string, deviceID string) error {
	return c.DeleteDeviceCtx(context.Background(), customerID, deviceID)
}

func (c *CustomerIO) auth() string {
	return base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf("%v:%v", c.siteID, c.apiKey)))
}

func (c *CustomerIO) request(ctx context.Context, method, url string, body interface{}) error {
	var req *http.Request
	if body != nil {
		j, err := json.Marshal(body)
		if err != nil {
			return err
		}

		req, err = http.NewRequest(method, url, bytes.NewBuffer(j))
		if err != nil {
			return err
		}
		req = req.WithContext(ctx)

		req.Header.Add("User-Agent", c.UserAgent)
		req.Header.Add("Content-Type", "application/json")
		req.Header.Add("Content-Length", strconv.Itoa(len(j)))
	} else {
		var err error
		req, err = http.NewRequest(method, url, nil)
		if err != nil {
			return err
		}
	}

	req.Header.Add("Authorization", fmt.Sprintf("Basic %v", c.auth()))

	resp, err := c.Client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode != http.StatusOK {
		return &CustomerIOError{
			status: resp.StatusCode,
			url:    url,
			body:   responseBody,
		}
	}

	return nil
}

type IdentifierType string

const (
	IdentifierTypeID    IdentifierType = "id"
	IdentifierTypeEmail IdentifierType = "email"
	IdentifierTypeCioID IdentifierType = "cio_id"
)

type Identifier struct {
	Type  IdentifierType
	Value string
}

func (id Identifier) kv() map[string]string {
	return map[string]string{
		string(id.Type): id.Value,
	}
}

func (id Identifier) validate() error {
	if !(id.Type == IdentifierTypeID ||
		id.Type == IdentifierTypeEmail ||
		id.Type == IdentifierTypeCioID) {
		return errors.New("invalid id type")
	}

	if strings.TrimSpace(id.Value) == "" {
		return errors.New("invalid id")
	}

	return nil
}

// MergeCustomersCtx sends a request to Customer.io to merge two customer profiles together.
func (c *CustomerIO) MergeCustomersCtx(ctx context.Context, primary Identifier, secondary Identifier) error {
	if primary.validate() != nil {
		return ParamError{Param: "primary"}
	}
	if secondary.validate() != nil {
		return ParamError{Param: "secondary"}
	}

	return c.request(ctx, "POST",
		fmt.Sprintf("%s/api/v1/merge_customers", c.URL),
		map[string]interface{}{
			"primary":   primary.kv(),
			"secondary": secondary.kv(),
		})
}

// MergeCustomers sends a request to Customer.io to merge two customer profiles together.
func (c *CustomerIO) MergeCustomers(primary Identifier, secondary Identifier) error {
	return c.MergeCustomersCtx(context.Background(), primary, secondary)
}
<|endoftext|>


<commit_before>package libp2pwebtransport

import (
	"bytes"
	"context"
	"crypto/sha256"
	"crypto/tls"
	"fmt"
	"sync"
	"time"

	"github.com/benbjohnson/clock"
	ma "github.com/multiformats/go-multiaddr"
	"github.com/multiformats/go-multibase"
	"github.com/multiformats/go-multihash"
)

type certConfig struct {
	start, end time.Time
	tlsConf    *tls.Config
	sha256     [32]byte // cached from the tlsConf
}

func newCertConfig(start, end time.Time, conf *tls.Config) (*certConfig, error) {
	return &certConfig{
		start:   start,
		end:     end,
		tlsConf: conf,
		sha256:  sha256.Sum256(conf.Certificates[0].Leaf.Raw),
	}, nil
}

// Certificate renewal logic:
// 0. To simplify the math, assume the certificate is valid for 10 days (in real life: 14 days).
// 1. On startup, we generate the first certificate (1).
// 2. After 4 days, we generate a second certificate (2).
//    We don't use that certificate yet, but we advertise the hashes of (1) and (2).
//    That allows clients to connect to us using addresses that are 4 days old.
// 3. After another 4 days, we now actually start using (2).
//    We also generate a third certificate (3), and start advertising the hashes of (2) and (3).
//    We continue to remember the hash of (1) for validation during the Noise handshake for another 4 days,
//    as the client might be connecting with a cached address.
type certManager struct {
	clock     clock.Clock
	ctx       context.Context
	ctxCancel context.CancelFunc
	refCount  sync.WaitGroup

	mx            sync.Mutex
	lastConfig    *certConfig // initially nil
	currentConfig *certConfig
	nextConfig    *certConfig // nil until we have passed half the certValidity of the current config
	addrComp      ma.Multiaddr
}

func newCertManager(clock clock.Clock) (*certManager, error) {
	m := &certManager{clock: clock}
	m.ctx, m.ctxCancel = context.WithCancel(context.Background())
	if err := m.init(); err != nil {
		return nil, err
	}

	t := m.clock.Ticker(certValidity * 4 / 9) // make sure we're a bit faster than 1/2
	m.refCount.Add(1)
	go func() {
		defer m.refCount.Done()
		defer t.Stop()
		if err := m.background(t); err != nil {
			log.Fatal(err)
		}
	}()
	return m, nil
}

func (m *certManager) init() error {
	start := m.clock.Now()
	end := start.Add(certValidity)
	tlsConf, err := getTLSConf(start, end)
	if err != nil {
		return err
	}
	cc, err := newCertConfig(start, end, tlsConf)
	if err != nil {
		return err
	}
	m.currentConfig = cc
	return m.cacheAddrComponent()
}

func (m *certManager) background(t *clock.Ticker) error {
	for {
		select {
		case <-m.ctx.Done():
			return nil
		case start := <-t.C:
			end := start.Add(certValidity)
			tlsConf, err := getTLSConf(start, end)
			if err != nil {
				return err
			}
			cc, err := newCertConfig(start, end, tlsConf)
			if err != nil {
				return err
			}
			m.mx.Lock()
			if m.nextConfig != nil {
				m.lastConfig = m.currentConfig
				m.currentConfig = m.nextConfig
			}
			m.nextConfig = cc
			if err := m.cacheAddrComponent(); err != nil {
				m.mx.Unlock()
				return err
			}
			m.mx.Unlock()
		}
	}
}

func (m *certManager) GetConfig() *tls.Config {
	m.mx.Lock()
	defer m.mx.Unlock()
	return m.currentConfig.tlsConf
}

func (m *certManager) AddrComponent() ma.Multiaddr {
	m.mx.Lock()
	defer m.mx.Unlock()
	return m.addrComp
}

func (m *certManager) Verify(hashes []multihash.DecodedMultihash) error {
	for _, h := range hashes {
		if h.Code != multihash.SHA2_256 {
			return fmt.Errorf("expected SHA256 hash, got %d", h.Code)
		}
		if !bytes.Equal(h.Digest, m.currentConfig.sha256[:]) &&
			(m.nextConfig == nil || !bytes.Equal(h.Digest, m.nextConfig.sha256[:])) &&
			(m.lastConfig == nil || !bytes.Equal(h.Digest, m.lastConfig.sha256[:])) {
			return fmt.Errorf("found unexpected hash: %+x", h.Digest)
		}
	}
	return nil
}

func (m *certManager) cacheAddrComponent() error {
	addr, err := m.addrComponentForCert(m.currentConfig.sha256[:])
	if err != nil {
		return err
	}
	if m.nextConfig != nil {
		comp, err := m.addrComponentForCert(m.nextConfig.sha256[:])
		if err != nil {
			return err
		}
		addr = addr.Encapsulate(comp)
	}
	m.addrComp = addr
	return nil
}

func (m *certManager) addrComponentForCert(hash []byte) (ma.Multiaddr, error) {
	mh, err := multihash.Encode(hash, multihash.SHA2_256)
	if err != nil {
		return nil, err
	}
	certStr, err := multibase.Encode(multibase.Base58BTC, mh)
	if err != nil {
		return nil, err
	}
	return ma.NewComponent(ma.ProtocolWithCode(ma.P_CERTHASH).Name, certStr)
}

func (m *certManager) Close() error {
	m.ctxCancel()
	m.refCount.Wait()
	return nil
}
<commit_msg>simplify certificate generation<commit_after>package libp2pwebtransport

import (
	"bytes"
	"context"
	"crypto/sha256"
	"crypto/tls"
	"fmt"
	"sync"
	"time"

	"github.com/benbjohnson/clock"
	ma "github.com/multiformats/go-multiaddr"
	"github.com/multiformats/go-multibase"
	"github.com/multiformats/go-multihash"
)

type certConfig struct {
	tlsConf *tls.Config
	sha256  [32]byte // cached from the tlsConf
}

func newCertConfig(start, end time.Time) (*certConfig, error) {
	conf, err := getTLSConf(start, end)
	if err != nil {
		return nil, err
	}
	return &certConfig{
		tlsConf: conf,
		sha256:  sha256.Sum256(conf.Certificates[0].Leaf.Raw),
	}, nil
}

// Certificate renewal logic:
// 0. To simplify the math, assume the certificate is valid for 10 days (in real life: 14 days).
// 1. On startup, we generate the first certificate (1).
// 2. After 4 days, we generate a second certificate (2).
//    We don't use that certificate yet, but we advertise the hashes of (1) and (2).
//    That allows clients to connect to us using addresses that are 4 days old.
// 3. After another 4 days, we now actually start using (2).
//    We also generate a third certificate (3), and start advertising the hashes of (2) and (3).
//    We continue to remember the hash of (1) for validation during the Noise handshake for another 4 days,
//    as the client might be connecting with a cached address.
type certManager struct {
	clock     clock.Clock
	ctx       context.Context
	ctxCancel context.CancelFunc
	refCount  sync.WaitGroup

	mx            sync.Mutex
	lastConfig    *certConfig // initially nil
	currentConfig *certConfig
	nextConfig    *certConfig // nil until we have passed half the certValidity of the current config
	addrComp      ma.Multiaddr
}

func newCertManager(clock clock.Clock) (*certManager, error) {
	m := &certManager{clock: clock}
	m.ctx, m.ctxCancel = context.WithCancel(context.Background())
	if err := m.init(); err != nil {
		return nil, err
	}

	t := m.clock.Ticker(certValidity * 4 / 9) // make sure we're a bit faster than 1/2
	m.refCount.Add(1)
	go func() {
		defer m.refCount.Done()
		defer t.Stop()
		if err := m.background(t); err != nil {
			log.Fatal(err)
		}
	}()
	return m, nil
}

func (m *certManager) init() error {
	start := m.clock.Now()
	end := start.Add(certValidity)
	cc, err := newCertConfig(start, end)
	if err != nil {
		return err
	}
	m.currentConfig = cc
	return m.cacheAddrComponent()
}

func (m *certManager) background(t *clock.Ticker) error {
	for {
		select {
		case <-m.ctx.Done():
			return nil
		case start := <-t.C:
			end := start.Add(certValidity)
			cc, err := newCertConfig(start, end)
			if err != nil {
				return err
			}
			m.mx.Lock()
			if m.nextConfig != nil {
				m.lastConfig = m.currentConfig
				m.currentConfig = m.nextConfig
			}
			m.nextConfig = cc
			if err := m.cacheAddrComponent(); err != nil {
				m.mx.Unlock()
				return err
			}
			m.mx.Unlock()
		}
	}
}

func (m *certManager) GetConfig() *tls.Config {
	m.mx.Lock()
	defer m.mx.Unlock()
	return m.currentConfig.tlsConf
}

func (m *certManager) AddrComponent() ma.Multiaddr {
	m.mx.Lock()
	defer m.mx.Unlock()
	return m.addrComp
}

func (m *certManager) Verify(hashes []multihash.DecodedMultihash) error {
	for _, h := range hashes {
		if h.Code != multihash.SHA2_256 {
			return fmt.Errorf("expected SHA256 hash, got %d", h.Code)
		}
		if !bytes.Equal(h.Digest, m.currentConfig.sha256[:]) &&
			(m.nextConfig == nil || !bytes.Equal(h.Digest, m.nextConfig.sha256[:])) &&
			(m.lastConfig == nil || !bytes.Equal(h.Digest, m.lastConfig.sha256[:])) {
			return fmt.Errorf("found unexpected hash: %+x", h.Digest)
		}
	}
	return nil
}

func (m *certManager) cacheAddrComponent() error {
	addr, err := m.addrComponentForCert(m.currentConfig.sha256[:])
	if err != nil {
		return err
	}
	if m.nextConfig != nil {
		comp, err := m.addrComponentForCert(m.nextConfig.sha256[:])
		if err != nil {
			return err
		}
		addr = addr.Encapsulate(comp)
	}
	m.addrComp = addr
	return nil
}

func (m *certManager) addrComponentForCert(hash []byte) (ma.Multiaddr, error) {
	mh, err := multihash.Encode(hash, multihash.SHA2_256)
	if err != nil {
		return nil, err
	}
	certStr, err := multibase.Encode(multibase.Base58BTC, mh)
	if err != nil {
		return nil, err
	}
	return ma.NewComponent(ma.ProtocolWithCode(ma.P_CERTHASH).Name, certStr)
}

func (m *certManager) Close() error {
	m.ctxCancel()
	m.refCount.Wait()
	return nil
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/autoscaling"
	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSAutoscalingLifecycleHook_basic(t *testing.T) {
	resourceName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSAutoscalingLifecycleHookDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSAutoscalingLifecycleHookConfig(resourceName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLifecycleHookExists("aws_autoscaling_lifecycle_hook.foobar"),
					resource.TestCheckResourceAttr("aws_autoscaling_lifecycle_hook.foobar", "autoscaling_group_name", resourceName),
					resource.TestCheckResourceAttr("aws_autoscaling_lifecycle_hook.foobar", "default_result", "CONTINUE"),
					resource.TestCheckResourceAttr("aws_autoscaling_lifecycle_hook.foobar", "heartbeat_timeout", "2000"),
					resource.TestCheckResourceAttr("aws_autoscaling_lifecycle_hook.foobar", "lifecycle_transition", "autoscaling:EC2_INSTANCE_LAUNCHING"),
				),
			},
		},
	})
}

func TestAccAWSAutoscalingLifecycleHook_omitDefaultResult(t *testing.T) {
	rName := acctest.RandString(10)
	rInt := acctest.RandInt()
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSAutoscalingLifecycleHookDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSAutoscalingLifecycleHookConfig_omitDefaultResult(rName, rInt),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLifecycleHookExists("aws_autoscaling_lifecycle_hook.foobar"),
					resource.TestCheckResourceAttr("aws_autoscaling_lifecycle_hook.foobar", "default_result", "ABANDON"),
				),
			},
		},
	})
}

func testAccCheckLifecycleHookExists(n string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		return checkLifecycleHookExistsByName(
			rs.Primary.Attributes["autoscaling_group_name"], rs.Primary.ID)
	}
}

func checkLifecycleHookExistsByName(asgName, hookName string) error {
	conn := testAccProvider.Meta().(*AWSClient).autoscalingconn
	params := &autoscaling.DescribeLifecycleHooksInput{
		AutoScalingGroupName: aws.String(asgName),
		LifecycleHookNames:   []*string{aws.String(hookName)},
	}
	resp, err := conn.DescribeLifecycleHooks(params)
	if err != nil {
		return err
	}
	if len(resp.LifecycleHooks) == 0 {
		return fmt.Errorf("LifecycleHook not found")
	}

	return nil
}

func testAccCheckAWSAutoscalingLifecycleHookDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).autoscalingconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_autoscaling_group" {
			continue
		}

		params := autoscaling.DescribeLifecycleHooksInput{
			AutoScalingGroupName: aws.String(rs.Primary.Attributes["autoscaling_group_name"]),
			LifecycleHookNames:   []*string{aws.String(rs.Primary.ID)},
		}

		resp, err := conn.DescribeLifecycleHooks(&params)

		if err == nil {
			if len(resp.LifecycleHooks) != 0 &&
				*resp.LifecycleHooks[0].LifecycleHookName == rs.Primary.ID {
				return fmt.Errorf("Lifecycle Hook Still Exists: %s", rs.Primary.ID)
			}
		}
	}

	return nil
}

func testAccAWSAutoscalingLifecycleHookConfig(name string) string {
	return fmt.Sprintf(`
resource "aws_launch_configuration" "foobar" {
    name = "%s"
    image_id = "ami-21f78e11"
    instance_type = "t1.micro"
}

resource "aws_sqs_queue" "foobar" {
  name = "foobar"
  delay_seconds = 90
  max_message_size = 2048
  message_retention_seconds = 86400
  receive_wait_time_seconds = 10
}

resource "aws_iam_role" "foobar" {
    name = "foobar"
    assume_role_policy = <<EOF
{
  "Version" : "2012-10-17",
  "Statement": [ {
    "Effect": "Allow",
    "Principal": {"AWS": "*"},
    "Action": [ "sts:AssumeRole" ]
  } ]
}
EOF
}

resource "aws_iam_role_policy" "foobar" {
    name = "foobar"
    role = "${aws_iam_role.foobar.id}"
    policy = <<EOF
{
    "Version" : "2012-10-17",
    "Statement": [ {
      "Effect": "Allow",
      "Action": [
	"sqs:SendMessage",
	"sqs:GetQueueUrl",
	"sns:Publish"
      ],
      "Resource": [
	"${aws_sqs_queue.foobar.arn}"
      ]
    } ]
}
EOF
}

resource "aws_autoscaling_group" "foobar" {
    availability_zones = ["us-west-2a"]
    name = "%s"
		max_size = 5
    min_size = 2
    health_check_grace_period = 300
    health_check_type = "ELB"
    force_delete = true
    termination_policies = ["OldestInstance"]
    launch_configuration = "${aws_launch_configuration.foobar.name}"
    tag {
        key = "Foo"
        value = "foo-bar"
        propagate_at_launch = true
    }
}

resource "aws_autoscaling_lifecycle_hook" "foobar" {
    name = "foobar"
    autoscaling_group_name = "${aws_autoscaling_group.foobar.name}"
    default_result = "CONTINUE"
    heartbeat_timeout = 2000
    lifecycle_transition = "autoscaling:EC2_INSTANCE_LAUNCHING"
    notification_metadata = <<EOF
{
  "foo": "bar"
}
EOF
    notification_target_arn = "${aws_sqs_queue.foobar.arn}"
    role_arn = "${aws_iam_role.foobar.arn}"
}
`, name, name)
}

func testAccAWSAutoscalingLifecycleHookConfig_omitDefaultResult(name string, rInt int) string {
	return fmt.Sprintf(`
resource "aws_launch_configuration" "foobar" {
  name          = "%s"
  image_id      = "ami-21f78e11"
  instance_type = "t1.micro"
}

resource "aws_sqs_queue" "foobar" {
  name                      = "foobar"
  delay_seconds             = 90
  max_message_size          = 2048
  message_retention_seconds = 86400
  receive_wait_time_seconds = 10
}

resource "aws_iam_role" "foobar" {
  name = "foobar-%d"

  assume_role_policy = <<EOF
{
  "Version" : "2012-10-17",
  "Statement": [ {
    "Effect": "Allow",
    "Principal": {"AWS": "*"},
    "Action": [ "sts:AssumeRole" ]
  } ]
}
EOF
}

resource "aws_iam_role_policy" "foobar" {
  name = "foobar"
  role = "${aws_iam_role.foobar.id}"

  policy = <<EOF
{
    "Version" : "2012-10-17",
    "Statement": [ {
      "Effect": "Allow",
      "Action": [
	"sqs:SendMessage",
	"sqs:GetQueueUrl",
	"sns:Publish"
      ],
      "Resource": [
	"${aws_sqs_queue.foobar.arn}"
      ]
    } ]
}
EOF
}

resource "aws_autoscaling_group" "foobar" {
  availability_zones        = ["us-west-2a"]
  name                      = "%s"
  max_size                  = 5
  min_size                  = 2
  health_check_grace_period = 300
  health_check_type         = "ELB"
  force_delete              = true
  termination_policies      = ["OldestInstance"]
  launch_configuration      = "${aws_launch_configuration.foobar.name}"

  tag {
    key                 = "Foo"
    value               = "foo-bar"
    propagate_at_launch = true
  }
}

resource "aws_autoscaling_lifecycle_hook" "foobar" {
  name                   = "foobar"
  autoscaling_group_name = "${aws_autoscaling_group.foobar.name}"
  heartbeat_timeout      = 2000
  lifecycle_transition   = "autoscaling:EC2_INSTANCE_LAUNCHING"

  notification_metadata = <<EOF
{
  "foo": "bar"
}
EOF

  notification_target_arn = "${aws_sqs_queue.foobar.arn}"
  role_arn                = "${aws_iam_role.foobar.arn}"
}`, name, rInt, name)
}
<commit_msg>Fixes TestAccAWSAutoscalingLifecycleHook_omitDefaultResult<commit_after>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/autoscaling"
	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSAutoscalingLifecycleHook_basic(t *testing.T) {
	resourceName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSAutoscalingLifecycleHookDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSAutoscalingLifecycleHookConfig(resourceName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLifecycleHookExists("aws_autoscaling_lifecycle_hook.foobar"),
					resource.TestCheckResourceAttr("aws_autoscaling_lifecycle_hook.foobar", "autoscaling_group_name", resourceName),
					resource.TestCheckResourceAttr("aws_autoscaling_lifecycle_hook.foobar", "default_result", "CONTINUE"),
					resource.TestCheckResourceAttr("aws_autoscaling_lifecycle_hook.foobar", "heartbeat_timeout", "2000"),
					resource.TestCheckResourceAttr("aws_autoscaling_lifecycle_hook.foobar", "lifecycle_transition", "autoscaling:EC2_INSTANCE_LAUNCHING"),
				),
			},
		},
	})
}

func TestAccAWSAutoscalingLifecycleHook_omitDefaultResult(t *testing.T) {
	rName := acctest.RandString(10)
	rInt := acctest.RandInt()
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSAutoscalingLifecycleHookDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSAutoscalingLifecycleHookConfig_omitDefaultResult(rName, rInt),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLifecycleHookExists("aws_autoscaling_lifecycle_hook.foobar"),
					resource.TestCheckResourceAttr("aws_autoscaling_lifecycle_hook.foobar", "default_result", "ABANDON"),
				),
			},
		},
	})
}

func testAccCheckLifecycleHookExists(n string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		return checkLifecycleHookExistsByName(
			rs.Primary.Attributes["autoscaling_group_name"], rs.Primary.ID)
	}
}

func checkLifecycleHookExistsByName(asgName, hookName string) error {
	conn := testAccProvider.Meta().(*AWSClient).autoscalingconn
	params := &autoscaling.DescribeLifecycleHooksInput{
		AutoScalingGroupName: aws.String(asgName),
		LifecycleHookNames:   []*string{aws.String(hookName)},
	}
	resp, err := conn.DescribeLifecycleHooks(params)
	if err != nil {
		return err
	}
	if len(resp.LifecycleHooks) == 0 {
		return fmt.Errorf("LifecycleHook not found")
	}

	return nil
}

func testAccCheckAWSAutoscalingLifecycleHookDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).autoscalingconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_autoscaling_group" {
			continue
		}

		params := autoscaling.DescribeLifecycleHooksInput{
			AutoScalingGroupName: aws.String(rs.Primary.Attributes["autoscaling_group_name"]),
			LifecycleHookNames:   []*string{aws.String(rs.Primary.ID)},
		}

		resp, err := conn.DescribeLifecycleHooks(&params)

		if err == nil {
			if len(resp.LifecycleHooks) != 0 &&
				*resp.LifecycleHooks[0].LifecycleHookName == rs.Primary.ID {
				return fmt.Errorf("Lifecycle Hook Still Exists: %s", rs.Primary.ID)
			}
		}
	}

	return nil
}

func testAccAWSAutoscalingLifecycleHookConfig(name string) string {
	return fmt.Sprintf(`
resource "aws_launch_configuration" "foobar" {
    name = "%s"
    image_id = "ami-21f78e11"
    instance_type = "t1.micro"
}

resource "aws_sqs_queue" "foobar" {
  name = "foobar"
  delay_seconds = 90
  max_message_size = 2048
  message_retention_seconds = 86400
  receive_wait_time_seconds = 10
}

resource "aws_iam_role" "foobar" {
    name = "foobar"
    assume_role_policy = <<EOF
{
  "Version" : "2012-10-17",
  "Statement": [ {
    "Effect": "Allow",
    "Principal": {"AWS": "*"},
    "Action": [ "sts:AssumeRole" ]
  } ]
}
EOF
}

resource "aws_iam_role_policy" "foobar" {
    name = "foobar"
    role = "${aws_iam_role.foobar.id}"
    policy = <<EOF
{
    "Version" : "2012-10-17",
    "Statement": [ {
      "Effect": "Allow",
      "Action": [
	"sqs:SendMessage",
	"sqs:GetQueueUrl",
	"sns:Publish"
      ],
      "Resource": [
	"${aws_sqs_queue.foobar.arn}"
      ]
    } ]
}
EOF
}

resource "aws_autoscaling_group" "foobar" {
    availability_zones = ["us-west-2a"]
    name = "%s"
		max_size = 5
    min_size = 2
    health_check_grace_period = 300
    health_check_type = "ELB"
    force_delete = true
    termination_policies = ["OldestInstance"]
    launch_configuration = "${aws_launch_configuration.foobar.name}"
    tag {
        key = "Foo"
        value = "foo-bar"
        propagate_at_launch = true
    }
}

resource "aws_autoscaling_lifecycle_hook" "foobar" {
    name = "foobar"
    autoscaling_group_name = "${aws_autoscaling_group.foobar.name}"
    default_result = "CONTINUE"
    heartbeat_timeout = 2000
    lifecycle_transition = "autoscaling:EC2_INSTANCE_LAUNCHING"
    notification_metadata = <<EOF
{
  "foo": "bar"
}
EOF
    notification_target_arn = "${aws_sqs_queue.foobar.arn}"
    role_arn = "${aws_iam_role.foobar.arn}"
}
`, name, name)
}

func testAccAWSAutoscalingLifecycleHookConfig_omitDefaultResult(name string, rInt int) string {
	return fmt.Sprintf(`
resource "aws_launch_configuration" "foobar" {
  name          = "%s"
  image_id      = "ami-21f78e11"
  instance_type = "t1.micro"
}

resource "aws_sqs_queue" "foobar" {
  name                      = "foobar-%d"
  delay_seconds             = 90
  max_message_size          = 2048
  message_retention_seconds = 86400
  receive_wait_time_seconds = 10
}

resource "aws_iam_role" "foobar" {
  name = "foobar-%d"

  assume_role_policy = <<EOF
{
  "Version" : "2012-10-17",
  "Statement": [ {
    "Effect": "Allow",
    "Principal": {"AWS": "*"},
    "Action": [ "sts:AssumeRole" ]
  } ]
}
EOF
}

resource "aws_iam_role_policy" "foobar" {
  name = "foobar-%d"
  role = "${aws_iam_role.foobar.id}"

  policy = <<EOF
{
    "Version" : "2012-10-17",
    "Statement": [ {
      "Effect": "Allow",
      "Action": [
	"sqs:SendMessage",
	"sqs:GetQueueUrl",
	"sns:Publish"
      ],
      "Resource": [
	"${aws_sqs_queue.foobar.arn}"
      ]
    } ]
}
EOF
}

resource "aws_autoscaling_group" "foobar" {
  availability_zones        = ["us-west-2a"]
  name                      = "%s"
  max_size                  = 5
  min_size                  = 2
  health_check_grace_period = 300
  health_check_type         = "ELB"
  force_delete              = true
  termination_policies      = ["OldestInstance"]
  launch_configuration      = "${aws_launch_configuration.foobar.name}"

  tag {
    key                 = "Foo"
    value               = "foo-bar"
    propagate_at_launch = true
  }
}

resource "aws_autoscaling_lifecycle_hook" "foobar" {
  name                   = "foobar-%d"
  autoscaling_group_name = "${aws_autoscaling_group.foobar.name}"
  heartbeat_timeout      = 2000
  lifecycle_transition   = "autoscaling:EC2_INSTANCE_LAUNCHING"

  notification_metadata = <<EOF
{
  "foo": "bar"
}
EOF

  notification_target_arn = "${aws_sqs_queue.foobar.arn}"
  role_arn                = "${aws_iam_role.foobar.arn}"
}`, name, rInt, rInt, rInt, name, rInt)
}
<|endoftext|>


<commit_before>package openstack

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"

	"github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
)

func TestAccNetworkingV2Subnet_basic(t *testing.T) {
	var subnet subnets.Subnet

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckNetworkingV2SubnetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccNetworkingV2Subnet_basic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckNetworkingV2SubnetExists(t, "openstack_networking_subnet_v2.subnet_1", &subnet),
				),
			},
			resource.TestStep{
				Config: testAccNetworkingV2Subnet_update,
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "name", "tf-test-subnet"),
					resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "gateway_ip", "192.168.199.1"),
					resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "enable_dhcp", "true"),
				),
			},
		},
	})
}

func TestAccNetworkingV2Subnet_enableDHCP(t *testing.T) {
	var subnet subnets.Subnet

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckNetworkingV2SubnetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccNetworkingV2Subnet_enableDHCP,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckNetworkingV2SubnetExists(t, "openstack_networking_subnet_v2.subnet_1", &subnet),
					resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "enable_dhcp", "true"),
				),
			},
		},
	})
}

func TestAccNetworkingV2Subnet_disableDHCP(t *testing.T) {
	var subnet subnets.Subnet

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckNetworkingV2SubnetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccNetworkingV2Subnet_disableDHCP,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckNetworkingV2SubnetExists(t, "openstack_networking_subnet_v2.subnet_1", &subnet),
					resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "enable_dhcp", "false"),
				),
			},
		},
	})
}

func TestAccNetworkingV2Subnet_noGateway(t *testing.T) {
	var subnet subnets.Subnet

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckNetworkingV2SubnetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccNetworkingV2Subnet_noGateway,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckNetworkingV2SubnetExists(t, "openstack_networking_subnet_v2.subnet_1", &subnet),
					resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "gateway_ip", ""),
				),
			},
		},
	})
}

func TestAccNetworkingV2Subnet_impliedGateway(t *testing.T) {
	var subnet subnets.Subnet

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckNetworkingV2SubnetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccNetworkingV2Subnet_impliedGateway,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckNetworkingV2SubnetExists(t, "openstack_networking_subnet_v2.subnet_1", &subnet),
					resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "gateway_ip", "192.168.199.1"),
				),
			},
		},
	})
}

func testAccCheckNetworkingV2SubnetDestroy(s *terraform.State) error {
	config := testAccProvider.Meta().(*Config)
	networkingClient, err := config.networkingV2Client(OS_REGION_NAME)
	if err != nil {
		return fmt.Errorf("(testAccCheckNetworkingV2SubnetDestroy) Error creating OpenStack networking client: %s", err)
	}

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "openstack_networking_subnet_v2" {
			continue
		}

		_, err := subnets.Get(networkingClient, rs.Primary.ID).Extract()
		if err == nil {
			return fmt.Errorf("Subnet still exists")
		}
	}

	return nil
}

func testAccCheckNetworkingV2SubnetExists(t *testing.T, n string, subnet *subnets.Subnet) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}

		config := testAccProvider.Meta().(*Config)
		networkingClient, err := config.networkingV2Client(OS_REGION_NAME)
		if err != nil {
			return fmt.Errorf("(testAccCheckNetworkingV2SubnetExists) Error creating OpenStack networking client: %s", err)
		}

		found, err := subnets.Get(networkingClient, rs.Primary.ID).Extract()
		if err != nil {
			return err
		}

		if found.ID != rs.Primary.ID {
			return fmt.Errorf("Subnet not found")
		}

		*subnet = *found

		return nil
	}
}

var testAccNetworkingV2Subnet_basic = fmt.Sprintf(`
  resource "openstack_networking_network_v2" "network_1" {
    name = "network_1"
    admin_state_up = "true"
  }

  resource "openstack_networking_subnet_v2" "subnet_1" {
    network_id = "${openstack_networking_network_v2.network_1.id}"
    cidr = "192.168.199.0/24"
		allocation_pools {
			start = "192.168.199.100"
			end = "192.168.199.200"
		}
  }`)

var testAccNetworkingV2Subnet_update = fmt.Sprintf(`
  resource "openstack_networking_network_v2" "network_1" {
    name = "network_1"
    admin_state_up = "true"
  }

  resource "openstack_networking_subnet_v2" "subnet_1" {
    name = "subnet_1"
    network_id = "${openstack_networking_network_v2.network_1.id}"
    cidr = "192.168.199.0/24"
    gateway_ip = "192.168.199.1"
 		allocation_pools {
			start = "192.168.199.100"
			end = "192.168.199.200"
		}
 }`)

var testAccNetworkingV2Subnet_enableDHCP = fmt.Sprintf(`
  resource "openstack_networking_network_v2" "network_1" {
    name = "network_1"
    admin_state_up = "true"
  }

  resource "openstack_networking_subnet_v2" "subnet_1" {
    name = "tf-test-subnet"
    network_id = "${openstack_networking_network_v2.network_1.id}"
    cidr = "192.168.199.0/24"
    gateway_ip = "192.168.199.1"
    enable_dhcp = true
  }`)

var testAccNetworkingV2Subnet_disableDHCP = fmt.Sprintf(`
  resource "openstack_networking_network_v2" "network_1" {
    name = "network_1"
    admin_state_up = "true"
  }

  resource "openstack_networking_subnet_v2" "subnet_1" {
    name = "tf-test-subnet"
    network_id = "${openstack_networking_network_v2.network_1.id}"
    cidr = "192.168.199.0/24"
    enable_dhcp = false
  }`)

var testAccNetworkingV2Subnet_noGateway = fmt.Sprintf(`
  resource "openstack_networking_network_v2" "network_1" {
    name = "network_1"
    admin_state_up = "true"
  }
  resource "openstack_networking_subnet_v2" "subnet_1" {
    name = "tf-test-subnet"
    network_id = "${openstack_networking_network_v2.network_1.id}"
    cidr = "192.168.199.0/24"
		no_gateway = true
  }`)

var testAccNetworkingV2Subnet_impliedGateway = fmt.Sprintf(`
  resource "openstack_networking_network_v2" "network_1" {
    name = "network_1"
    admin_state_up = "true"
  }
  resource "openstack_networking_subnet_v2" "subnet_1" {
    name = "tf-test-subnet"
    network_id = "${openstack_networking_network_v2.network_1.id}"
    cidr = "192.168.199.0/24"
  }`)
<commit_msg>provider/openstack: gophercloud migration: Fixing subnet test<commit_after>package openstack

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"

	"github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
)

func TestAccNetworkingV2Subnet_basic(t *testing.T) {
	var subnet subnets.Subnet

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckNetworkingV2SubnetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccNetworkingV2Subnet_basic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckNetworkingV2SubnetExists(t, "openstack_networking_subnet_v2.subnet_1", &subnet),
				),
			},
			resource.TestStep{
				Config: testAccNetworkingV2Subnet_update,
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "name", "subnet_1"),
					resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "gateway_ip", "192.168.199.1"),
					resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "enable_dhcp", "true"),
				),
			},
		},
	})
}

func TestAccNetworkingV2Subnet_enableDHCP(t *testing.T) {
	var subnet subnets.Subnet

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckNetworkingV2SubnetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccNetworkingV2Subnet_enableDHCP,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckNetworkingV2SubnetExists(t, "openstack_networking_subnet_v2.subnet_1", &subnet),
					resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "enable_dhcp", "true"),
				),
			},
		},
	})
}

func TestAccNetworkingV2Subnet_disableDHCP(t *testing.T) {
	var subnet subnets.Subnet

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckNetworkingV2SubnetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccNetworkingV2Subnet_disableDHCP,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckNetworkingV2SubnetExists(t, "openstack_networking_subnet_v2.subnet_1", &subnet),
					resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "enable_dhcp", "false"),
				),
			},
		},
	})
}

func TestAccNetworkingV2Subnet_noGateway(t *testing.T) {
	var subnet subnets.Subnet

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckNetworkingV2SubnetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccNetworkingV2Subnet_noGateway,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckNetworkingV2SubnetExists(t, "openstack_networking_subnet_v2.subnet_1", &subnet),
					resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "gateway_ip", ""),
				),
			},
		},
	})
}

func TestAccNetworkingV2Subnet_impliedGateway(t *testing.T) {
	var subnet subnets.Subnet

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckNetworkingV2SubnetDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccNetworkingV2Subnet_impliedGateway,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckNetworkingV2SubnetExists(t, "openstack_networking_subnet_v2.subnet_1", &subnet),
					resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "gateway_ip", "192.168.199.1"),
				),
			},
		},
	})
}

func testAccCheckNetworkingV2SubnetDestroy(s *terraform.State) error {
	config := testAccProvider.Meta().(*Config)
	networkingClient, err := config.networkingV2Client(OS_REGION_NAME)
	if err != nil {
		return fmt.Errorf("(testAccCheckNetworkingV2SubnetDestroy) Error creating OpenStack networking client: %s", err)
	}

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "openstack_networking_subnet_v2" {
			continue
		}

		_, err := subnets.Get(networkingClient, rs.Primary.ID).Extract()
		if err == nil {
			return fmt.Errorf("Subnet still exists")
		}
	}

	return nil
}

func testAccCheckNetworkingV2SubnetExists(t *testing.T, n string, subnet *subnets.Subnet) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}

		config := testAccProvider.Meta().(*Config)
		networkingClient, err := config.networkingV2Client(OS_REGION_NAME)
		if err != nil {
			return fmt.Errorf("(testAccCheckNetworkingV2SubnetExists) Error creating OpenStack networking client: %s", err)
		}

		found, err := subnets.Get(networkingClient, rs.Primary.ID).Extract()
		if err != nil {
			return err
		}

		if found.ID != rs.Primary.ID {
			return fmt.Errorf("Subnet not found")
		}

		*subnet = *found

		return nil
	}
}

var testAccNetworkingV2Subnet_basic = fmt.Sprintf(`
  resource "openstack_networking_network_v2" "network_1" {
    name = "network_1"
    admin_state_up = "true"
  }

  resource "openstack_networking_subnet_v2" "subnet_1" {
    network_id = "${openstack_networking_network_v2.network_1.id}"
    cidr = "192.168.199.0/24"
		allocation_pools {
			start = "192.168.199.100"
			end = "192.168.199.200"
		}
  }`)

var testAccNetworkingV2Subnet_update = fmt.Sprintf(`
  resource "openstack_networking_network_v2" "network_1" {
    name = "network_1"
    admin_state_up = "true"
  }

  resource "openstack_networking_subnet_v2" "subnet_1" {
    name = "subnet_1"
    network_id = "${openstack_networking_network_v2.network_1.id}"
    cidr = "192.168.199.0/24"
    gateway_ip = "192.168.199.1"
 		allocation_pools {
			start = "192.168.199.100"
			end = "192.168.199.200"
		}
 }`)

var testAccNetworkingV2Subnet_enableDHCP = fmt.Sprintf(`
  resource "openstack_networking_network_v2" "network_1" {
    name = "network_1"
    admin_state_up = "true"
  }

  resource "openstack_networking_subnet_v2" "subnet_1" {
    name = "tf-test-subnet"
    network_id = "${openstack_networking_network_v2.network_1.id}"
    cidr = "192.168.199.0/24"
    gateway_ip = "192.168.199.1"
    enable_dhcp = true
  }`)

var testAccNetworkingV2Subnet_disableDHCP = fmt.Sprintf(`
  resource "openstack_networking_network_v2" "network_1" {
    name = "network_1"
    admin_state_up = "true"
  }

  resource "openstack_networking_subnet_v2" "subnet_1" {
    name = "tf-test-subnet"
    network_id = "${openstack_networking_network_v2.network_1.id}"
    cidr = "192.168.199.0/24"
    enable_dhcp = false
  }`)

var testAccNetworkingV2Subnet_noGateway = fmt.Sprintf(`
  resource "openstack_networking_network_v2" "network_1" {
    name = "network_1"
    admin_state_up = "true"
  }
  resource "openstack_networking_subnet_v2" "subnet_1" {
    name = "tf-test-subnet"
    network_id = "${openstack_networking_network_v2.network_1.id}"
    cidr = "192.168.199.0/24"
		no_gateway = true
  }`)

var testAccNetworkingV2Subnet_impliedGateway = fmt.Sprintf(`
  resource "openstack_networking_network_v2" "network_1" {
    name = "network_1"
    admin_state_up = "true"
  }
  resource "openstack_networking_subnet_v2" "subnet_1" {
    name = "tf-test-subnet"
    network_id = "${openstack_networking_network_v2.network_1.id}"
    cidr = "192.168.199.0/24"
  }`)
<|endoftext|>


<commit_before>// Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.

package main

import (
	"encoding/json"
	"errors"
	"log"

	"github.com/MustWin/baremetal-sdk-go"
	"github.com/hashicorp/terraform/helper/schema"

	"github.com/oracle/terraform-provider-oci/crud"
	"github.com/oracle/terraform-provider-oci/options"
)

func InstanceResource() *schema.Resource {
	return &schema.Resource{
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},
		Timeouts: &schema.ResourceTimeout{
			Create: &crud.TwoHours,
			Update: &crud.TwoHours,
			Delete: &crud.TwoHours,
		},
		Create: createInstance,
		Read:   readInstance,
		Update: updateInstance,
		Delete: deleteInstance,
		Schema: map[string]*schema.Schema{
			"create_vnic_details": {
				Type:     schema.TypeMap,
				Optional: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"assign_public_ip": {
							Type:     schema.TypeBool,
							Optional: true,
						},
						"display_name": {
							Type:     schema.TypeString,
							Optional: true,
						},
						"hostname_label": {
							Type:     schema.TypeString,
							Optional: true,
						},
						"private_ip": {
							Type:     schema.TypeString,
							Optional: true,
						},
						"subnet_id": {
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
			},
			"availability_domain": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"compartment_id": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"display_name": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"hostname_label": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"id": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"image": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"ipxe_script": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"metadata": {
				Type:     schema.TypeMap,
				Optional: true,
				Elem:     schema.TypeString,
				ForceNew: true,
			},
			"extended_metadata": {
				Type:     schema.TypeMap,
				Optional: true,
				ForceNew: true,
				Elem:     schema.TypeString,
			},
			"region": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"shape": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"state": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"subnet_id": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},
			"time_created": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"public_ip": {
				Type:     schema.TypeString,
				Required: false,
				Computed: true,
			},
			"private_ip": {
				Type:     schema.TypeString,
				Required: false,
				Computed: true,
			},
		},
	}
}

func createInstance(d *schema.ResourceData, m interface{}) (e error) {
	sync := &InstanceResourceCrud{}
	sync.D = d
	sync.Client = m.(*baremetal.Client)
	return crud.CreateResource(d, sync)
}

func readInstance(d *schema.ResourceData, m interface{}) (e error) {
	sync := &InstanceResourceCrud{}
	sync.D = d
	sync.Client = m.(*baremetal.Client)
	return crud.ReadResource(sync)
}

func updateInstance(d *schema.ResourceData, m interface{}) (e error) {
	sync := &InstanceResourceCrud{}
	sync.D = d
	sync.Client = m.(*baremetal.Client)
	return crud.UpdateResource(d, sync)
}

func deleteInstance(d *schema.ResourceData, m interface{}) (e error) {
	sync := &InstanceResourceCrud{}
	sync.D = d
	sync.Client = m.(*baremetal.Client)
	return crud.DeleteResource(d, sync)
}

type InstanceResourceCrud struct {
	crud.BaseCrud
	Resource *baremetal.Instance

	// Computed fields
	public_ip  string
	private_ip string
}

func (s *InstanceResourceCrud) ID() string {
	return s.Resource.ID
}

func (s *InstanceResourceCrud) CreatedPending() []string {
	return []string{
		baremetal.ResourceProvisioning,
		baremetal.ResourceStarting,
	}
}

func (s *InstanceResourceCrud) CreatedTarget() []string {
	return []string{baremetal.ResourceRunning}
}

func (s *InstanceResourceCrud) DeletedPending() []string {
	return []string{baremetal.ResourceTerminating}
}

func (s *InstanceResourceCrud) DeletedTarget() []string {
	return []string{baremetal.ResourceTerminated}
}

func resourceInstanceMapToMetadata(rm map[string]interface{}) map[string]string {
	result := map[string]string{}
	for k, v := range rm {
		result[k] = v.(string)
	}
	return result
}

func mapToExtendedMetadata(rm map[string]interface{}) map[string]interface{} {
	result := make(map[string]interface{})
	for k, v := range rm {
		val := make(map[string]interface{})
		//Use the string value that was passed if it is not a valid JSON string
		if err := json.Unmarshal([]byte(v.(string)), &val); err == nil {
			result[k] = val
		} else {
			result[k] = v.(string)
		}
	}
	return result
}

func (s *InstanceResourceCrud) Create() (e error) {
	availabilityDomain := s.D.Get("availability_domain").(string)
	compartmentID := s.D.Get("compartment_id").(string)
	image := s.D.Get("image").(string)
	shape := s.D.Get("shape").(string)
	subnet := s.D.Get("subnet_id").(string)

	opts := &baremetal.LaunchInstanceOptions{}
	if displayName, ok := s.D.GetOk("display_name"); ok {
		opts.DisplayName = displayName.(string)
	}
	if hostnameLabel, ok := s.D.GetOk("hostname_label"); ok {
		opts.HostnameLabel = hostnameLabel.(string)
	}
	if ipxeScript, ok := s.D.GetOk("ipxe_script"); ok {
		opts.IpxeScript = ipxeScript.(string)
	}

	if rawMetadata, ok := s.D.GetOk("metadata"); ok {
		metadata := resourceInstanceMapToMetadata(rawMetadata.(map[string]interface{}))
		opts.Metadata = metadata
	}

	if rawExtendedMetadata, ok := s.D.GetOk("extended_metadata"); ok {
		extendedMetadata := mapToExtendedMetadata(rawExtendedMetadata.(map[string]interface{}))
		opts.ExtendedMetadata = extendedMetadata
	}

	if rawVnic, ok := s.D.GetOk("create_vnic_details"); ok {
		opts.CreateVnicOptions = SetCreateVnicOptions(rawVnic)
	}

	s.Resource, e = s.Client.LaunchInstance(
		availabilityDomain,
		compartmentID,
		image,
		shape,
		subnet,
		opts)
	return
}

/*
 * Return the public, private IP pair associated with the instance's primary Vnic.
 *
 * NOTE while the instance is still being created, calls to this function
 * can return  an error priort to the Vnic being attached.
 */
func (s *InstanceResourceCrud) getInstanceIPs() (public_ip string, private_ip string, e error) {
	compartmentID := s.Resource.CompartmentID

	opts := &baremetal.ListVnicAttachmentsOptions{}
	opts.InstanceID = s.Resource.ID

	// Page through all VNIC attachments for the instance.
	var attachments []baremetal.VnicAttachment
	for {
		var result *baremetal.ListVnicAttachments
		if result, e = s.Client.ListVnicAttachments(compartmentID, opts); e != nil {
			break
		}

		attachments = append(attachments, result.Attachments...)
		if hasNextPage := options.SetNextPageOption(result.NextPage, &opts.ListOptions.PageListOptions); !hasNextPage {
			break
		}
	}

	if len(attachments) < 1 {
		return "", "", errors.New("No VNIC attachments found.")
	}

	for _, attachment := range attachments {
		if attachment.State == baremetal.ResourceAttached {
			vnic, _ := s.Client.GetVnic(attachment.VnicID)

			// Ignore errors on GetVnic, since we might not have permissions to view some secondary VNICs.
			if vnic != nil && vnic.IsPrimary {
				return vnic.PublicIPAddress, vnic.PrivateIPAddress, nil
			}
		}
	}

	return "", "", errors.New("Primary VNIC not found.")
}

func (s *InstanceResourceCrud) Get() (e error) {
	s.Resource, e = s.Client.GetInstance(s.D.Id())

	if e != nil {
		return e
	}

	// Compute instance IPs through attached Vnic
	// (Not available while state==PROVISIONING)
	public_ip, private_ip, e2 := s.getInstanceIPs()
	if e2 != nil {
		log.Printf("[DEBUG] Primary VNIC could not be found: %q (InstanceID: %q, State: %q)", e2, s.Resource.ID, s.Resource.State)
	}

	if public_ip != "" {
		s.public_ip = public_ip
	}
	if private_ip != "" {
		s.private_ip = private_ip
	}
	return
}

func (s *InstanceResourceCrud) Update() (e error) {
	opts := &baremetal.UpdateOptions{}
	if displayName, ok := s.D.GetOk("display_name"); ok {
		opts.DisplayName = displayName.(string)
	}

	s.Resource, e = s.Client.UpdateInstance(s.D.Id(), opts)
	return
}

func (s *InstanceResourceCrud) SetData() {
	s.D.Set("availability_domain", s.Resource.AvailabilityDomain)
	s.D.Set("compartment_id", s.Resource.CompartmentID)
	s.D.Set("display_name", s.Resource.DisplayName)
	s.D.Set("image", s.Resource.ImageID)
	s.D.Set("ipxe_script", s.Resource.IpxeScript)
	s.D.Set("metadata", s.Resource.Metadata)
	s.D.Set("region", s.Resource.Region)
	s.D.Set("shape", s.Resource.Shape)
	s.D.Set("state", s.Resource.State)
	s.D.Set("time_created", s.Resource.TimeCreated.String())
	s.D.Set("public_ip", s.public_ip)
	s.D.Set("private_ip", s.private_ip)
}

func (s *InstanceResourceCrud) Delete() (e error) {
	return s.Client.TerminateInstance(s.D.Id(), nil)
}
<commit_msg>Only get ip addresses of instance when the instance is running<commit_after>// Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.

package main

import (
	"encoding/json"
	"errors"
	"log"

	"github.com/MustWin/baremetal-sdk-go"
	"github.com/hashicorp/terraform/helper/schema"

	"github.com/oracle/terraform-provider-oci/crud"
	"github.com/oracle/terraform-provider-oci/options"
)

func InstanceResource() *schema.Resource {
	return &schema.Resource{
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},
		Timeouts: &schema.ResourceTimeout{
			Create: &crud.TwoHours,
			Update: &crud.TwoHours,
			Delete: &crud.TwoHours,
		},
		Create: createInstance,
		Read:   readInstance,
		Update: updateInstance,
		Delete: deleteInstance,
		Schema: map[string]*schema.Schema{
			"create_vnic_details": {
				Type:     schema.TypeMap,
				Optional: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"assign_public_ip": {
							Type:     schema.TypeBool,
							Optional: true,
						},
						"display_name": {
							Type:     schema.TypeString,
							Optional: true,
						},
						"hostname_label": {
							Type:     schema.TypeString,
							Optional: true,
						},
						"private_ip": {
							Type:     schema.TypeString,
							Optional: true,
						},
						"subnet_id": {
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
			},
			"availability_domain": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"compartment_id": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"display_name": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"hostname_label": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"id": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"image": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"ipxe_script": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"metadata": {
				Type:     schema.TypeMap,
				Optional: true,
				Elem:     schema.TypeString,
				ForceNew: true,
			},
			"extended_metadata": {
				Type:     schema.TypeMap,
				Optional: true,
				ForceNew: true,
				Elem:     schema.TypeString,
			},
			"region": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"shape": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"state": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"subnet_id": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},
			"time_created": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"public_ip": {
				Type:     schema.TypeString,
				Required: false,
				Computed: true,
			},
			"private_ip": {
				Type:     schema.TypeString,
				Required: false,
				Computed: true,
			},
		},
	}
}

func createInstance(d *schema.ResourceData, m interface{}) (e error) {
	sync := &InstanceResourceCrud{}
	sync.D = d
	sync.Client = m.(*baremetal.Client)
	return crud.CreateResource(d, sync)
}

func readInstance(d *schema.ResourceData, m interface{}) (e error) {
	sync := &InstanceResourceCrud{}
	sync.D = d
	sync.Client = m.(*baremetal.Client)
	return crud.ReadResource(sync)
}

func updateInstance(d *schema.ResourceData, m interface{}) (e error) {
	sync := &InstanceResourceCrud{}
	sync.D = d
	sync.Client = m.(*baremetal.Client)
	return crud.UpdateResource(d, sync)
}

func deleteInstance(d *schema.ResourceData, m interface{}) (e error) {
	sync := &InstanceResourceCrud{}
	sync.D = d
	sync.Client = m.(*baremetal.Client)
	return crud.DeleteResource(d, sync)
}

type InstanceResourceCrud struct {
	crud.BaseCrud
	Resource *baremetal.Instance

	// Computed fields
	public_ip  string
	private_ip string
}

func (s *InstanceResourceCrud) ID() string {
	return s.Resource.ID
}

func (s *InstanceResourceCrud) CreatedPending() []string {
	return []string{
		baremetal.ResourceProvisioning,
		baremetal.ResourceStarting,
	}
}

func (s *InstanceResourceCrud) CreatedTarget() []string {
	return []string{baremetal.ResourceRunning}
}

func (s *InstanceResourceCrud) DeletedPending() []string {
	return []string{baremetal.ResourceTerminating}
}

func (s *InstanceResourceCrud) DeletedTarget() []string {
	return []string{baremetal.ResourceTerminated}
}

func resourceInstanceMapToMetadata(rm map[string]interface{}) map[string]string {
	result := map[string]string{}
	for k, v := range rm {
		result[k] = v.(string)
	}
	return result
}

func mapToExtendedMetadata(rm map[string]interface{}) map[string]interface{} {
	result := make(map[string]interface{})
	for k, v := range rm {
		val := make(map[string]interface{})
		//Use the string value that was passed if it is not a valid JSON string
		if err := json.Unmarshal([]byte(v.(string)), &val); err == nil {
			result[k] = val
		} else {
			result[k] = v.(string)
		}
	}
	return result
}

func (s *InstanceResourceCrud) Create() (e error) {
	availabilityDomain := s.D.Get("availability_domain").(string)
	compartmentID := s.D.Get("compartment_id").(string)
	image := s.D.Get("image").(string)
	shape := s.D.Get("shape").(string)
	subnet := s.D.Get("subnet_id").(string)

	opts := &baremetal.LaunchInstanceOptions{}
	if displayName, ok := s.D.GetOk("display_name"); ok {
		opts.DisplayName = displayName.(string)
	}
	if hostnameLabel, ok := s.D.GetOk("hostname_label"); ok {
		opts.HostnameLabel = hostnameLabel.(string)
	}
	if ipxeScript, ok := s.D.GetOk("ipxe_script"); ok {
		opts.IpxeScript = ipxeScript.(string)
	}

	if rawMetadata, ok := s.D.GetOk("metadata"); ok {
		metadata := resourceInstanceMapToMetadata(rawMetadata.(map[string]interface{}))
		opts.Metadata = metadata
	}

	if rawExtendedMetadata, ok := s.D.GetOk("extended_metadata"); ok {
		extendedMetadata := mapToExtendedMetadata(rawExtendedMetadata.(map[string]interface{}))
		opts.ExtendedMetadata = extendedMetadata
	}

	if rawVnic, ok := s.D.GetOk("create_vnic_details"); ok {
		opts.CreateVnicOptions = SetCreateVnicOptions(rawVnic)
	}

	s.Resource, e = s.Client.LaunchInstance(
		availabilityDomain,
		compartmentID,
		image,
		shape,
		subnet,
		opts)
	return
}

/*
 * Return the public, private IP pair associated with the instance's primary Vnic.
 *
 * NOTE while the instance is still being created, calls to this function
 * can return  an error priort to the Vnic being attached.
 */
func (s *InstanceResourceCrud) getInstanceIPs() (public_ip string, private_ip string, e error) {
	compartmentID := s.Resource.CompartmentID

	opts := &baremetal.ListVnicAttachmentsOptions{}
	opts.InstanceID = s.Resource.ID

	// Page through all VNIC attachments for the instance.
	var attachments []baremetal.VnicAttachment
	for {
		var result *baremetal.ListVnicAttachments
		if result, e = s.Client.ListVnicAttachments(compartmentID, opts); e != nil {
			break
		}

		attachments = append(attachments, result.Attachments...)
		if hasNextPage := options.SetNextPageOption(result.NextPage, &opts.ListOptions.PageListOptions); !hasNextPage {
			break
		}
	}

	if len(attachments) < 1 {
		return "", "", errors.New("No VNIC attachments found.")
	}

	for _, attachment := range attachments {
		if attachment.State == baremetal.ResourceAttached {
			vnic, _ := s.Client.GetVnic(attachment.VnicID)

			// Ignore errors on GetVnic, since we might not have permissions to view some secondary VNICs.
			if vnic != nil && vnic.IsPrimary {
				return vnic.PublicIPAddress, vnic.PrivateIPAddress, nil
			}
		}
	}

	return "", "", errors.New("Primary VNIC not found.")
}

func (s *InstanceResourceCrud) Get() (e error) {
	s.Resource, e = s.Client.GetInstance(s.D.Id())

	if e != nil {
		return e
	}

	// Compute instance IPs through attached Vnic
	if s.Resource.State != baremetal.ResourceRunning {
		return
	}
	public_ip, private_ip, e2 := s.getInstanceIPs()
	if e2 != nil {
		log.Printf("[DEBUG] Primary VNIC could not be found: %q (InstanceID: %q, State: %q)", e2, s.Resource.ID, s.Resource.State)
	}

	if public_ip != "" {
		s.public_ip = public_ip
	}
	if private_ip != "" {
		s.private_ip = private_ip
	}
	return
}

func (s *InstanceResourceCrud) Update() (e error) {
	opts := &baremetal.UpdateOptions{}
	if displayName, ok := s.D.GetOk("display_name"); ok {
		opts.DisplayName = displayName.(string)
	}

	s.Resource, e = s.Client.UpdateInstance(s.D.Id(), opts)
	return
}

func (s *InstanceResourceCrud) SetData() {
	s.D.Set("availability_domain", s.Resource.AvailabilityDomain)
	s.D.Set("compartment_id", s.Resource.CompartmentID)
	s.D.Set("display_name", s.Resource.DisplayName)
	s.D.Set("image", s.Resource.ImageID)
	s.D.Set("ipxe_script", s.Resource.IpxeScript)
	s.D.Set("metadata", s.Resource.Metadata)
	s.D.Set("region", s.Resource.Region)
	s.D.Set("shape", s.Resource.Shape)
	s.D.Set("state", s.Resource.State)
	s.D.Set("time_created", s.Resource.TimeCreated.String())
	s.D.Set("public_ip", s.public_ip)
	s.D.Set("private_ip", s.private_ip)
}

func (s *InstanceResourceCrud) Delete() (e error) {
	return s.Client.TerminateInstance(s.D.Id(), nil)
}
<|endoftext|>


<commit_before>package elasticsearch_test

import (
	"os"
	"testing"

	"encoding/json"
	"github.com/kyani-inc/storage/providers/elasticsearch"
	"github.com/subosito/gotenv"
	"reflect"
)

var (
	host, index, scheme, namespace, awsKey, awsSecret string
)

type product struct {
	Name        string      `json:"name"`
	Price       int         `json:"price"`
	Description description `json:"description"`
}

type description struct {
	Description string `json:"nickname"`
}

func init() {
	gotenv.Load(".env")
	host = os.Getenv("ES_HOST")
	index = os.Getenv("ES_INDEX")
	namespace = os.Getenv("ES_NAMESPACE")
	scheme = os.Getenv("ES_SCHEME")
	awsKey = os.Getenv("AWS_KEY")
	awsSecret = os.Getenv("AWS_SECRET")
}

func emptyVars() bool {
	return host == "" || index == "" || scheme == "" || awsKey == "" || awsSecret == ""

}

func TestES(t *testing.T) {
	if emptyVars() {
		t.Error("Must have ENV set")
	}

	es, err := elasticsearch.New(host, scheme, index, namespace, awsKey, awsSecret)

	if err != nil {
		t.Errorf("Building new ES client error %+v", err)
	}

	td := product{
		Name:        "Kyäni Sunrise",
		Price:       100,
		Description: description{Description: "Complete Nutrition & Antioxidant Powerhouse"},
	}

	data, err := json.Marshal(td)

	err = es.Put("Sunrise", data)

	if err != nil {
		t.Errorf("Error on Put error:%s", err)
	}

	crit := es.Get("Sunrise")

	if len(crit) < 1 {
		t.Errorf("Error on Get - data retrieved: %s", crit)
	}

	var container product

	err = json.Unmarshal(crit, &container)

	if err != nil {
		t.Errorf("Unmarshal error: %s", err)
	}

	if !(reflect.DeepEqual(td, container)) {
		t.Errorf("Incorrect data returned original key: %v, recieved: %v", td, container)
	}

	es.Delete("Sunrise")

	crit = es.Get("Sunrise")

	if len(crit) > 0 {
		t.Errorf("No successful deletion retrieved for:%v ", crit)
	}
}

// need to change to doctype being a part of the new func
// probably should call it category
<commit_msg>skip instead of fail for travis build<commit_after>package elasticsearch_test

import (
	"os"
	"testing"

	"encoding/json"
	"github.com/kyani-inc/storage/providers/elasticsearch"
	"github.com/subosito/gotenv"
	"reflect"
)

var (
	host, index, scheme, namespace, awsKey, awsSecret string
)

type product struct {
	Name        string      `json:"name"`
	Price       int         `json:"price"`
	Description description `json:"description"`
}

type description struct {
	Description string `json:"nickname"`
}

func init() {
	gotenv.Load(".env")
	host = os.Getenv("ES_HOST")
	index = os.Getenv("ES_INDEX")
	namespace = os.Getenv("ES_NAMESPACE")
	scheme = os.Getenv("ES_SCHEME")
	awsKey = os.Getenv("AWS_KEY")
	awsSecret = os.Getenv("AWS_SECRET")
}

func emptyVars() bool {
	return host == "" || index == "" || scheme == "" || awsKey == "" || awsSecret == ""

}

func TestES(t *testing.T) {
	if emptyVars() {
		t.Skip("Must have ENV set")
	}

	es, err := elasticsearch.New(host, scheme, index, namespace, awsKey, awsSecret)

	if err != nil {
		t.Errorf("Building new ES client error %+v", err)
	}

	td := product{
		Name:        "Kyäni Sunrise",
		Price:       100,
		Description: description{Description: "Complete Nutrition & Antioxidant Powerhouse"},
	}

	data, err := json.Marshal(td)

	err = es.Put("Sunrise", data)

	if err != nil {
		t.Errorf("Error on Put error:%s", err)
	}

	crit := es.Get("Sunrise")

	if len(crit) < 1 {
		t.Errorf("Error on Get - data retrieved: %s", crit)
	}

	var container product

	err = json.Unmarshal(crit, &container)

	if err != nil {
		t.Errorf("Unmarshal error: %s", err)
	}

	if !(reflect.DeepEqual(td, container)) {
		t.Errorf("Incorrect data returned original key: %v, recieved: %v", td, container)
	}

	es.Delete("Sunrise")

	crit = es.Get("Sunrise")

	if len(crit) > 0 {
		t.Errorf("No successful deletion retrieved for:%v ", crit)
	}
}

// need to change to doctype being a part of the new func
// probably should call it category
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"sync"
	"sync/atomic"
	"time"
)

type plugStats struct {
	Path      string
	Functions []string
}

type cacheStats struct {
	m          sync.Mutex
	Enabled    bool
	GetCount   uint64
	GetHits    uint64
	HitPercent float64
	SetCount   uint64
}

func (cs *cacheStats) setHitPercent() {
	cs.m.Lock()
	defer cs.m.Unlock()
	if cs.GetCount == 0 {
		cs.HitPercent = 0
		return
	}
	cs.HitPercent = float64(cs.GetHits) / float64(cs.GetCount)
}

// Get increments GetCount safely
func (cs *cacheStats) Get() {
	atomic.AddUint64(&cs.GetCount, 1)
}

// Hit increments GetHits safely
func (cs *cacheStats) Hit() {
	atomic.AddUint64(&cs.GetHits, 1)
}

// Set increments SetCount safely
func (cs *cacheStats) Set() {
	atomic.AddUint64(&cs.SetCount, 1)
}

// serverStats holds a bunch of global data.  This is only threadsafe when
// calling functions, so don't directly manipulate anything except when you
// know only one thread can possibly exist!  (e.g., when first setting up the
// object)
type serverStats struct {
	m           sync.Mutex
	InfoCache   cacheStats
	TileCache   cacheStats
	Plugins     []plugStats
	RAISVersion string
	RAISBuild   string
	ServerStart time.Time
	Uptime      string
}

func (s *serverStats) setUptime() {
	s.m.Lock()
	s.Uptime = time.Since(s.ServerStart).Round(time.Second).String()
	s.m.Unlock()
}

// Serialize writes the stats data to w in JSON format
func (s *serverStats) Serialize() ([]byte, error) {
	// Calculate derived stats only on serializations
	s.setUptime()
	s.InfoCache.setHitPercent()
	s.TileCache.setHitPercent()

	return json.Marshal(s)
}
<commit_msg>rais-server: add cache length stat<commit_after>package main

import (
	"encoding/json"
	"sync"
	"sync/atomic"
	"time"
)

type plugStats struct {
	Path      string
	Functions []string
}

type cacheStats struct {
	m          sync.Mutex
	Enabled    bool
	GetCount   uint64
	GetHits    uint64
	HitPercent float64
	SetCount   uint64
	Length     int
}

func (cs *cacheStats) setHitPercent() {
	cs.m.Lock()
	defer cs.m.Unlock()
	if cs.GetCount == 0 {
		cs.HitPercent = 0
		return
	}
	cs.HitPercent = float64(cs.GetHits) / float64(cs.GetCount)
}

// Get increments GetCount safely
func (cs *cacheStats) Get() {
	atomic.AddUint64(&cs.GetCount, 1)
}

// Hit increments GetHits safely
func (cs *cacheStats) Hit() {
	atomic.AddUint64(&cs.GetHits, 1)
}

// Set increments SetCount safely
func (cs *cacheStats) Set() {
	atomic.AddUint64(&cs.SetCount, 1)
}

// serverStats holds a bunch of global data.  This is only threadsafe when
// calling functions, so don't directly manipulate anything except when you
// know only one thread can possibly exist!  (e.g., when first setting up the
// object)
type serverStats struct {
	m           sync.Mutex
	InfoCache   cacheStats
	TileCache   cacheStats
	Plugins     []plugStats
	RAISVersion string
	RAISBuild   string
	ServerStart time.Time
	Uptime      string
}

// Serialize writes the stats data to w in JSON format
func (s *serverStats) Serialize() ([]byte, error) {
	s.calculateDerivedStats()
	return json.Marshal(s)
}

// calculateDerivedStats computes things we don't need to store real-time, such
// as cache hit percent, uptime, etc.
func (s *serverStats) calculateDerivedStats() {
	s.m.Lock()

	s.Uptime = time.Since(s.ServerStart).Round(time.Second).String()
	if infoCache != nil {
		s.InfoCache.setHitPercent()
		s.InfoCache.Length = infoCache.Len()
	}
	if tileCache != nil {
		s.TileCache.setHitPercent()
		s.TileCache.Length = tileCache.Len()
	}

	s.m.Unlock()
}
<|endoftext|>


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

package roaring

///////////////////////////////////////////////////////////////////////////

var containerWidth uint64 = 65536

////////////////// array
func arrayEmpty() []uint16 {
	return make([]uint16, 0)
}

func arrayFull() []uint16 {
	array := make([]uint16, containerWidth)
	for i := 0; i < int(containerWidth); i++ {
		array[i] = uint16(i)
	}
	return array
}

func arrayFirstBitSet() []uint16 {
	array := make([]uint16, 0)
	array = append(array, uint16(0))
	return array
}

func arrayLastBitSet() []uint16 {
	array := make([]uint16, 0)
	array = append(array, uint16(65535))
	return array
}

func arrayFirstBitUnset() []uint16 {
	array := make([]uint16, containerWidth-1)
	for i := 1; i < int(containerWidth); i++ {
		array[i-1] = uint16(i)
	}
	return array
}

func arrayLastBitUnset() []uint16 {
	array := make([]uint16, containerWidth-1)
	for i := 0; i < int(containerWidth)-1; i++ {
		array[i] = uint16(i)
	}
	return array
}

func arrayInnerBitsSet() []uint16 {
	array := make([]uint16, containerWidth-2)
	for i := 1; i < int(containerWidth)-1; i++ {
		array[i-1] = uint16(i)
	}
	return array
}

func arrayOuterBitsSet() []uint16 {
	array := make([]uint16, 0)
	array = append(array, uint16(0))
	array = append(array, uint16(65535))
	return array
}

////////////////// bitmap
func bitmapEmpty() []uint64 {
	return make([]uint64, bitmapN)
}

func bitmapFull() []uint64 {
	bitmap := make([]uint64, bitmapN)
	for i := 0; i < bitmapN; i++ {
		bitmap[i] = 0xFFFFFFFFFFFFFFFF
	}
	return bitmap
}

func bitmapFirstBitSet() []uint64 {
	bitmap := make([]uint64, bitmapN)
	bitmap[0] = 0x0000000000000001
	return bitmap
}

func bitmapLastBitSet() []uint64 {
	bitmap := make([]uint64, bitmapN)
	bitmap[bitmapN-1] = 0x8000000000000000
	return bitmap
}

func bitmapFirstBitUnset() []uint64 {
	bitmap := make([]uint64, bitmapN)
	bitmap[0] = 0xFFFFFFFFFFFFFFFE
	for i := 1; i < bitmapN; i++ {
		bitmap[i] = 0xFFFFFFFFFFFFFFFF
	}
	return bitmap
}

func bitmapLastBitUnset() []uint64 {
	bitmap := make([]uint64, bitmapN)
	for i := 0; i < bitmapN-1; i++ {
		bitmap[i] = 0xFFFFFFFFFFFFFFFF
	}
	bitmap[bitmapN-1] = 0x7FFFFFFFFFFFFFFF
	return bitmap
}

func bitmapInnerBitsSet() []uint64 {
	bitmap := make([]uint64, bitmapN)
	bitmap[0] = 0xFFFFFFFFFFFFFFFE
	for i := 1; i < bitmapN-1; i++ {
		bitmap[i] = 0xFFFFFFFFFFFFFFFF
	}
	bitmap[bitmapN-1] = 0x7FFFFFFFFFFFFFFF
	return bitmap
}

func bitmapOuterBitsSet() []uint64 {
	bitmap := make([]uint64, bitmapN)
	bitmap[0] = 0x0000000000000001
	for i := 1; i < bitmapN-1; i++ {
		bitmap[i] = 0x0000000000000000
	}
	bitmap[bitmapN-1] = 0x8000000000000000
	return bitmap
}

////////////////// run
func runEmpty() []interval16 {
	return make([]interval16, 0)
}

func runFull() []interval16 {
	run := make([]interval16, 0)
	run = append(run, interval16{start: 0, last: 65535})
	return run
}

func runFirstBitSet() []interval16 {
	run := make([]interval16, 0)
	run = append(run, interval16{start: 0, last: 0})
	return run
}

func runLastBitSet() []interval16 {
	run := make([]interval16, 0)
	run = append(run, interval16{start: 65535, last: 65535})
	return run
}

func runFirstBitUnset() []interval16 {
	run := make([]interval16, 0)
	run = append(run, interval16{start: 1, last: 65535})
	return run
}

func runLastBitUnset() []interval16 {
	run := make([]interval16, 0)
	run = append(run, interval16{start: 0, last: 65534})
	return run
}

func runInnerBitsSet() []interval16 {
	run := make([]interval16, 0)
	run = append(run, interval16{start: 1, last: 65534})
	return run
}

func runOuterBitsSet() []interval16 {
	run := make([]interval16, 0)
	run = append(run, interval16{start: 0, last: 0})
	run = append(run, interval16{start: 65535, last: 65535})
	return run
}

///////////////////////////////////////////////////////////////////////////

type testOp struct {
	f   func(a, b *container) *container
	x   string
	y   string
	exp string
}

func doContainer(containerType byte, data interface{}) *container {
	c := &container{
		containerType: containerType,
	}

	switch containerType {
	case ContainerArray:
		c.array = data.([]uint16)
	case ContainerBitmap:
		c.bitmap = data.([]uint64)
	case ContainerRun:
		c.runs = data.([]interval16)
	}
	c.n = c.count()

	return c
}

func setupContainerTests() map[byte]map[string]*container {

	cts := make(map[byte]map[string]*container)

	// array containers
	cts[ContainerArray] = map[string]*container{
		"empty":         doContainer(ContainerArray, arrayEmpty()),
		"full":          doContainer(ContainerArray, arrayFull()),
		"firstBitSet":   doContainer(ContainerArray, arrayFirstBitSet()),
		"lastBitSet":    doContainer(ContainerArray, arrayLastBitSet()),
		"firstBitUnset": doContainer(ContainerArray, arrayFirstBitUnset()),
		"lastBitUnset":  doContainer(ContainerArray, arrayLastBitUnset()),
		"innerBitsSet":  doContainer(ContainerArray, arrayInnerBitsSet()),
		"outerBitsSet":  doContainer(ContainerArray, arrayOuterBitsSet()),
	}

	// bitmap containers
	cts[ContainerBitmap] = map[string]*container{
		"empty":         doContainer(ContainerBitmap, bitmapEmpty()),
		"full":          doContainer(ContainerBitmap, bitmapFull()),
		"firstBitSet":   doContainer(ContainerBitmap, bitmapFirstBitSet()),
		"lastBitSet":    doContainer(ContainerBitmap, bitmapLastBitSet()),
		"firstBitUnset": doContainer(ContainerBitmap, bitmapFirstBitUnset()),
		"lastBitUnset":  doContainer(ContainerBitmap, bitmapLastBitUnset()),
		"innerBitsSet":  doContainer(ContainerBitmap, bitmapInnerBitsSet()),
		"outerBitsSet":  doContainer(ContainerBitmap, bitmapOuterBitsSet()),
	}

	// run containers
	cts[ContainerRun] = map[string]*container{
		"empty":         doContainer(ContainerRun, runEmpty()),
		"full":          doContainer(ContainerRun, runFull()),
		"firstBitSet":   doContainer(ContainerRun, runFirstBitSet()),
		"lastBitSet":    doContainer(ContainerRun, runLastBitSet()),
		"firstBitUnset": doContainer(ContainerRun, runFirstBitUnset()),
		"lastBitUnset":  doContainer(ContainerRun, runLastBitUnset()),
		"innerBitsSet":  doContainer(ContainerRun, runInnerBitsSet()),
		"outerBitsSet":  doContainer(ContainerRun, runOuterBitsSet()),
	}

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

package roaring

///////////////////////////////////////////////////////////////////////////

var containerWidth uint64 = 65536

////////////////// array
func arrayEmpty() []uint16 {
	return make([]uint16, 0)
}

func arrayFull() []uint16 {
	array := make([]uint16, containerWidth)
	for i := 0; i < int(containerWidth); i++ {
		array[i] = uint16(i)
	}
	return array
}

func arrayFirstBitSet() []uint16 {
	array := make([]uint16, 0)
	array = append(array, uint16(0))
	return array
}

func arrayLastBitSet() []uint16 {
	array := make([]uint16, 0)
	array = append(array, uint16(65535))
	return array
}

func arrayFirstBitUnset() []uint16 {
	array := make([]uint16, containerWidth-1)
	for i := 1; i < int(containerWidth); i++ {
		array[i-1] = uint16(i)
	}
	return array
}

func arrayLastBitUnset() []uint16 {
	array := make([]uint16, containerWidth-1)
	for i := 0; i < int(containerWidth)-1; i++ {
		array[i] = uint16(i)
	}
	return array
}

func arrayInnerBitsSet() []uint16 {
	array := make([]uint16, containerWidth-2)
	for i := 1; i < int(containerWidth)-1; i++ {
		array[i-1] = uint16(i)
	}
	return array
}

func arrayOuterBitsSet() []uint16 {
	return []uint16{0, 65535}
}

////////////////// bitmap
func bitmapEmpty() []uint64 {
	return make([]uint64, bitmapN)
}

func bitmapFull() []uint64 {
	bitmap := make([]uint64, bitmapN)
	for i := 0; i < bitmapN; i++ {
		bitmap[i] = 0xFFFFFFFFFFFFFFFF
	}
	return bitmap
}

func bitmapFirstBitSet() []uint64 {
	bitmap := make([]uint64, bitmapN)
	bitmap[0] = 0x0000000000000001
	return bitmap
}

func bitmapLastBitSet() []uint64 {
	bitmap := make([]uint64, bitmapN)
	bitmap[bitmapN-1] = 0x8000000000000000
	return bitmap
}

func bitmapFirstBitUnset() []uint64 {
	bitmap := bitmapFull()
	bitmap[0] = 0xFFFFFFFFFFFFFFFE
	return bitmap
}

func bitmapLastBitUnset() []uint64 {
	bitmap := bitmapFull()
	bitmap[bitmapN-1] = 0x7FFFFFFFFFFFFFFF
	return bitmap
}

func bitmapInnerBitsSet() []uint64 {
	bitmap := bitmapFull()
	bitmap[0] = 0xFFFFFFFFFFFFFFFE
	bitmap[bitmapN-1] = 0x7FFFFFFFFFFFFFFF
	return bitmap
}

func bitmapOuterBitsSet() []uint64 {
	bitmap := bitmapEmpty()
	bitmap[0] = 0x0000000000000001
	bitmap[bitmapN-1] = 0x8000000000000000
	return bitmap
}

////////////////// run
func runEmpty() []interval16 {
	return make([]interval16, 0)
}

func runFull() []interval16 {
	run := make([]interval16, 0)
	run = append(run, interval16{start: 0, last: 65535})
	return run
}

func runFirstBitSet() []interval16 {
	run := make([]interval16, 0)
	run = append(run, interval16{start: 0, last: 0})
	return run
}

func runLastBitSet() []interval16 {
	run := make([]interval16, 0)
	run = append(run, interval16{start: 65535, last: 65535})
	return run
}

func runFirstBitUnset() []interval16 {
	run := make([]interval16, 0)
	run = append(run, interval16{start: 1, last: 65535})
	return run
}

func runLastBitUnset() []interval16 {
	run := make([]interval16, 0)
	run = append(run, interval16{start: 0, last: 65534})
	return run
}

func runInnerBitsSet() []interval16 {
	run := make([]interval16, 0)
	run = append(run, interval16{start: 1, last: 65534})
	return run
}

func runOuterBitsSet() []interval16 {
	run := make([]interval16, 0)
	run = append(run, interval16{start: 0, last: 0})
	run = append(run, interval16{start: 65535, last: 65535})
	return run
}

///////////////////////////////////////////////////////////////////////////

type testOp struct {
	f   func(a, b *container) *container
	x   string
	y   string
	exp string
}

func doContainer(containerType byte, data interface{}) *container {
	c := &container{
		containerType: containerType,
	}

	switch containerType {
	case ContainerArray:
		c.array = data.([]uint16)
	case ContainerBitmap:
		c.bitmap = data.([]uint64)
	case ContainerRun:
		c.runs = data.([]interval16)
	}
	c.n = c.count()

	return c
}

func setupContainerTests() map[byte]map[string]*container {

	cts := make(map[byte]map[string]*container)

	// array containers
	cts[ContainerArray] = map[string]*container{
		"empty":         doContainer(ContainerArray, arrayEmpty()),
		"full":          doContainer(ContainerArray, arrayFull()),
		"firstBitSet":   doContainer(ContainerArray, arrayFirstBitSet()),
		"lastBitSet":    doContainer(ContainerArray, arrayLastBitSet()),
		"firstBitUnset": doContainer(ContainerArray, arrayFirstBitUnset()),
		"lastBitUnset":  doContainer(ContainerArray, arrayLastBitUnset()),
		"innerBitsSet":  doContainer(ContainerArray, arrayInnerBitsSet()),
		"outerBitsSet":  doContainer(ContainerArray, arrayOuterBitsSet()),
	}

	// bitmap containers
	cts[ContainerBitmap] = map[string]*container{
		"empty":         doContainer(ContainerBitmap, bitmapEmpty()),
		"full":          doContainer(ContainerBitmap, bitmapFull()),
		"firstBitSet":   doContainer(ContainerBitmap, bitmapFirstBitSet()),
		"lastBitSet":    doContainer(ContainerBitmap, bitmapLastBitSet()),
		"firstBitUnset": doContainer(ContainerBitmap, bitmapFirstBitUnset()),
		"lastBitUnset":  doContainer(ContainerBitmap, bitmapLastBitUnset()),
		"innerBitsSet":  doContainer(ContainerBitmap, bitmapInnerBitsSet()),
		"outerBitsSet":  doContainer(ContainerBitmap, bitmapOuterBitsSet()),
	}

	// run containers
	cts[ContainerRun] = map[string]*container{
		"empty":         doContainer(ContainerRun, runEmpty()),
		"full":          doContainer(ContainerRun, runFull()),
		"firstBitSet":   doContainer(ContainerRun, runFirstBitSet()),
		"lastBitSet":    doContainer(ContainerRun, runLastBitSet()),
		"firstBitUnset": doContainer(ContainerRun, runFirstBitUnset()),
		"lastBitUnset":  doContainer(ContainerRun, runLastBitUnset()),
		"innerBitsSet":  doContainer(ContainerRun, runInnerBitsSet()),
		"outerBitsSet":  doContainer(ContainerRun, runOuterBitsSet()),
	}

	return cts
}
<|endoftext|>