<commit_before>package main

import (
	"github.com/theojulienne/go-wireless/wpactl"
	"log"
)

type WifiManager struct {
	Controller *wpactl.WPAController
	stateChange []chan string
}

const (
	WifiStateDisconnected = "disconnected"
	WifiStateConnected = "connected"
	WifiStateInvalidKey = "invalid_key"
)

func NewWifiManager(iface string) (*WifiManager, error) {
	ctl, err := wpactl.NewController(iface)
	if err != nil {
		return nil, err
	}

	manager := &WifiManager{}
	manager.stateChange = make([]chan string, 0)
	manager.Controller = ctl

	go manager.eventLoop()

	return manager, nil
}

func (m *WifiManager) WatchState() (chan string) {
	ch := make(chan string, 128)

	m.stateChange = append(m.stateChange, ch)

	return ch
}

func (m *WifiManager) UnwatchState(target chan string) {
	for i,c := range m.stateChange {
		if c == target {
			m.stateChange[i] = nil
		}
	}
}

func (m *WifiManager) emitState(state string) {
	for _,ch := range m.stateChange {
		if ch != nil {
			ch <- state
		}
	}
}

func (m *WifiManager) eventLoop() {
	for {
		event := <- m.Controller.EventChannel
		log.Println(event)
		switch event.Name {
			case "CTRL-EVENT-DISCONNECTED":
				m.emitState(WifiStateDisconnected)
			case "CTRL-EVENT-CONNECTED":
				m.emitState(WifiStateConnected)
			case "CTRL-EVENT-SSID-TEMP-DISABLED":
				m.emitState(WifiStateInvalidKey)
		}
	}
}

func (m *WifiManager) Cleanup() {
	m.Controller.Cleanup()
}

func (m *WifiManager) WifiConfigured() (bool, error) {
	networks, err := m.Controller.ListNetworks()
	if err != nil {
		return false, nil
	}
	enabledNetworks := 0
	for _,network := range networks {
		result, _ := m.Controller.GetNetworkSetting(network.Id, "disabled")
		if result == "1" {
			continue
		}
		enabledNetworks += 1
	}
	return (enabledNetworks > 0), nil
}

func (m *WifiManager) DisableAllNetworks() (error) {
	networks, err := m.Controller.ListNetworks()
	if err != nil {
		return false, nil
	}

	for _,network := range networks {
		m.Controller.DisableNetwork(network.Id)
	}
}

func (m *WifiManager) AddStandardNetwork(ssid string, key string) (error) {
	i, err := m.Controller.AddNetwork()
	if err != nil {
		return err
	}
	// FIXME: handle errors for all of these!
	m.Controller.SetNetworkSettingString(i, "ssid", ssid)
	m.Controller.SetNetworkSettingString(i, "psk", key)
	m.Controller.SetNetworkSettingRaw(i, "scan_ssid", "1")
	m.Controller.SetNetworkSettingRaw(i, "key_mgmt", "WPA-PSK")
	m.Controller.SelectNetwork(i)
	m.Controller.SaveConfiguration()

	return nil
}

<commit_msg>Fix typos.<commit_after>package main

import (
	"github.com/theojulienne/go-wireless/wpactl"
	"log"
)

type WifiManager struct {
	Controller *wpactl.WPAController
	stateChange []chan string
}

const (
	WifiStateDisconnected = "disconnected"
	WifiStateConnected = "connected"
	WifiStateInvalidKey = "invalid_key"
)

func NewWifiManager(iface string) (*WifiManager, error) {
	ctl, err := wpactl.NewController(iface)
	if err != nil {
		return nil, err
	}

	manager := &WifiManager{}
	manager.stateChange = make([]chan string, 0)
	manager.Controller = ctl

	go manager.eventLoop()

	return manager, nil
}

func (m *WifiManager) WatchState() (chan string) {
	ch := make(chan string, 128)

	m.stateChange = append(m.stateChange, ch)

	return ch
}

func (m *WifiManager) UnwatchState(target chan string) {
	for i,c := range m.stateChange {
		if c == target {
			m.stateChange[i] = nil
		}
	}
}

func (m *WifiManager) emitState(state string) {
	for _,ch := range m.stateChange {
		if ch != nil {
			ch <- state
		}
	}
}

func (m *WifiManager) eventLoop() {
	for {
		event := <- m.Controller.EventChannel
		log.Println(event)
		switch event.Name {
			case "CTRL-EVENT-DISCONNECTED":
				m.emitState(WifiStateDisconnected)
			case "CTRL-EVENT-CONNECTED":
				m.emitState(WifiStateConnected)
			case "CTRL-EVENT-SSID-TEMP-DISABLED":
				m.emitState(WifiStateInvalidKey)
		}
	}
}

func (m *WifiManager) Cleanup() {
	m.Controller.Cleanup()
}

func (m *WifiManager) WifiConfigured() (bool, error) {
	networks, err := m.Controller.ListNetworks()
	if err != nil {
		return false, nil
	}
	enabledNetworks := 0
	for _,network := range networks {
		result, _ := m.Controller.GetNetworkSetting(network.Id, "disabled")
		if result == "1" {
			continue
		}
		enabledNetworks += 1
	}
	return (enabledNetworks > 0), nil
}

func (m *WifiManager) DisableAllNetworks() (error) {
	networks, err := m.Controller.ListNetworks()
	if err != nil {
		return err
	}

	for _,network := range networks {
		m.Controller.DisableNetwork(network.Id)
	}

	return nil
}

func (m *WifiManager) AddStandardNetwork(ssid string, key string) (error) {
	i, err := m.Controller.AddNetwork()
	if err != nil {
		return err
	}
	// FIXME: handle errors for all of these!
	m.Controller.SetNetworkSettingString(i, "ssid", ssid)
	m.Controller.SetNetworkSettingString(i, "psk", key)
	m.Controller.SetNetworkSettingRaw(i, "scan_ssid", "1")
	m.Controller.SetNetworkSettingRaw(i, "key_mgmt", "WPA-PSK")
	m.Controller.SelectNetwork(i)
	m.Controller.SaveConfiguration()

	return nil
}

<|endoftext|>


<commit_before>package services/cloudca

type Tier struct {

}

type TierService interface {
	Get(id string) (Tier, error)
	GetByName(name string) (Tier, error)
	List() ([]Tier, error)
}

type TierApi struct {
	entityService EntityService
}

func NewInstanceService(apiClient CCAApiClient, serviceCode string, environmentName string) TierService {
	return TierApi{
		"entityService": NewEntityService(apiClient, serviceCode, environmentName, TIER_ENTITY_TYPE)
	}
}

func (tierApi TierApi) Get(id string) (Tier, error) {
	return Tier{}, nil
}

func (tierApi TierApi) GetByName(name string) (Tier, error) {
	return Tier{}, nil
}

func (tierApi TierApi) List() ([]Tier, error) {
	return []Tier{}, nil
}
<commit_msg>Added List(vpcId string) method to TierService<commit_after>package services/cloudca

type Tier struct {

}

type TierService interface {
	Get(id string) (Tier, error)
	GetByName(name string) (Tier, error)
	List() ([]Tier, error)
	List(vpcId string) ([]Tier, error)
}

type TierApi struct {
	entityService EntityService
}

func NewInstanceService(apiClient CCAApiClient, serviceCode string, environmentName string) TierService {
	return TierApi{
		"entityService": NewEntityService(apiClient, serviceCode, environmentName, TIER_ENTITY_TYPE)
	}
}

func (tierApi TierApi) Get(id string) (Tier, error) {
	return Tier{}, nil
}

func (tierApi TierApi) GetByName(name string) (Tier, error) {
	return Tier{}, nil
}

func (tierApi TierApi) List() ([]Tier, error) {
	return []Tier{}, nil
}

func (tierApi TierApi) List(vpcId string) ([]Tier, error) {
	return []Tier{}, nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"os"
	"regexp"

	ktail "github.com/fujiwara/kinesis-tailf"

	"github.com/apex/go-apex"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/kinesis"
)

type KinesisEvent struct {
	Records []struct {
		Kinesis struct {
			KinesisSchemaVersion        string  `json:"kinesisSchemaVersion"`
			PartitionKey                string  `json:"partitionKey"`
			SequenceNumber              string  `json:"sequenceNumber"`
			Data                        []byte  `json:"data"`
			ApproximateArrivalTimestamp float64 `json:"approximateArrivalTimestamp"`
		} `json:"kinesis"`
		EventSource       string `json:"eventSource"`
		EventVersion      string `json:"eventVersion"`
		EventID           string `json:"eventID"`
		EventName         string `json:"eventName"`
		InvokeIdentityArn string `json:"invokeIdentityArn"`
		AwsRegion         string `json:"awsRegion"`
		EventSourceARN    string `json:"eventSourceARN"`
	} `json:"Records"`
}

var (
	ch         chan []byte
	ksv        *kinesis.Kinesis
	streamName *string
	matcher    *regexp.Regexp
)

func init() {
	ksv = kinesis.New(session.New())
	streamName = aws.String(os.Getenv("STREAM_NAME"))
	matcher = regexp.MustCompile(os.Getenv("MATCH"))
}

func main() {
	apex.HandleFunc(proceess)
}

func proceess(event json.RawMessage, ctx *apex.Context) (interface{}, error) {
	var e KinesisEvent
	if err := json.Unmarshal(event, &e); err != nil {
		return nil, err
	}
	if len(e.Records) == 0 {
		return nil, nil
	}

	result := make([]byte, 4096)
	count := 0
	match := 0
	for _, record := range e.Records {
		data := record.Kinesis.Data
		rs, err := ktail.UnmarshalRecords(data)
		if err != nil {
			count++
			if matcher.Match(data) {
				match++
				result = append(result, data...)
				result = append(result, ktail.LF...)
			}
			continue
		}
		for _, r := range rs {
			count++
			if matcher.Match(r.Data) {
				match++
				result = append(result, r.Data...)
				result = append(result, ktail.LF...)
			}
		}
	}
	if len(result) == 0 {
		return nil, nil
	}
	log.Printf("records: event: %d processed: %d match: %d",
		len(e.Records),
		count,
		match,
	)
	return ksv.PutRecord(&kinesis.PutRecordInput{
		Data:         result,
		PartitionKey: aws.String(e.Records[0].Kinesis.PartitionKey),
		StreamName:   streamName,
	})
}
<commit_msg>remove unused variable<commit_after>package main

import (
	"encoding/json"
	"log"
	"os"
	"regexp"

	ktail "github.com/fujiwara/kinesis-tailf"

	"github.com/apex/go-apex"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/kinesis"
)

type KinesisEvent struct {
	Records []struct {
		Kinesis struct {
			KinesisSchemaVersion        string  `json:"kinesisSchemaVersion"`
			PartitionKey                string  `json:"partitionKey"`
			SequenceNumber              string  `json:"sequenceNumber"`
			Data                        []byte  `json:"data"`
			ApproximateArrivalTimestamp float64 `json:"approximateArrivalTimestamp"`
		} `json:"kinesis"`
		EventSource       string `json:"eventSource"`
		EventVersion      string `json:"eventVersion"`
		EventID           string `json:"eventID"`
		EventName         string `json:"eventName"`
		InvokeIdentityArn string `json:"invokeIdentityArn"`
		AwsRegion         string `json:"awsRegion"`
		EventSourceARN    string `json:"eventSourceARN"`
	} `json:"Records"`
}

var (
	ksv        *kinesis.Kinesis
	streamName *string
	matcher    *regexp.Regexp
)

func init() {
	ksv = kinesis.New(session.New())
	streamName = aws.String(os.Getenv("STREAM_NAME"))
	matcher = regexp.MustCompile(os.Getenv("MATCH"))
}

func main() {
	apex.HandleFunc(proceess)
}

func proceess(event json.RawMessage, ctx *apex.Context) (interface{}, error) {
	var e KinesisEvent
	if err := json.Unmarshal(event, &e); err != nil {
		return nil, err
	}
	if len(e.Records) == 0 {
		return nil, nil
	}

	result := make([]byte, 4096)
	count := 0
	match := 0
	for _, record := range e.Records {
		data := record.Kinesis.Data
		rs, err := ktail.UnmarshalRecords(data)
		if err != nil {
			count++
			if matcher.Match(data) {
				match++
				result = append(result, data...)
				result = append(result, ktail.LF...)
			}
			continue
		}
		for _, r := range rs {
			count++
			if matcher.Match(r.Data) {
				match++
				result = append(result, r.Data...)
				result = append(result, ktail.LF...)
			}
		}
	}
	if len(result) == 0 {
		return nil, nil
	}
	log.Printf("records: event: %d processed: %d match: %d",
		len(e.Records),
		count,
		match,
	)
	return ksv.PutRecord(&kinesis.PutRecordInput{
		Data:         result,
		PartitionKey: aws.String(e.Records[0].Kinesis.PartitionKey),
		StreamName:   streamName,
	})
}
<|endoftext|>


<commit_before>package multipartstreamer

import (
  "bytes"
  "fmt"
  "io"
  "io/ioutil"
  "mime/multipart"
  "net/http"
  "os"
)

type MultipartStreamer struct {
  ContentType   string
  bodyBuffer    *bytes.Buffer
  bodyWriter    *multipart.Writer
  closeBuffer   *bytes.Buffer
  fileHandle    *os.File
  contentLength int64
}

func New() (m *MultipartStreamer) {
  m = &MultipartStreamer{bodyBuffer: bytes.NewBufferString("")}

  m.bodyWriter = multipart.NewWriter(m.bodyBuffer)
  boundary := m.bodyWriter.Boundary()
  m.ContentType = "multipart/form-data; boundary=" + boundary

  closeBoundary := fmt.Sprintf("\r\n--%s--\r\n", boundary)
  m.closeBuffer = bytes.NewBufferString(closeBoundary)

  return
}

// Prepares a file and some form fields to be written to the multipart.Writer.
// Wraps up both WriteFields() and writeFile().
//
// key - The name of the field for the file data.
//
// filename - The name of the file to upload.
//
// fields - A map of form field keys and values.
func (m *MultipartStreamer) Write(key, filename string, fields map[string]string) (err error) {
  err = m.WriteFields(fields)
  if err != nil {
    return
  }

  err = m.WriteFile(key, filename)

  return
}

// Writes form fields to the multipart.Writer.
//
// fields   - A map of form field keys and values.
func (m *MultipartStreamer) WriteFields(fields map[string]string) error {
  var err error

  for key, value := range fields {
    err = m.bodyWriter.WriteField(key, value)
    if err != nil {
      return err
    }
  }

  return nil
}

// Prepares a file to be written to the multipart.Writer.
//
// key - The name of the field for the file data.
//
// filename - The name of the file to upload.
func (m *MultipartStreamer) WriteFile(key, filename string) (err error) {
  _, err = m.bodyWriter.CreateFormFile(key, filename)
  if err != nil {
    return
  }

  m.fileHandle, err = os.Open(filename)
  if err != nil {
    return
  }

  var stat os.FileInfo
  stat, err = m.fileHandle.Stat()
  m.contentLength = stat.Size()

  return
}

// Sets up the http.Request body, and some crucial HTTP headers.
func (m *MultipartStreamer) SetupRequest(req *http.Request) {
  req.Body = m.GetReader()
  req.Header.Add("Content-Type", m.ContentType)
  req.ContentLength = m.Len()
}

// Calculates the byte size of the multipart content.
func (m *MultipartStreamer) Len() int64 {
  return m.contentLength + int64(m.bodyBuffer.Len()) + int64(m.closeBuffer.Len())
}

// Gets an io.ReadCloser for passing to an http.Request.
func (m *MultipartStreamer) GetReader() io.ReadCloser {
  reader := io.MultiReader(m.bodyBuffer, m.fileHandle, m.closeBuffer)
  return ioutil.NopCloser(reader)
}
<commit_msg>gofmt<commit_after>package multipartstreamer

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
)

type MultipartStreamer struct {
	ContentType   string
	bodyBuffer    *bytes.Buffer
	bodyWriter    *multipart.Writer
	closeBuffer   *bytes.Buffer
	fileHandle    *os.File
	contentLength int64
}

func New() (m *MultipartStreamer) {
	m = &MultipartStreamer{bodyBuffer: bytes.NewBufferString("")}

	m.bodyWriter = multipart.NewWriter(m.bodyBuffer)
	boundary := m.bodyWriter.Boundary()
	m.ContentType = "multipart/form-data; boundary=" + boundary

	closeBoundary := fmt.Sprintf("\r\n--%s--\r\n", boundary)
	m.closeBuffer = bytes.NewBufferString(closeBoundary)

	return
}

// Prepares a file and some form fields to be written to the multipart.Writer.
// Wraps up both WriteFields() and writeFile().
//
// key - The name of the field for the file data.
//
// filename - The name of the file to upload.
//
// fields - A map of form field keys and values.
func (m *MultipartStreamer) Write(key, filename string, fields map[string]string) (err error) {
	err = m.WriteFields(fields)
	if err != nil {
		return
	}

	err = m.WriteFile(key, filename)

	return
}

// Writes form fields to the multipart.Writer.
//
// fields   - A map of form field keys and values.
func (m *MultipartStreamer) WriteFields(fields map[string]string) error {
	var err error

	for key, value := range fields {
		err = m.bodyWriter.WriteField(key, value)
		if err != nil {
			return err
		}
	}

	return nil
}

// Prepares a file to be written to the multipart.Writer.
//
// key - The name of the field for the file data.
//
// filename - The name of the file to upload.
func (m *MultipartStreamer) WriteFile(key, filename string) (err error) {
	_, err = m.bodyWriter.CreateFormFile(key, filename)
	if err != nil {
		return
	}

	m.fileHandle, err = os.Open(filename)
	if err != nil {
		return
	}

	var stat os.FileInfo
	stat, err = m.fileHandle.Stat()
	m.contentLength = stat.Size()

	return
}

// Sets up the http.Request body, and some crucial HTTP headers.
func (m *MultipartStreamer) SetupRequest(req *http.Request) {
	req.Body = m.GetReader()
	req.Header.Add("Content-Type", m.ContentType)
	req.ContentLength = m.Len()
}

func (m *MultipartStreamer) Boundary() string {
	return m.bodyWriter.Boundary()
}

// Calculates the byte size of the multipart content.
func (m *MultipartStreamer) Len() int64 {
	return m.contentLength + int64(m.bodyBuffer.Len()) + int64(m.closeBuffer.Len())
}

// Gets an io.ReadCloser for passing to an http.Request.
func (m *MultipartStreamer) GetReader() io.ReadCloser {
	reader := io.MultiReader(m.bodyBuffer, m.fileHandle, m.closeBuffer)
	return ioutil.NopCloser(reader)
}
<|endoftext|>


<commit_before>package pgtype_test

import (
	"reflect"
	"testing"

	"github.com/jackc/pgx/pgtype"
	"github.com/jackc/pgx/pgtype/testutil"
)

func TestHstoreTranscode(t *testing.T) {
	// text := func(s string) pgtype.Text {
	// 	return pgtype.Text{String: s, Status: pgtype.Present}
	// }

	values := []interface{}{
		&pgtype.Hstore{Map: map[string]pgtype.Text{}, Status: pgtype.Present},
		// &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("bar")}, Status: pgtype.Present},
		// &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("bar"), "baz": text("quz")}, Status: pgtype.Present},
		// &pgtype.Hstore{Map: map[string]pgtype.Text{"NULL": text("bar")}, Status: pgtype.Present},
		// &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("NULL")}, Status: pgtype.Present},
		// &pgtype.Hstore{Status: pgtype.Null},
	}

	// specialStrings := []string{
	// 	`"`,
	// 	`'`,
	// 	`\`,
	// 	`\\`,
	// 	`=>`,
	// 	` `,
	// 	`\ / / \\ => " ' " '`,
	// }
	// for _, s := range specialStrings {
	// 	// Special key values
	// 	values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{s + "foo": text("bar")}, Status: pgtype.Present})         // at beginning
	// 	values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo" + s + "bar": text("bar")}, Status: pgtype.Present}) // in middle
	// 	values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo" + s: text("bar")}, Status: pgtype.Present})         // at end
	// 	values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{s: text("bar")}, Status: pgtype.Present})                 // is key

	// 	// Special value values
	// 	values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text(s + "bar")}, Status: pgtype.Present})         // at beginning
	// 	values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("foo" + s + "bar")}, Status: pgtype.Present}) // in middle
	// 	values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("foo" + s)}, Status: pgtype.Present})         // at end
	// 	values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text(s)}, Status: pgtype.Present})                 // is key
	// }

	testutil.TestSuccessfulTranscodeEqFunc(t, "hstore", values, func(ai, bi interface{}) bool {
		a := ai.(pgtype.Hstore)
		b := bi.(pgtype.Hstore)

		if len(a.Map) != len(b.Map) || a.Status != b.Status {
			return false
		}

		for k := range a.Map {
			if a.Map[k] != b.Map[k] {
				return false
			}
		}

		return true
	})
}

func TestHstoreSet(t *testing.T) {
	successfulTests := []struct {
		src    map[string]string
		result pgtype.Hstore
	}{
		{src: map[string]string{"foo": "bar"}, result: pgtype.Hstore{Map: map[string]pgtype.Text{"foo": pgtype.Text{String: "bar", Status: pgtype.Present}}, Status: pgtype.Present}},
	}

	for i, tt := range successfulTests {
		var dst pgtype.Hstore
		err := dst.Set(tt.src)
		if err != nil {
			t.Errorf("%d: %v", i, err)
		}

		if !reflect.DeepEqual(dst, tt.result) {
			t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.src, tt.result, dst)
		}
	}
}

func TestHstoreAssignTo(t *testing.T) {
	var m map[string]string

	simpleTests := []struct {
		src      pgtype.Hstore
		dst      *map[string]string
		expected map[string]string
	}{
		{src: pgtype.Hstore{Map: map[string]pgtype.Text{"foo": pgtype.Text{String: "bar", Status: pgtype.Present}}, Status: pgtype.Present}, dst: &m, expected: map[string]string{"foo": "bar"}},
		{src: pgtype.Hstore{Status: pgtype.Null}, dst: &m, expected: ((map[string]string)(nil))},
	}

	for i, tt := range simpleTests {
		err := tt.src.AssignTo(tt.dst)
		if err != nil {
			t.Errorf("%d: %v", i, err)
		}

		if !reflect.DeepEqual(*tt.dst, tt.expected) {
			t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, *tt.dst)
		}
	}
}
<commit_msg>Uncomment Hstore tests<commit_after>package pgtype_test

import (
	"reflect"
	"testing"

	"github.com/jackc/pgx/pgtype"
	"github.com/jackc/pgx/pgtype/testutil"
)

func TestHstoreTranscode(t *testing.T) {
	text := func(s string) pgtype.Text {
		return pgtype.Text{String: s, Status: pgtype.Present}
	}

	values := []interface{}{
		&pgtype.Hstore{Map: map[string]pgtype.Text{}, Status: pgtype.Present},
		&pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("bar")}, Status: pgtype.Present},
		&pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("bar"), "baz": text("quz")}, Status: pgtype.Present},
		&pgtype.Hstore{Map: map[string]pgtype.Text{"NULL": text("bar")}, Status: pgtype.Present},
		&pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("NULL")}, Status: pgtype.Present},
		&pgtype.Hstore{Status: pgtype.Null},
	}

	specialStrings := []string{
		`"`,
		`'`,
		`\`,
		`\\`,
		`=>`,
		` `,
		`\ / / \\ => " ' " '`,
	}
	for _, s := range specialStrings {
		// Special key values
		values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{s + "foo": text("bar")}, Status: pgtype.Present})         // at beginning
		values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo" + s + "bar": text("bar")}, Status: pgtype.Present}) // in middle
		values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo" + s: text("bar")}, Status: pgtype.Present})         // at end
		values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{s: text("bar")}, Status: pgtype.Present})                 // is key

		// Special value values
		values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text(s + "bar")}, Status: pgtype.Present})         // at beginning
		values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("foo" + s + "bar")}, Status: pgtype.Present}) // in middle
		values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("foo" + s)}, Status: pgtype.Present})         // at end
		values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text(s)}, Status: pgtype.Present})                 // is key
	}

	testutil.TestSuccessfulTranscodeEqFunc(t, "hstore", values, func(ai, bi interface{}) bool {
		a := ai.(pgtype.Hstore)
		b := bi.(pgtype.Hstore)

		if len(a.Map) != len(b.Map) || a.Status != b.Status {
			return false
		}

		for k := range a.Map {
			if a.Map[k] != b.Map[k] {
				return false
			}
		}

		return true
	})
}

func TestHstoreSet(t *testing.T) {
	successfulTests := []struct {
		src    map[string]string
		result pgtype.Hstore
	}{
		{src: map[string]string{"foo": "bar"}, result: pgtype.Hstore{Map: map[string]pgtype.Text{"foo": pgtype.Text{String: "bar", Status: pgtype.Present}}, Status: pgtype.Present}},
	}

	for i, tt := range successfulTests {
		var dst pgtype.Hstore
		err := dst.Set(tt.src)
		if err != nil {
			t.Errorf("%d: %v", i, err)
		}

		if !reflect.DeepEqual(dst, tt.result) {
			t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.src, tt.result, dst)
		}
	}
}

func TestHstoreAssignTo(t *testing.T) {
	var m map[string]string

	simpleTests := []struct {
		src      pgtype.Hstore
		dst      *map[string]string
		expected map[string]string
	}{
		{src: pgtype.Hstore{Map: map[string]pgtype.Text{"foo": pgtype.Text{String: "bar", Status: pgtype.Present}}, Status: pgtype.Present}, dst: &m, expected: map[string]string{"foo": "bar"}},
		{src: pgtype.Hstore{Status: pgtype.Null}, dst: &m, expected: ((map[string]string)(nil))},
	}

	for i, tt := range simpleTests {
		err := tt.src.AssignTo(tt.dst)
		if err != nil {
			t.Errorf("%d: %v", i, err)
		}

		if !reflect.DeepEqual(*tt.dst, tt.expected) {
			t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, *tt.dst)
		}
	}
}
<|endoftext|>


<commit_before>package bridge

import (
	"bytes"
	"errors"
	"fmt"
	"net"

	"github.com/docker/libnetwork/types"
	"github.com/ishidawataru/sctp"
	"github.com/sirupsen/logrus"
)

func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
	if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
		return nil, nil
	}

	defHostIP := net.IPv4zero // 0.0.0.0
	if reqDefBindIP != nil {
		defHostIP = reqDefBindIP
	}

	var containerIPv6 net.IP
	if ep.addrv6 != nil {
		containerIPv6 = ep.addrv6.IP
	}

	pb, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, containerIPv6, defHostIP, ulPxyEnabled)
	if err != nil {
		return nil, err
	}
	return pb, nil
}

func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIPv4, containerIPv6, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
	bs := make([]types.PortBinding, 0, len(bindings))
	for _, c := range bindings {
		bIPv4 := c.GetCopy()
		bIPv6 := c.GetCopy()
		// Allocate IPv4 Port mappings
		if ok := n.validatePortBindingIPv4(&bIPv4, containerIPv4, defHostIP); ok {
			if err := n.allocatePort(&bIPv4, ulPxyEnabled); err != nil {
				// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
				if cuErr := n.releasePortsInternal(bs); cuErr != nil {
					logrus.Warnf("allocation failure for %v, failed to clear previously allocated ipv4 port bindings: %v", bIPv4, cuErr)
				}
				return nil, err
			}
			bs = append(bs, bIPv4)
		}

		// Allocate IPv6 Port mappings
		// If the container has no IPv6 address, allow proxying host IPv6 traffic to it
		// by setting up the binding with the IPv4 interface if the userland proxy is enabled
		// This change was added to keep backward compatibility
		containerIP := containerIPv6
		if ulPxyEnabled && (containerIPv6 == nil) {
			containerIP = containerIPv4
		}
		if ok := n.validatePortBindingIPv6(&bIPv6, containerIP, defHostIP); ok {
			if err := n.allocatePort(&bIPv6, ulPxyEnabled); err != nil {
				// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
				if cuErr := n.releasePortsInternal(bs); cuErr != nil {
					logrus.Warnf("allocation failure for %v, failed to clear previously allocated ipv6 port bindings: %v", bIPv6, cuErr)
				}
				return nil, err
			}
			bs = append(bs, bIPv6)
		}
	}
	return bs, nil
}

// validatePortBindingIPv4 validates the port binding, populates the missing Host IP field and returns true
// if this is a valid IPv4 binding, else returns false
func (n *bridgeNetwork) validatePortBindingIPv4(bnd *types.PortBinding, containerIPv4, defHostIP net.IP) bool {
	//Return early if there is a valid Host IP, but its not a IPv4 address
	if len(bnd.HostIP) > 0 && bnd.HostIP.To4() == nil {
		return false
	}
	// Adjust the host address in the operational binding
	if len(bnd.HostIP) == 0 {
		// Return early if the default binding address is an IPv6 address
		if defHostIP.To4() == nil {
			return false
		}
		bnd.HostIP = defHostIP
	}
	bnd.IP = containerIPv4
	return true

}

// validatePortBindingIPv6 validates the port binding, populates the missing Host IP field and returns true
// if this is a valid IPv6 binding, else returns false
func (n *bridgeNetwork) validatePortBindingIPv6(bnd *types.PortBinding, containerIP, defHostIP net.IP) bool {
	// Return early if there is no container endpoint
	if containerIP == nil {
		return false
	}
	// Return early if there is a valid Host IP, which is a IPv4 address
	if len(bnd.HostIP) > 0 && bnd.HostIP.To4() != nil {
		return false
	}

	// Setup a binding to  "::" if Host IP is empty and the default binding IP is 0.0.0.0
	if len(bnd.HostIP) == 0 {
		if defHostIP.Equal(net.IPv4zero) {
			bnd.HostIP = net.IPv6zero
			// If the default binding IP is an IPv6 address, use it
		} else if defHostIP.To4() == nil {
			bnd.HostIP = defHostIP
			// Return false if default binding ip is an IPv4 address
		} else {
			return false
		}
	}
	bnd.IP = containerIP
	return true
}

func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, ulPxyEnabled bool) error {
	var (
		host net.Addr
		err  error
	)

	// Adjust HostPortEnd if this is not a range.
	if bnd.HostPortEnd == 0 {
		bnd.HostPortEnd = bnd.HostPort
	}

	// Construct the container side transport address
	container, err := bnd.ContainerAddr()
	if err != nil {
		return err
	}

	portmapper := n.portMapper

	if bnd.IP.To4() == nil {
		portmapper = n.portMapperV6
	}

	// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
	for i := 0; i < maxAllocatePortAttempts; i++ {
		if host, err = portmapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled); err == nil {
			break
		}
		// There is no point in immediately retrying to map an explicitly chosen port.
		if bnd.HostPort != 0 {
			logrus.Warnf("Failed to allocate and map port %d-%d: %s", bnd.HostPort, bnd.HostPortEnd, err)
			break
		}
		logrus.Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1)
	}
	if err != nil {
		return err
	}

	// Save the host port (regardless it was or not specified in the binding)
	switch netAddr := host.(type) {
	case *net.TCPAddr:
		bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
		return nil
	case *net.UDPAddr:
		bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
		return nil
	case *sctp.SCTPAddr:
		bnd.HostPort = uint16(host.(*sctp.SCTPAddr).Port)
		return nil
	default:
		// For completeness
		return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
	}
}

func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error {
	return n.releasePortsInternal(ep.portMapping)
}

func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error {
	var errorBuf bytes.Buffer

	// Attempt to release all port bindings, do not stop on failure
	for _, m := range bindings {
		if err := n.releasePort(m); err != nil {
			errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err))
		}
	}

	if errorBuf.Len() != 0 {
		return errors.New(errorBuf.String())
	}
	return nil
}

func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
	// Construct the host side transport address
	host, err := bnd.HostAddr()
	if err != nil {
		return err
	}

	portmapper := n.portMapper

	if bnd.HostIP.To4() == nil {
		portmapper = n.portMapperV6
	}

	return portmapper.Unmap(host)
}
<commit_msg>Use hostIP to decide on Portmapper version<commit_after>package bridge

import (
	"bytes"
	"errors"
	"fmt"
	"net"

	"github.com/docker/libnetwork/types"
	"github.com/ishidawataru/sctp"
	"github.com/sirupsen/logrus"
)

func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
	if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
		return nil, nil
	}

	defHostIP := net.IPv4zero // 0.0.0.0
	if reqDefBindIP != nil {
		defHostIP = reqDefBindIP
	}

	var containerIPv6 net.IP
	if ep.addrv6 != nil {
		containerIPv6 = ep.addrv6.IP
	}

	pb, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, containerIPv6, defHostIP, ulPxyEnabled)
	if err != nil {
		return nil, err
	}
	return pb, nil
}

func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIPv4, containerIPv6, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
	bs := make([]types.PortBinding, 0, len(bindings))
	for _, c := range bindings {
		bIPv4 := c.GetCopy()
		bIPv6 := c.GetCopy()
		// Allocate IPv4 Port mappings
		if ok := n.validatePortBindingIPv4(&bIPv4, containerIPv4, defHostIP); ok {
			if err := n.allocatePort(&bIPv4, ulPxyEnabled); err != nil {
				// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
				if cuErr := n.releasePortsInternal(bs); cuErr != nil {
					logrus.Warnf("allocation failure for %v, failed to clear previously allocated ipv4 port bindings: %v", bIPv4, cuErr)
				}
				return nil, err
			}
			bs = append(bs, bIPv4)
		}

		// Allocate IPv6 Port mappings
		// If the container has no IPv6 address, allow proxying host IPv6 traffic to it
		// by setting up the binding with the IPv4 interface if the userland proxy is enabled
		// This change was added to keep backward compatibility
		containerIP := containerIPv6
		if ulPxyEnabled && (containerIPv6 == nil) {
			containerIP = containerIPv4
		}
		if ok := n.validatePortBindingIPv6(&bIPv6, containerIP, defHostIP); ok {
			if err := n.allocatePort(&bIPv6, ulPxyEnabled); err != nil {
				// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
				if cuErr := n.releasePortsInternal(bs); cuErr != nil {
					logrus.Warnf("allocation failure for %v, failed to clear previously allocated ipv6 port bindings: %v", bIPv6, cuErr)
				}
				return nil, err
			}
			bs = append(bs, bIPv6)
		}
	}
	return bs, nil
}

// validatePortBindingIPv4 validates the port binding, populates the missing Host IP field and returns true
// if this is a valid IPv4 binding, else returns false
func (n *bridgeNetwork) validatePortBindingIPv4(bnd *types.PortBinding, containerIPv4, defHostIP net.IP) bool {
	//Return early if there is a valid Host IP, but its not a IPv4 address
	if len(bnd.HostIP) > 0 && bnd.HostIP.To4() == nil {
		return false
	}
	// Adjust the host address in the operational binding
	if len(bnd.HostIP) == 0 {
		// Return early if the default binding address is an IPv6 address
		if defHostIP.To4() == nil {
			return false
		}
		bnd.HostIP = defHostIP
	}
	bnd.IP = containerIPv4
	return true

}

// validatePortBindingIPv6 validates the port binding, populates the missing Host IP field and returns true
// if this is a valid IPv6 binding, else returns false
func (n *bridgeNetwork) validatePortBindingIPv6(bnd *types.PortBinding, containerIP, defHostIP net.IP) bool {
	// Return early if there is no container endpoint
	if containerIP == nil {
		return false
	}
	// Return early if there is a valid Host IP, which is a IPv4 address
	if len(bnd.HostIP) > 0 && bnd.HostIP.To4() != nil {
		return false
	}

	// Setup a binding to  "::" if Host IP is empty and the default binding IP is 0.0.0.0
	if len(bnd.HostIP) == 0 {
		if defHostIP.Equal(net.IPv4zero) {
			bnd.HostIP = net.IPv6zero
			// If the default binding IP is an IPv6 address, use it
		} else if defHostIP.To4() == nil {
			bnd.HostIP = defHostIP
			// Return false if default binding ip is an IPv4 address
		} else {
			return false
		}
	}
	bnd.IP = containerIP
	return true
}

func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, ulPxyEnabled bool) error {
	var (
		host net.Addr
		err  error
	)

	// Adjust HostPortEnd if this is not a range.
	if bnd.HostPortEnd == 0 {
		bnd.HostPortEnd = bnd.HostPort
	}

	// Construct the container side transport address
	container, err := bnd.ContainerAddr()
	if err != nil {
		return err
	}

	portmapper := n.portMapper

	if bnd.HostIP.To4() == nil {
		portmapper = n.portMapperV6
	}

	// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
	for i := 0; i < maxAllocatePortAttempts; i++ {
		if host, err = portmapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled); err == nil {
			break
		}
		// There is no point in immediately retrying to map an explicitly chosen port.
		if bnd.HostPort != 0 {
			logrus.Warnf("Failed to allocate and map port %d-%d: %s", bnd.HostPort, bnd.HostPortEnd, err)
			break
		}
		logrus.Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1)
	}
	if err != nil {
		return err
	}

	// Save the host port (regardless it was or not specified in the binding)
	switch netAddr := host.(type) {
	case *net.TCPAddr:
		bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
		return nil
	case *net.UDPAddr:
		bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
		return nil
	case *sctp.SCTPAddr:
		bnd.HostPort = uint16(host.(*sctp.SCTPAddr).Port)
		return nil
	default:
		// For completeness
		return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
	}
}

func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error {
	return n.releasePortsInternal(ep.portMapping)
}

func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error {
	var errorBuf bytes.Buffer

	// Attempt to release all port bindings, do not stop on failure
	for _, m := range bindings {
		if err := n.releasePort(m); err != nil {
			errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err))
		}
	}

	if errorBuf.Len() != 0 {
		return errors.New(errorBuf.String())
	}
	return nil
}

func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
	// Construct the host side transport address
	host, err := bnd.HostAddr()
	if err != nil {
		return err
	}

	portmapper := n.portMapper

	if bnd.HostIP.To4() == nil {
		portmapper = n.portMapperV6
	}

	return portmapper.Unmap(host)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strconv"
)

func BootedTable() *Table {
	tbl := NewTable()

	t := map[string] Function {

		// Type conversion

		"string": func(s *Stack) *Stack {
			s.push(s.popString())
			return s
		},

		// Basic I/O

		"print": func(s *Stack) *Stack {
			fmt.Println(s.popString())
			return s
		},

		// Stack operations

		"pop": func(s *Stack) *Stack {
			s.pop()
			return s
		},
		"size": func(s *Stack) *Stack {
			s.push(s.size())
			return s
		},
		"dup": func(s *Stack) *Stack {
			s.push(s.top())
			return s
		},
		"swap": func(s *Stack) *Stack {
			a := s.pop()
			b := s.pop()
			s.push(b)
			s.push(a)
			return s
		},
		"drop": func(s *Stack) *Stack {
			s.clear()
			return s
		},

		// Arithmetic operations

		"add": func(s *Stack) *Stack {
			add := s.pop().(int) + s.pop().(int)
			s.push(add)
			return s
		},
		"prod": func(s *Stack) *Stack {
			prod := s.pop().(int) * s.pop().(int)
			s.push(prod)
			return s
		},

	}

	tbl.functions = t

	tbl.alias("+", "add")
	tbl.alias("*", "prod")

	return tbl
}

func Eval(code string, stk *Stack, tbl *Table) (s *Stack, t *Table) {
	tokens := Parse(code)
	return Run(tokens, stk, tbl)
}

func Run(tokens *Tokens, stk *Stack, tbl *Table) (s *Stack, t *Table) {

	for _, tok := range *tokens {
		switch tok.key {
		case "str":
			stk.push(tok.val)

		case "int":
			i, _ := strconv.Atoi(tok.val)
			stk.push(i)

		case "stm":
			// add statements to stack

		case "fun":
			if tbl.has(tok.val) {
				f := tbl.get(tok.val)
				stk = f(stk)
			} else {
				// no function error!
			}

		default:
			// problem?

		}
	}

	fmt.Println(stk.String())

	return stk, tbl
}
<commit_msg>Added VType interface plus two implementations<commit_after>package main

import (
	"fmt"
	"strconv"
)

type VType interface {
	String()  string
}

type VString struct {
	value string
}

func (v *VString) String() string {
	return v.value
}

type VInteger struct {
	value int
}

func (v *VInteger) String() string {
	return strconv.Itob(v.value, 10)
}

func BootedTable() *Table {
	tbl := NewTable()

	t := map[string] Function {

		// Type conversion

		"string": func(s *Stack) *Stack {
			s.push(s.popString())
			return s
		},

		// Basic I/O

		"print": func(s *Stack) *Stack {
			fmt.Println(s.popString())
			return s
		},

		// Stack operations

		"pop": func(s *Stack) *Stack {
			s.pop()
			return s
		},
		"size": func(s *Stack) *Stack {
			s.push(s.size())
			return s
		},
		"dup": func(s *Stack) *Stack {
			s.push(s.top())
			return s
		},
		"swap": func(s *Stack) *Stack {
			a := s.pop()
			b := s.pop()
			s.push(b)
			s.push(a)
			return s
		},
		"drop": func(s *Stack) *Stack {
			s.clear()
			return s
		},

		// Arithmetic operations

		"add": func(s *Stack) *Stack {
			add := s.pop().(int) + s.pop().(int)
			s.push(add)
			return s
		},
		"prod": func(s *Stack) *Stack {
			prod := s.pop().(int) * s.pop().(int)
			s.push(prod)
			return s
		},

	}

	tbl.functions = t

	tbl.alias("+", "add")
	tbl.alias("*", "prod")

	return tbl
}

func Eval(code string, stk *Stack, tbl *Table) (s *Stack, t *Table) {
	tokens := Parse(code)
	return Run(tokens, stk, tbl)
}

func Run(tokens *Tokens, stk *Stack, tbl *Table) (s *Stack, t *Table) {

	for _, tok := range *tokens {
		switch tok.key {
		case "str":
			stk.push(tok.val)

		case "int":
			i, _ := strconv.Atoi(tok.val)
			stk.push(i)

		case "stm":
			// add statements to stack

		case "fun":
			if tbl.has(tok.val) {
				f := tbl.get(tok.val)
				stk = f(stk)
			} else {
				// no function error!
			}

		default:
			// problem?

		}
	}

	fmt.Println(stk.String())

	return stk, tbl
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package json

import (
	"bytes"
	"io/ioutil"
	"reflect"
	"testing"

	"github.com/yarpc/yarpc-go/transport"
	"github.com/yarpc/yarpc-go/transport/transporttest"

	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"golang.org/x/net/context"
)

var _typeOfMapInterface = reflect.TypeOf(map[string]interface{}{})

func TestCall(t *testing.T) {
	mockCtrl := gomock.NewController(t)
	defer mockCtrl.Finish()

	caller := "caller"
	service := "service"

	tests := []struct {
		procedure       string
		headers         transport.Headers
		body            interface{}
		encodedRequest  string
		encodedResponse string

		// whether the outbound receives the request
		noCall bool

		// Either want, or wantType and wantErr must be set.
		want     interface{}  // expected response body
		wantType reflect.Type // type of response body
		wantErr  string       // error message
	}{
		{
			procedure:       "foo",
			body:            []string{"foo", "bar"},
			encodedRequest:  `["foo","bar"]`,
			encodedResponse: `{"success": true}`,
			want:            map[string]interface{}{"success": true},
		},
		{
			procedure:       "bar",
			body:            []int{1, 2, 3},
			encodedRequest:  `[1,2,3]`,
			encodedResponse: `invalid JSON`,
			wantType:        _typeOfMapInterface,
			wantErr:         "failed to parse JSON",
			// TODO make error message consistent with other languages
		},
		{
			procedure: "baz",
			body:      func() {}, // funcs cannot be json.Marshal'ed
			noCall:    true,
			wantType:  _typeOfMapInterface,
			wantErr:   "failed to serialize JSON",
			// TODO make error message consistent with other languages
		},
	}

	for _, tt := range tests {
		outbound := transporttest.NewMockOutbound(mockCtrl)
		client := New(transport.Channel{
			Caller:   caller,
			Service:  service,
			Outbound: outbound,
		})

		if !tt.noCall {
			outbound.EXPECT().Call(gomock.Any(),
				transporttest.NewRequestMatcher(t,
					&transport.Request{
						Caller:    caller,
						Service:   service,
						Procedure: tt.procedure,
						Encoding:  Encoding,
						Body:      bytes.NewReader([]byte(tt.encodedRequest)),
					}),
			).Return(
				&transport.Response{Body: ioutil.NopCloser(
					bytes.NewReader([]byte(tt.encodedResponse)),
				)}, nil)
		}

		var wantType reflect.Type
		if tt.want != nil {
			wantType = reflect.TypeOf(tt.want)
		} else {
			require.NotNil(t, tt.wantType, "wantType is required if want is nil")
			wantType = tt.wantType
		}
		resBody := reflect.Zero(wantType).Interface()

		_, err := client.Call(&Request{
			Context:   context.TODO(), // TODO
			Procedure: tt.procedure,
			Headers:   tt.headers,
			// TTL: TODO
		}, tt.body, &resBody)

		if tt.wantErr != "" {
			if assert.Error(t, err) {
				assert.Contains(t, err.Error(), tt.wantErr)
			}
		} else {
			if assert.NoError(t, err) {
				assert.Equal(t, tt.want, resBody)
			}
		}
	}
}
<commit_msg>json/outbound: test request and response headers (#98)<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package json

import (
	"bytes"
	"io/ioutil"
	"reflect"
	"testing"

	"github.com/yarpc/yarpc-go/transport"
	"github.com/yarpc/yarpc-go/transport/transporttest"

	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"golang.org/x/net/context"
)

var _typeOfMapInterface = reflect.TypeOf(map[string]interface{}{})

func TestCall(t *testing.T) {
	mockCtrl := gomock.NewController(t)
	defer mockCtrl.Finish()

	caller := "caller"
	service := "service"

	tests := []struct {
		procedure       string
		headers         transport.Headers
		body            interface{}
		encodedRequest  string
		encodedResponse string

		// whether the outbound receives the request
		noCall bool

		// Either want, or wantType and wantErr must be set.
		want        interface{} // expected response body
		wantHeaders transport.Headers
		wantType    reflect.Type // type of response body
		wantErr     string       // error message
	}{
		{
			procedure:       "foo",
			body:            []string{"foo", "bar"},
			encodedRequest:  `["foo","bar"]`,
			encodedResponse: `{"success": true}`,
			want:            map[string]interface{}{"success": true},
		},
		{
			procedure:       "bar",
			body:            []int{1, 2, 3},
			encodedRequest:  `[1,2,3]`,
			encodedResponse: `invalid JSON`,
			wantType:        _typeOfMapInterface,
			wantErr:         "failed to parse JSON",
			// TODO make error message consistent with other languages
		},
		{
			procedure: "baz",
			body:      func() {}, // funcs cannot be json.Marshal'ed
			noCall:    true,
			wantType:  _typeOfMapInterface,
			wantErr:   "failed to serialize JSON",
			// TODO make error message consistent with other languages
		},
		{
			procedure:       "requestHeaders",
			headers:         transport.Headers{"user-id": "42"},
			body:            map[string]interface{}{},
			encodedRequest:  "{}",
			encodedResponse: "{}",
			want:            map[string]interface{}{},
			wantHeaders:     transport.Headers{"success": "true"},
		},
	}

	for _, tt := range tests {
		outbound := transporttest.NewMockOutbound(mockCtrl)
		client := New(transport.Channel{
			Caller:   caller,
			Service:  service,
			Outbound: outbound,
		})

		if !tt.noCall {
			outbound.EXPECT().Call(gomock.Any(),
				transporttest.NewRequestMatcher(t,
					&transport.Request{
						Caller:    caller,
						Service:   service,
						Procedure: tt.procedure,
						Encoding:  Encoding,
						Headers:   tt.headers,
						Body:      bytes.NewReader([]byte(tt.encodedRequest)),
					}),
			).Return(
				&transport.Response{
					Body: ioutil.NopCloser(
						bytes.NewReader([]byte(tt.encodedResponse))),
					Headers: tt.wantHeaders,
				}, nil)
		}

		var wantType reflect.Type
		if tt.want != nil {
			wantType = reflect.TypeOf(tt.want)
		} else {
			require.NotNil(t, tt.wantType, "wantType is required if want is nil")
			wantType = tt.wantType
		}
		resBody := reflect.Zero(wantType).Interface()

		res, err := client.Call(&Request{
			Context:   context.TODO(), // TODO
			Procedure: tt.procedure,
			Headers:   tt.headers,
			// TTL: TODO
		}, tt.body, &resBody)

		if tt.wantErr != "" {
			if assert.Error(t, err) {
				assert.Contains(t, err.Error(), tt.wantErr)
			}
		} else {
			if assert.NoError(t, err) {
				assert.Equal(t, tt.wantHeaders, res.Headers)
				assert.Equal(t, tt.want, resBody)
			}
		}
	}
}
<|endoftext|>


<commit_before>package engine

import (
	"bytes"
	"encoding/base64"
	"encoding/gob"
	"fmt"

	"github.com/go-redis/redis"
	"github.com/khezen/bulklog/collection"
)

func flushBuffer2RedisPipe(tx redis.Pipeliner, bufferKey, pipeKey string) (err error) {
	var length int64
	length, err = tx.LLen(bufferKey).Result()
	if err != nil {
		return fmt.Errorf("LLEN(bufferKey).%s", err.Error())
	}
	if length > 0 {
		_, err = tx.Rename(bufferKey, fmt.Sprintf("%s.buffer", pipeKey)).Result()
		if err != nil {
			return fmt.Errorf("RENAME(bufferKey pipeKey.buffer).%s", err.Error())
		}
	}

	return nil
}

func getRedisPipeDocuments(red *redis.Client, pipeKey string) (documents []collection.Document, err error) {
	bufferKey := fmt.Sprintf("%s.buffer", pipeKey)
	documentsLen, err := red.LLen(bufferKey).Result()
	if err != nil {
		return nil, fmt.Errorf("(LLEN pipeKey.buffer).%s", err.Error())
	}
	docStrings, err := red.LRange(bufferKey, 0, documentsLen).Result()
	if err != nil {
		return nil, fmt.Errorf("(LRANGE pipeKey.buffer 0 documentsLen).%s", err.Error())
	}
	documents = make([]collection.Document, 0, documentsLen)
	var buf *bytes.Buffer
	for _, docBase64 := range docStrings {
		docBytes, err := base64.StdEncoding.DecodeString(docBase64)
		if err != nil {
			return nil, fmt.Errorf("base64.std.decode.%s", err.Error())
		}
		buf = bytes.NewBuffer(docBytes)
		var doc collection.Document
		err = gob.NewDecoder(buf).Decode(&doc)
		if err != nil {
			return nil, fmt.Errorf("(gob.decode.%s", err.Error())
		}
		documents = append(documents, doc)
	}
	return documents, nil
}

func deleteRedisPipeDocuments(tx redis.Pipeliner, pipeKey string) (err error) {
	_, err = tx.Del(fmt.Sprintf("%s.buffer", pipeKey)).Result()
	if err != nil {
		return fmt.Errorf("(DEL pipeKey.buffer).%s", err.Error())
	}
	return nil
}
<commit_msg>wrap redis error<commit_after>package engine

import (
	"bytes"
	"encoding/base64"
	"encoding/gob"
	"fmt"

	"github.com/go-redis/redis"
	"github.com/khezen/bulklog/collection"
)

func flushBuffer2RedisPipe(tx redis.Pipeliner, bufferKey, pipeKey string) (err error) {
	_, err = tx.Rename(bufferKey, fmt.Sprintf("%s.buffer", pipeKey)).Result()
	if err != nil {
		return fmt.Errorf("RENAME(bufferKey pipeKey.buffer).%s", err.Error())
	}
	return nil
}

func getRedisPipeDocuments(red *redis.Client, pipeKey string) (documents []collection.Document, err error) {
	bufferKey := fmt.Sprintf("%s.buffer", pipeKey)
	documentsLen, err := red.LLen(bufferKey).Result()
	if err != nil {
		return nil, fmt.Errorf("(LLEN pipeKey.buffer).%s", err.Error())
	}
	docStrings, err := red.LRange(bufferKey, 0, documentsLen).Result()
	if err != nil {
		return nil, fmt.Errorf("(LRANGE pipeKey.buffer 0 documentsLen).%s", err.Error())
	}
	documents = make([]collection.Document, 0, documentsLen)
	var buf *bytes.Buffer
	for _, docBase64 := range docStrings {
		docBytes, err := base64.StdEncoding.DecodeString(docBase64)
		if err != nil {
			return nil, fmt.Errorf("base64.std.decode.%s", err.Error())
		}
		buf = bytes.NewBuffer(docBytes)
		var doc collection.Document
		err = gob.NewDecoder(buf).Decode(&doc)
		if err != nil {
			return nil, fmt.Errorf("(gob.decode.%s", err.Error())
		}
		documents = append(documents, doc)
	}
	return documents, nil
}

func deleteRedisPipeDocuments(tx redis.Pipeliner, pipeKey string) (err error) {
	_, err = tx.Del(fmt.Sprintf("%s.buffer", pipeKey)).Result()
	if err != nil {
		return fmt.Errorf("(DEL pipeKey.buffer).%s", err.Error())
	}
	return nil
}
<|endoftext|>


<commit_before>package libcontainerd

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"sync"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	containerd "github.com/docker/containerd/api/grpc/types"
	"github.com/docker/docker/pkg/locker"
	sysinfo "github.com/docker/docker/pkg/system"
	"github.com/docker/docker/utils"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
)

const (
	maxConnectionRetryCount   = 3
	connectionRetryDelay      = 3 * time.Second
	containerdShutdownTimeout = 15 * time.Second
	containerdBinary          = "docker-containerd"
	containerdPidFilename     = "docker-containerd.pid"
	containerdSockFilename    = "docker-containerd.sock"
	eventTimestampFilename    = "event.ts"
)

type remote struct {
	sync.RWMutex
	apiClient   containerd.APIClient
	daemonPid   int
	stateDir    string
	rpcAddr     string
	startDaemon bool
	debugLog    bool
	rpcConn     *grpc.ClientConn
	clients     []*client
	eventTsPath string
	pastEvents  map[string]*containerd.Event
	runtimeArgs []string
}

// New creates a fresh instance of libcontainerd remote.
func New(stateDir string, options ...RemoteOption) (_ Remote, err error) {
	defer func() {
		if err != nil {
			err = fmt.Errorf("Failed to connect to containerd. Please make sure containerd is installed in your PATH or you have specificed the correct address. Got error: %v", err)
		}
	}()
	r := &remote{
		stateDir:    stateDir,
		daemonPid:   -1,
		eventTsPath: filepath.Join(stateDir, eventTimestampFilename),
		pastEvents:  make(map[string]*containerd.Event),
	}
	for _, option := range options {
		if err := option.Apply(r); err != nil {
			return nil, err
		}
	}

	if err := sysinfo.MkdirAll(stateDir, 0700); err != nil {
		return nil, err
	}

	if r.rpcAddr == "" {
		r.rpcAddr = filepath.Join(stateDir, containerdSockFilename)
	}

	if r.startDaemon {
		if err := r.runContainerdDaemon(); err != nil {
			return nil, err
		}
	}

	// don't output the grpc reconnect logging
	grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags))
	dialOpts := append([]grpc.DialOption{grpc.WithInsecure()},
		grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
			return net.DialTimeout("unix", addr, timeout)
		}),
	)
	conn, err := grpc.Dial(r.rpcAddr, dialOpts...)
	if err != nil {
		return nil, fmt.Errorf("error connecting to containerd: %v", err)
	}

	r.rpcConn = conn
	r.apiClient = containerd.NewAPIClient(conn)

	go r.handleConnectionChange()

	if err := r.startEventsMonitor(); err != nil {
		return nil, err
	}

	return r, nil
}

func (r *remote) handleConnectionChange() {
	var transientFailureCount = 0
	state := grpc.Idle
	for {
		s, err := r.rpcConn.WaitForStateChange(context.Background(), state)
		if err != nil {
			break
		}
		state = s
		logrus.Debugf("containerd connection state change: %v", s)

		if r.daemonPid != -1 {
			switch state {
			case grpc.TransientFailure:
				// Reset state to be notified of next failure
				transientFailureCount++
				if transientFailureCount >= maxConnectionRetryCount {
					transientFailureCount = 0
					if utils.IsProcessAlive(r.daemonPid) {
						utils.KillProcess(r.daemonPid)
					}
					if err := r.runContainerdDaemon(); err != nil { //FIXME: Handle error
						logrus.Errorf("error restarting containerd: %v", err)
					}
				} else {
					state = grpc.Idle
					time.Sleep(connectionRetryDelay)
				}
			case grpc.Shutdown:
				// Well, we asked for it to stop, just return
				return
			}
		}
	}
}

func (r *remote) Cleanup() {
	if r.daemonPid == -1 {
		return
	}
	r.rpcConn.Close()
	// Ask the daemon to quit
	syscall.Kill(r.daemonPid, syscall.SIGTERM)

	// Wait up to 15secs for it to stop
	for i := time.Duration(0); i < containerdShutdownTimeout; i += time.Second {
		if !utils.IsProcessAlive(r.daemonPid) {
			break
		}
		time.Sleep(time.Second)
	}

	if utils.IsProcessAlive(r.daemonPid) {
		logrus.Warnf("libcontainerd: containerd (%d) didn't stop within 15 secs, killing it\n", r.daemonPid)
		syscall.Kill(r.daemonPid, syscall.SIGKILL)
	}

	// cleanup some files
	os.Remove(filepath.Join(r.stateDir, containerdPidFilename))
	os.Remove(filepath.Join(r.stateDir, containerdSockFilename))
}

func (r *remote) Client(b Backend) (Client, error) {
	c := &client{
		clientCommon: clientCommon{
			backend:    b,
			containers: make(map[string]*container),
			locker:     locker.New(),
		},
		remote:        r,
		exitNotifiers: make(map[string]*exitNotifier),
	}

	r.Lock()
	r.clients = append(r.clients, c)
	r.Unlock()
	return c, nil
}

func (r *remote) updateEventTimestamp(t time.Time) {
	f, err := os.OpenFile(r.eventTsPath, syscall.O_CREAT|syscall.O_WRONLY|syscall.O_TRUNC, 0600)
	defer f.Close()
	if err != nil {
		logrus.Warnf("libcontainerd: failed to open event timestamp file: %v", err)
		return
	}

	b, err := t.MarshalText()
	if err != nil {
		logrus.Warnf("libcontainerd: failed to encode timestamp: %v", err)
		return
	}

	n, err := f.Write(b)
	if err != nil || n != len(b) {
		logrus.Warnf("libcontainerd: failed to update event timestamp file: %v", err)
		f.Truncate(0)
		return
	}

}

func (r *remote) getLastEventTimestamp() int64 {
	t := time.Now()

	fi, err := os.Stat(r.eventTsPath)
	if os.IsNotExist(err) || fi.Size() == 0 {
		return t.Unix()
	}

	f, err := os.Open(r.eventTsPath)
	defer f.Close()
	if err != nil {
		logrus.Warn("libcontainerd: Unable to access last event ts: %v", err)
		return t.Unix()
	}

	b := make([]byte, fi.Size())
	n, err := f.Read(b)
	if err != nil || n != len(b) {
		logrus.Warn("libcontainerd: Unable to read last event ts: %v", err)
		return t.Unix()
	}

	t.UnmarshalText(b)

	return t.Unix()
}

func (r *remote) startEventsMonitor() error {
	// First, get past events
	er := &containerd.EventsRequest{
		Timestamp: uint64(r.getLastEventTimestamp()),
	}
	events, err := r.apiClient.Events(context.Background(), er)
	if err != nil {
		return err
	}
	go r.handleEventStream(events)
	return nil
}

func (r *remote) handleEventStream(events containerd.API_EventsClient) {
	live := false
	for {
		e, err := events.Recv()
		if err != nil {
			logrus.Errorf("failed to receive event from containerd: %v", err)
			go r.startEventsMonitor()
			return
		}

		if live == false {
			logrus.Debugf("received past containerd event: %#v", e)

			// Pause/Resume events should never happens after exit one
			switch e.Type {
			case StateExit:
				r.pastEvents[e.Id] = e
			case StatePause:
				r.pastEvents[e.Id] = e
			case StateResume:
				r.pastEvents[e.Id] = e
			case stateLive:
				live = true
				r.updateEventTimestamp(time.Unix(int64(e.Timestamp), 0))
			}
		} else {
			logrus.Debugf("received containerd event: %#v", e)

			var container *container
			var c *client
			r.RLock()
			for _, c = range r.clients {
				container, err = c.getContainer(e.Id)
				if err == nil {
					break
				}
			}
			r.RUnlock()
			if container == nil {
				logrus.Errorf("no state for container: %q", err)
				continue
			}

			if err := container.handleEvent(e); err != nil {
				logrus.Errorf("error processing state change for %s: %v", e.Id, err)
			}

			r.updateEventTimestamp(time.Unix(int64(e.Timestamp), 0))
		}
	}
}

func (r *remote) runContainerdDaemon() error {
	pidFilename := filepath.Join(r.stateDir, containerdPidFilename)
	f, err := os.OpenFile(pidFilename, os.O_RDWR|os.O_CREATE, 0600)
	defer f.Close()
	if err != nil {
		return err
	}

	// File exist, check if the daemon is alive
	b := make([]byte, 8)
	n, err := f.Read(b)
	if err != nil && err != io.EOF {
		return err
	}

	if n > 0 {
		pid, err := strconv.ParseUint(string(b[:n]), 10, 64)
		if err != nil {
			return err
		}
		if utils.IsProcessAlive(int(pid)) {
			logrus.Infof("previous instance of containerd still alive (%d)", pid)
			r.daemonPid = int(pid)
			return nil
		}
	}

	// rewind the file
	_, err = f.Seek(0, os.SEEK_SET)
	if err != nil {
		return err
	}

	// Truncate it
	err = f.Truncate(0)
	if err != nil {
		return err
	}

	// Start a new instance
	args := []string{"-l", r.rpcAddr, "--runtime", "docker-runc"}
	if r.debugLog {
		args = append(args, "--debug", "--metrics-interval=0")
	}
	if len(r.runtimeArgs) > 0 {
		for _, v := range r.runtimeArgs {
			args = append(args, "--runtime-args")
			args = append(args, v)
		}
		logrus.Debugf("runContainerdDaemon: runtimeArgs: %s", args)
	}
	cmd := exec.Command(containerdBinary, args...)
	// redirect containerd logs to docker logs
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
	if err := cmd.Start(); err != nil {
		return err
	}
	logrus.Infof("New containerd process, pid: %d\n", cmd.Process.Pid)

	if _, err := f.WriteString(fmt.Sprintf("%d", cmd.Process.Pid)); err != nil {
		utils.KillProcess(cmd.Process.Pid)
		return err
	}

	go cmd.Wait() // Reap our child when needed
	r.daemonPid = cmd.Process.Pid
	return nil
}

// WithRemoteAddr sets the external containerd socket to connect to.
func WithRemoteAddr(addr string) RemoteOption {
	return rpcAddr(addr)
}

type rpcAddr string

func (a rpcAddr) Apply(r Remote) error {
	if remote, ok := r.(*remote); ok {
		remote.rpcAddr = string(a)
		return nil
	}
	return fmt.Errorf("WithRemoteAddr option not supported for this remote")
}

// WithRuntimeArgs sets the list of runtime args passed to containerd
func WithRuntimeArgs(args []string) RemoteOption {
	return runtimeArgs(args)
}

type runtimeArgs []string

func (rt runtimeArgs) Apply(r Remote) error {
	if remote, ok := r.(*remote); ok {
		remote.runtimeArgs = rt
		return nil
	}
	return fmt.Errorf("WithRuntimeArgs option not supported for this remote")
}

// WithStartDaemon defines if libcontainerd should also run containerd daemon.
func WithStartDaemon(start bool) RemoteOption {
	return startDaemon(start)
}

type startDaemon bool

func (s startDaemon) Apply(r Remote) error {
	if remote, ok := r.(*remote); ok {
		remote.startDaemon = bool(s)
		return nil
	}
	return fmt.Errorf("WithStartDaemon option not supported for this remote")
}

// WithDebugLog defines if containerd debug logs will be enabled for daemon.
func WithDebugLog(debug bool) RemoteOption {
	return debugLog(debug)
}

type debugLog bool

func (d debugLog) Apply(r Remote) error {
	if remote, ok := r.(*remote); ok {
		remote.debugLog = bool(d)
		return nil
	}
	return fmt.Errorf("WithDebugLog option not supported for this remote")
}
<commit_msg>Clear nofity socket from containerd env<commit_after>package libcontainerd

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	containerd "github.com/docker/containerd/api/grpc/types"
	"github.com/docker/docker/pkg/locker"
	sysinfo "github.com/docker/docker/pkg/system"
	"github.com/docker/docker/utils"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
)

const (
	maxConnectionRetryCount   = 3
	connectionRetryDelay      = 3 * time.Second
	containerdShutdownTimeout = 15 * time.Second
	containerdBinary          = "docker-containerd"
	containerdPidFilename     = "docker-containerd.pid"
	containerdSockFilename    = "docker-containerd.sock"
	eventTimestampFilename    = "event.ts"
)

type remote struct {
	sync.RWMutex
	apiClient   containerd.APIClient
	daemonPid   int
	stateDir    string
	rpcAddr     string
	startDaemon bool
	debugLog    bool
	rpcConn     *grpc.ClientConn
	clients     []*client
	eventTsPath string
	pastEvents  map[string]*containerd.Event
	runtimeArgs []string
}

// New creates a fresh instance of libcontainerd remote.
func New(stateDir string, options ...RemoteOption) (_ Remote, err error) {
	defer func() {
		if err != nil {
			err = fmt.Errorf("Failed to connect to containerd. Please make sure containerd is installed in your PATH or you have specificed the correct address. Got error: %v", err)
		}
	}()
	r := &remote{
		stateDir:    stateDir,
		daemonPid:   -1,
		eventTsPath: filepath.Join(stateDir, eventTimestampFilename),
		pastEvents:  make(map[string]*containerd.Event),
	}
	for _, option := range options {
		if err := option.Apply(r); err != nil {
			return nil, err
		}
	}

	if err := sysinfo.MkdirAll(stateDir, 0700); err != nil {
		return nil, err
	}

	if r.rpcAddr == "" {
		r.rpcAddr = filepath.Join(stateDir, containerdSockFilename)
	}

	if r.startDaemon {
		if err := r.runContainerdDaemon(); err != nil {
			return nil, err
		}
	}

	// don't output the grpc reconnect logging
	grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags))
	dialOpts := append([]grpc.DialOption{grpc.WithInsecure()},
		grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
			return net.DialTimeout("unix", addr, timeout)
		}),
	)
	conn, err := grpc.Dial(r.rpcAddr, dialOpts...)
	if err != nil {
		return nil, fmt.Errorf("error connecting to containerd: %v", err)
	}

	r.rpcConn = conn
	r.apiClient = containerd.NewAPIClient(conn)

	go r.handleConnectionChange()

	if err := r.startEventsMonitor(); err != nil {
		return nil, err
	}

	return r, nil
}

func (r *remote) handleConnectionChange() {
	var transientFailureCount = 0
	state := grpc.Idle
	for {
		s, err := r.rpcConn.WaitForStateChange(context.Background(), state)
		if err != nil {
			break
		}
		state = s
		logrus.Debugf("containerd connection state change: %v", s)

		if r.daemonPid != -1 {
			switch state {
			case grpc.TransientFailure:
				// Reset state to be notified of next failure
				transientFailureCount++
				if transientFailureCount >= maxConnectionRetryCount {
					transientFailureCount = 0
					if utils.IsProcessAlive(r.daemonPid) {
						utils.KillProcess(r.daemonPid)
					}
					if err := r.runContainerdDaemon(); err != nil { //FIXME: Handle error
						logrus.Errorf("error restarting containerd: %v", err)
					}
				} else {
					state = grpc.Idle
					time.Sleep(connectionRetryDelay)
				}
			case grpc.Shutdown:
				// Well, we asked for it to stop, just return
				return
			}
		}
	}
}

func (r *remote) Cleanup() {
	if r.daemonPid == -1 {
		return
	}
	r.rpcConn.Close()
	// Ask the daemon to quit
	syscall.Kill(r.daemonPid, syscall.SIGTERM)

	// Wait up to 15secs for it to stop
	for i := time.Duration(0); i < containerdShutdownTimeout; i += time.Second {
		if !utils.IsProcessAlive(r.daemonPid) {
			break
		}
		time.Sleep(time.Second)
	}

	if utils.IsProcessAlive(r.daemonPid) {
		logrus.Warnf("libcontainerd: containerd (%d) didn't stop within 15 secs, killing it\n", r.daemonPid)
		syscall.Kill(r.daemonPid, syscall.SIGKILL)
	}

	// cleanup some files
	os.Remove(filepath.Join(r.stateDir, containerdPidFilename))
	os.Remove(filepath.Join(r.stateDir, containerdSockFilename))
}

func (r *remote) Client(b Backend) (Client, error) {
	c := &client{
		clientCommon: clientCommon{
			backend:    b,
			containers: make(map[string]*container),
			locker:     locker.New(),
		},
		remote:        r,
		exitNotifiers: make(map[string]*exitNotifier),
	}

	r.Lock()
	r.clients = append(r.clients, c)
	r.Unlock()
	return c, nil
}

func (r *remote) updateEventTimestamp(t time.Time) {
	f, err := os.OpenFile(r.eventTsPath, syscall.O_CREAT|syscall.O_WRONLY|syscall.O_TRUNC, 0600)
	defer f.Close()
	if err != nil {
		logrus.Warnf("libcontainerd: failed to open event timestamp file: %v", err)
		return
	}

	b, err := t.MarshalText()
	if err != nil {
		logrus.Warnf("libcontainerd: failed to encode timestamp: %v", err)
		return
	}

	n, err := f.Write(b)
	if err != nil || n != len(b) {
		logrus.Warnf("libcontainerd: failed to update event timestamp file: %v", err)
		f.Truncate(0)
		return
	}

}

func (r *remote) getLastEventTimestamp() int64 {
	t := time.Now()

	fi, err := os.Stat(r.eventTsPath)
	if os.IsNotExist(err) || fi.Size() == 0 {
		return t.Unix()
	}

	f, err := os.Open(r.eventTsPath)
	defer f.Close()
	if err != nil {
		logrus.Warn("libcontainerd: Unable to access last event ts: %v", err)
		return t.Unix()
	}

	b := make([]byte, fi.Size())
	n, err := f.Read(b)
	if err != nil || n != len(b) {
		logrus.Warn("libcontainerd: Unable to read last event ts: %v", err)
		return t.Unix()
	}

	t.UnmarshalText(b)

	return t.Unix()
}

func (r *remote) startEventsMonitor() error {
	// First, get past events
	er := &containerd.EventsRequest{
		Timestamp: uint64(r.getLastEventTimestamp()),
	}
	events, err := r.apiClient.Events(context.Background(), er)
	if err != nil {
		return err
	}
	go r.handleEventStream(events)
	return nil
}

func (r *remote) handleEventStream(events containerd.API_EventsClient) {
	live := false
	for {
		e, err := events.Recv()
		if err != nil {
			logrus.Errorf("failed to receive event from containerd: %v", err)
			go r.startEventsMonitor()
			return
		}

		if live == false {
			logrus.Debugf("received past containerd event: %#v", e)

			// Pause/Resume events should never happens after exit one
			switch e.Type {
			case StateExit:
				r.pastEvents[e.Id] = e
			case StatePause:
				r.pastEvents[e.Id] = e
			case StateResume:
				r.pastEvents[e.Id] = e
			case stateLive:
				live = true
				r.updateEventTimestamp(time.Unix(int64(e.Timestamp), 0))
			}
		} else {
			logrus.Debugf("received containerd event: %#v", e)

			var container *container
			var c *client
			r.RLock()
			for _, c = range r.clients {
				container, err = c.getContainer(e.Id)
				if err == nil {
					break
				}
			}
			r.RUnlock()
			if container == nil {
				logrus.Errorf("no state for container: %q", err)
				continue
			}

			if err := container.handleEvent(e); err != nil {
				logrus.Errorf("error processing state change for %s: %v", e.Id, err)
			}

			r.updateEventTimestamp(time.Unix(int64(e.Timestamp), 0))
		}
	}
}

func (r *remote) runContainerdDaemon() error {
	pidFilename := filepath.Join(r.stateDir, containerdPidFilename)
	f, err := os.OpenFile(pidFilename, os.O_RDWR|os.O_CREATE, 0600)
	defer f.Close()
	if err != nil {
		return err
	}

	// File exist, check if the daemon is alive
	b := make([]byte, 8)
	n, err := f.Read(b)
	if err != nil && err != io.EOF {
		return err
	}

	if n > 0 {
		pid, err := strconv.ParseUint(string(b[:n]), 10, 64)
		if err != nil {
			return err
		}
		if utils.IsProcessAlive(int(pid)) {
			logrus.Infof("previous instance of containerd still alive (%d)", pid)
			r.daemonPid = int(pid)
			return nil
		}
	}

	// rewind the file
	_, err = f.Seek(0, os.SEEK_SET)
	if err != nil {
		return err
	}

	// Truncate it
	err = f.Truncate(0)
	if err != nil {
		return err
	}

	// Start a new instance
	args := []string{"-l", r.rpcAddr, "--runtime", "docker-runc"}
	if r.debugLog {
		args = append(args, "--debug", "--metrics-interval=0")
	}
	if len(r.runtimeArgs) > 0 {
		for _, v := range r.runtimeArgs {
			args = append(args, "--runtime-args")
			args = append(args, v)
		}
		logrus.Debugf("runContainerdDaemon: runtimeArgs: %s", args)
	}

	cmd := exec.Command(containerdBinary, args...)
	// redirect containerd logs to docker logs
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
	cmd.Env = nil
	// clear the NOTIFY_SOCKET from the env when starting containerd
	for _, e := range os.Environ() {
		if !strings.HasPrefix(e, "NOTIFY_SOCKET") {
			cmd.Env = append(cmd.Env, e)
		}
	}
	if err := cmd.Start(); err != nil {
		return err
	}
	logrus.Infof("New containerd process, pid: %d\n", cmd.Process.Pid)

	if _, err := f.WriteString(fmt.Sprintf("%d", cmd.Process.Pid)); err != nil {
		utils.KillProcess(cmd.Process.Pid)
		return err
	}

	go cmd.Wait() // Reap our child when needed
	r.daemonPid = cmd.Process.Pid
	return nil
}

// WithRemoteAddr sets the external containerd socket to connect to.
func WithRemoteAddr(addr string) RemoteOption {
	return rpcAddr(addr)
}

type rpcAddr string

func (a rpcAddr) Apply(r Remote) error {
	if remote, ok := r.(*remote); ok {
		remote.rpcAddr = string(a)
		return nil
	}
	return fmt.Errorf("WithRemoteAddr option not supported for this remote")
}

// WithRuntimeArgs sets the list of runtime args passed to containerd
func WithRuntimeArgs(args []string) RemoteOption {
	return runtimeArgs(args)
}

type runtimeArgs []string

func (rt runtimeArgs) Apply(r Remote) error {
	if remote, ok := r.(*remote); ok {
		remote.runtimeArgs = rt
		return nil
	}
	return fmt.Errorf("WithRuntimeArgs option not supported for this remote")
}

// WithStartDaemon defines if libcontainerd should also run containerd daemon.
func WithStartDaemon(start bool) RemoteOption {
	return startDaemon(start)
}

type startDaemon bool

func (s startDaemon) Apply(r Remote) error {
	if remote, ok := r.(*remote); ok {
		remote.startDaemon = bool(s)
		return nil
	}
	return fmt.Errorf("WithStartDaemon option not supported for this remote")
}

// WithDebugLog defines if containerd debug logs will be enabled for daemon.
func WithDebugLog(debug bool) RemoteOption {
	return debugLog(debug)
}

type debugLog bool

func (d debugLog) Apply(r Remote) error {
	if remote, ok := r.(*remote); ok {
		remote.debugLog = bool(d)
		return nil
	}
	return fmt.Errorf("WithDebugLog option not supported for this remote")
}
<|endoftext|>


<commit_before>package render

import (
	"image"
	"image/color"
	"image/draw"
)

type Sprite struct {
	LayeredPoint
	r *image.RGBA
}

func NewEmptySprite(x, y float64, w, h int) * Sprite{
	r := image.NewRGBA(image.Rect(0, 0,w, h))
	return NewSprite(x, y, r)
}

func NewSprite(x, y float64, r *image.RGBA) *Sprite {
	return &Sprite{
		LayeredPoint: LayeredPoint{
			Point: Point{
				X: x,
				Y: y,
			},
		},
		r: r,
	}
}

func (s *Sprite) GetRGBA() *image.RGBA {
	return s.r
}

func (s *Sprite) SetRGBA(r *image.RGBA) {
	s.r = r
}

func (s *Sprite) DrawOffset(buff draw.Image, xOff, yOff float64) {
	ShinyDraw(buff, s.r, int(s.X+xOff), int(s.Y+yOff))
}

func (s *Sprite) Draw(buff draw.Image) {
	ShinyDraw(buff, s.r, int(s.X), int(s.Y))
}

func (s *Sprite) Copy() Modifiable {
	newS := new(Sprite)
	*newS = *s
	return newS
}

func (s *Sprite) IsNil() bool {
	return s.r == nil
}

func (s *Sprite) ApplyColor(c color.Color) Modifiable {
	s.r = ApplyColor(s.r, c)
	return s
}

func (s *Sprite) FillMask(img image.RGBA) Modifiable {
	s.r = FillMask(s.r, img)
	return s
}

func (s *Sprite) ApplyMask(img image.RGBA) Modifiable {
	s.r = ApplyMask(s.r, img)
	return s
}

func (s *Sprite) Rotate(degrees int) Modifiable {
	s.r = Rotate(s.r, degrees)
	return s
}
func (s *Sprite) Scale(xRatio float64, yRatio float64) Modifiable {
	s.r = Scale(s.r, xRatio, yRatio)
	return s
}
func (s *Sprite) FlipX() Modifiable {
	s.r = FlipX(s.r)
	return s
}
func (s *Sprite) FlipY() Modifiable {
	s.r = FlipY(s.r)
	return s
}
func (s *Sprite) Fade(alpha int) Modifiable {
	s.r = Fade(s.r, alpha)
	return s
}
func  OverlaySprites(sps []Sprite ) *Sprite{
	tmpSprite := sps[len(sps)-1].Copy().(*Sprite)
	for i:= len(sps)-1; i>0; i-- {
		tmpSprite.r = FillMask(tmpSprite.r, *sps[i-1].r)
	}
	return tmpSprite
}

func ParseSubSprite(s string, x, y, w, h, pad int) *Sprite {
	sh, _ := LoadSheet(dir, s, w, h, pad)
	return sh.SubSprite(x, y)
}
<commit_msg>go fmted<commit_after>package render

import (
	"image"
	"image/color"
	"image/draw"
)

type Sprite struct {
	LayeredPoint
	r *image.RGBA
}

func NewEmptySprite(x, y float64, w, h int) *Sprite {
	r := image.NewRGBA(image.Rect(0, 0, w, h))
	return NewSprite(x, y, r)
}

func NewSprite(x, y float64, r *image.RGBA) *Sprite {
	return &Sprite{
		LayeredPoint: LayeredPoint{
			Point: Point{
				X: x,
				Y: y,
			},
		},
		r: r,
	}
}

func (s *Sprite) GetRGBA() *image.RGBA {
	return s.r
}

func (s *Sprite) SetRGBA(r *image.RGBA) {
	s.r = r
}

func (s *Sprite) DrawOffset(buff draw.Image, xOff, yOff float64) {
	ShinyDraw(buff, s.r, int(s.X+xOff), int(s.Y+yOff))
}

func (s *Sprite) Draw(buff draw.Image) {
	ShinyDraw(buff, s.r, int(s.X), int(s.Y))
}

func (s *Sprite) Copy() Modifiable {
	newS := new(Sprite)
	*newS = *s
	return newS
}

func (s *Sprite) IsNil() bool {
	return s.r == nil
}

func (s *Sprite) ApplyColor(c color.Color) Modifiable {
	s.r = ApplyColor(s.r, c)
	return s
}

func (s *Sprite) FillMask(img image.RGBA) Modifiable {
	s.r = FillMask(s.r, img)
	return s
}

func (s *Sprite) ApplyMask(img image.RGBA) Modifiable {
	s.r = ApplyMask(s.r, img)
	return s
}

func (s *Sprite) Rotate(degrees int) Modifiable {
	s.r = Rotate(s.r, degrees)
	return s
}
func (s *Sprite) Scale(xRatio float64, yRatio float64) Modifiable {
	s.r = Scale(s.r, xRatio, yRatio)
	return s
}
func (s *Sprite) FlipX() Modifiable {
	s.r = FlipX(s.r)
	return s
}
func (s *Sprite) FlipY() Modifiable {
	s.r = FlipY(s.r)
	return s
}
func (s *Sprite) Fade(alpha int) Modifiable {
	s.r = Fade(s.r, alpha)
	return s
}
func OverlaySprites(sps []Sprite) *Sprite {
	tmpSprite := sps[len(sps)-1].Copy().(*Sprite)
	for i := len(sps) - 1; i > 0; i-- {
		tmpSprite.r = FillMask(tmpSprite.r, *sps[i-1].r)
	}
	return tmpSprite
}

func ParseSubSprite(s string, x, y, w, h, pad int) *Sprite {
	sh, _ := LoadSheet(dir, s, w, h, pad)
	return sh.SubSprite(x, y)
}
<|endoftext|>


<commit_before><commit_msg>add parameter to file dan date interval, and also get interval from database<commit_after><|endoftext|>


<commit_before>package normalizeurl

import (
	"testing"
)

func TestNormalize(t *testing.T) {
	tests := []struct {
		value    string
		expected string
	}{
		{"www.sindresorhus.com", "http://sindresorhus.com"},
		{"sindresorhus.com", "http://sindresorhus.com"},
		{"HTTP://sindresorhus.com", "http://sindresorhus.com"},
		{"//sindresorhus.com", "http://sindresorhus.com"},
		{"http://sindresorhus.com", "http://sindresorhus.com"},
		{"http://sindresorhus.com:80", "http://sindresorhus.com"},
		{"https://sindresorhus.com:443", "https://sindresorhus.com"},
		{"ftp://sindresorhus.com:21", "ftp://sindresorhus.com"},
		{"http://www.sindresorhus.com", "http://sindresorhus.com"},
		{"www.sindresorhus.com", "http://sindresorhus.com"},
		{"http://sindresorhus.com/foo/", "http://sindresorhus.com/foo"},
		{"sindresorhus.com/?foo=bar%20baz", "http://sindresorhus.com/?foo=bar baz"},
		{"http://sindresorhus.com/?", "http://sindresorhus.com"},
		{"http://xn--xample-hva.com", "http://êxample.com"},
		{"http://sindresorhus.com/?b=bar&a=foo", "http://sindresorhus.com/?a=foo&b=bar"},
	}

	for i := range tests {
		actual, err := normalize(tests[i].value)
		if err != nil {
			t.Error("normalize failed", err)
		}
		if actual != tests[i].expected {
			t.Error("normalize did not match expected value", i, actual, tests[i].expected)
		}
	}
}
<commit_msg>chore: use my domain for those test cases<commit_after>package normalizeurl

import (
	"testing"
)

func TestNormalize(t *testing.T) {
	tests := []struct {
		value    string
		expected string
	}{
		{"www.sekimura.org", "http://sekimura.org"},
		{"sekimura.org", "http://sekimura.org"},
		{"HTTP://sekimura.org", "http://sekimura.org"},
		{"//sekimura.org", "http://sekimura.org"},
		{"http://sekimura.org", "http://sekimura.org"},
		{"http://sekimura.org:80", "http://sekimura.org"},
		{"https://sekimura.org:443", "https://sekimura.org"},
		{"ftp://sekimura.org:21", "ftp://sekimura.org"},
		{"http://www.sekimura.org", "http://sekimura.org"},
		{"www.sekimura.org", "http://sekimura.org"},
		{"http://sekimura.org/foo/", "http://sekimura.org/foo"},
		{"sekimura.org/?foo=bar%20baz", "http://sekimura.org/?foo=bar baz"},
		{"http://sekimura.org/?", "http://sekimura.org"},
		{"http://xn--xample-hva.com", "http://êxample.com"},
		{"http://sekimura.org/?b=bar&a=foo", "http://sekimura.org/?a=foo&b=bar"},
	}

	for i := range tests {
		actual, err := normalize(tests[i].value)
		if err != nil {
			t.Error("normalize failed", err)
		}
		if actual != tests[i].expected {
			t.Error("normalize did not match expected value", i, actual, tests[i].expected)
		}
	}
}
<|endoftext|>


<commit_before>package cluster_test

import (
	"context"
	"crypto/x509"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/canonical/go-dqlite/driver"
	"github.com/lxc/lxd/lxd/cluster"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/osarch"
	"github.com/lxc/lxd/shared/version"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// After a heartbeat request is completed, the leader updates the heartbeat
// timestamp column, and the serving node updates its cache of raft nodes.
func TestHeartbeat(t *testing.T) {
	f := heartbeatFixture{t: t}
	defer f.Cleanup()

	f.Bootstrap()
	f.Grow()
	f.Grow()

	leader := f.Leader()
	leaderState := f.State(leader)

	// Artificially mark all nodes as down
	err := leaderState.Cluster.Transaction(func(tx *db.ClusterTx) error {
		nodes, err := tx.GetNodes()
		require.NoError(t, err)
		for _, node := range nodes {
			err := tx.SetNodeHeartbeat(node.Address, time.Now().Add(-time.Minute))
			require.NoError(t, err)
		}
		return nil
	})
	require.NoError(t, err)

	// Perform the heartbeat requests.
	leader.Cluster = leaderState.Cluster
	heartbeat, _ := cluster.HeartbeatTask(leader)
	ctx := context.Background()
	heartbeat(ctx)

	// The heartbeat timestamps of all nodes got updated
	err = leaderState.Cluster.Transaction(func(tx *db.ClusterTx) error {
		nodes, err := tx.GetNodes()
		require.NoError(t, err)

		offlineThreshold, err := tx.GetNodeOfflineThreshold()
		require.NoError(t, err)

		for _, node := range nodes {
			assert.False(t, node.IsOffline(offlineThreshold))
		}
		return nil
	})
	require.NoError(t, err)
}

// Helper for testing heartbeat-related code.
type heartbeatFixture struct {
	t        *testing.T
	gateways map[int]*cluster.Gateway              // node index to gateway
	states   map[*cluster.Gateway]*state.State     // gateway to its state handle
	servers  map[*cluster.Gateway]*httptest.Server // gateway to its HTTP server
	cleanups []func()
}

// Bootstrap the first node of the cluster.
func (f *heartbeatFixture) Bootstrap() *cluster.Gateway {
	f.t.Logf("create bootstrap node for test cluster")
	state, gateway, _ := f.node()

	err := cluster.Bootstrap(state, gateway, "buzz")
	require.NoError(f.t, err)

	return gateway
}

// Grow adds a new node to the cluster.
func (f *heartbeatFixture) Grow() *cluster.Gateway {
	// Figure out the current leader
	f.t.Logf("adding another node to the test cluster")
	target := f.Leader()
	targetState := f.states[target]

	state, gateway, address := f.node()
	name := address

	nodes, err := cluster.Accept(
		targetState, target, name, address, cluster.SchemaVersion, len(version.APIExtensions), osarch.ARCH_64BIT_INTEL_X86)
	require.NoError(f.t, err)

	err = cluster.Join(state, gateway, target.NetworkCert(), target.ServerCert(), name, nodes)
	require.NoError(f.t, err)

	return gateway
}

// Return the leader gateway in the cluster.
func (f *heartbeatFixture) Leader() *cluster.Gateway {
	timeout := time.Second
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	for {
		for _, gateway := range f.gateways {
			isLeader, err := gateway.IsLeader()
			if err != nil {
				f.t.Errorf("failed to check leadership: %v", err)
			}
			if isLeader {
				return gateway
			}
		}

		select {
		case <-ctx.Done():
			f.t.Errorf("no leader was elected within %s", timeout)
		default:
		}

		// Wait a bit for election to take place
		time.Sleep(10 * time.Millisecond)
	}
}

// Return a follower gateway in the cluster.
func (f *heartbeatFixture) Follower() *cluster.Gateway {
	timeout := time.Second
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	for {
		for _, gateway := range f.gateways {
			isLeader, err := gateway.IsLeader()
			if err != nil {
				f.t.Errorf("failed to check leadership: %v", err)
			}
			if !isLeader {
				return gateway
			}
		}

		select {
		case <-ctx.Done():
			f.t.Errorf("no node running as follower")
		default:
		}

		// Wait a bit for election to take place
		time.Sleep(10 * time.Millisecond)
	}
}

// Return the cluster index of the given gateway.
func (f *heartbeatFixture) Index(gateway *cluster.Gateway) int {
	for i := range f.gateways {
		if f.gateways[i] == gateway {
			return i
		}
	}
	return -1
}

// Return the state associated with the given gateway.
func (f *heartbeatFixture) State(gateway *cluster.Gateway) *state.State {
	return f.states[gateway]
}

// Return the HTTP server associated with the given gateway.
func (f *heartbeatFixture) Server(gateway *cluster.Gateway) *httptest.Server {
	return f.servers[gateway]
}

// Creates a new node, without either bootstrapping or joining it.
//
// Return the associated gateway and network address.
func (f *heartbeatFixture) node() (*state.State, *cluster.Gateway, string) {
	if f.gateways == nil {
		f.gateways = make(map[int]*cluster.Gateway)
		f.states = make(map[*cluster.Gateway]*state.State)
		f.servers = make(map[*cluster.Gateway]*httptest.Server)
	}

	state, cleanup := state.NewTestState(f.t)
	f.cleanups = append(f.cleanups, cleanup)

	serverCert := shared.TestingKeyPair()
	state.ServerCert = func() *shared.CertInfo { return serverCert }
	gateway := newGateway(f.t, state.Node, serverCert, serverCert)
	f.cleanups = append(f.cleanups, func() { gateway.Shutdown() })

	mux := http.NewServeMux()
	server := newServer(serverCert, mux)

	trustedCerts := func() map[int]map[string]x509.Certificate {
		return nil
	}

	for path, handler := range gateway.HandlerFuncs(nil, trustedCerts) {
		mux.HandleFunc(path, handler)
	}

	address := server.Listener.Addr().String()
	mf := &membershipFixtures{t: f.t, state: state}
	mf.ClusterAddress(address)

	var err error
	require.NoError(f.t, state.Cluster.Close())
	store := gateway.NodeStore()
	dial := gateway.DialFunc()
	state.Cluster, err = db.OpenCluster(
		"db.bin", store, address, "/unused/db/dir", 5*time.Second, nil,
		driver.WithDialFunc(dial))
	require.NoError(f.t, err)

	f.gateways[len(f.gateways)] = gateway
	f.states[gateway] = state
	f.servers[gateway] = server

	return state, gateway, address
}

func (f *heartbeatFixture) Cleanup() {
	// Run the cleanups in reverse order
	for i := len(f.cleanups) - 1; i >= 0; i-- {
		f.cleanups[i]()
	}
	for _, server := range f.servers {
		server.Close()
	}
}
<commit_msg>lxd/cluster/heartbeat/test: Fixes TestHeartbeat so that it waits for join notification heartbeats to occur<commit_after>package cluster_test

import (
	"context"
	"crypto/x509"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/canonical/go-dqlite/driver"
	"github.com/lxc/lxd/lxd/cluster"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/osarch"
	"github.com/lxc/lxd/shared/version"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// After a heartbeat request is completed, the leader updates the heartbeat
// timestamp column, and the serving node updates its cache of raft nodes.
func TestHeartbeat(t *testing.T) {
	f := heartbeatFixture{t: t}
	defer f.Cleanup()

	f.Bootstrap()
	f.Grow()
	f.Grow()

	time.Sleep(1 * time.Second) // Wait for join notifiation triggered heartbeats to complete.

	leader := f.Leader()
	leaderState := f.State(leader)

	// Artificially mark all nodes as down
	err := leaderState.Cluster.Transaction(func(tx *db.ClusterTx) error {
		nodes, err := tx.GetNodes()
		require.NoError(t, err)
		for _, node := range nodes {
			err := tx.SetNodeHeartbeat(node.Address, time.Now().Add(-time.Minute))
			require.NoError(t, err)
		}
		return nil
	})
	require.NoError(t, err)

	// Perform the heartbeat requests.
	leader.Cluster = leaderState.Cluster
	heartbeat, _ := cluster.HeartbeatTask(leader)
	ctx := context.Background()
	heartbeat(ctx)

	// The heartbeat timestamps of all nodes got updated
	err = leaderState.Cluster.Transaction(func(tx *db.ClusterTx) error {
		nodes, err := tx.GetNodes()
		require.NoError(t, err)

		offlineThreshold, err := tx.GetNodeOfflineThreshold()
		require.NoError(t, err)

		for _, node := range nodes {
			assert.False(t, node.IsOffline(offlineThreshold))
		}
		return nil
	})
	require.NoError(t, err)
}

// Helper for testing heartbeat-related code.
type heartbeatFixture struct {
	t        *testing.T
	gateways map[int]*cluster.Gateway              // node index to gateway
	states   map[*cluster.Gateway]*state.State     // gateway to its state handle
	servers  map[*cluster.Gateway]*httptest.Server // gateway to its HTTP server
	cleanups []func()
}

// Bootstrap the first node of the cluster.
func (f *heartbeatFixture) Bootstrap() *cluster.Gateway {
	f.t.Logf("create bootstrap node for test cluster")
	state, gateway, _ := f.node()

	err := cluster.Bootstrap(state, gateway, "buzz")
	require.NoError(f.t, err)

	return gateway
}

// Grow adds a new node to the cluster.
func (f *heartbeatFixture) Grow() *cluster.Gateway {
	// Figure out the current leader
	f.t.Logf("adding another node to the test cluster")
	target := f.Leader()
	targetState := f.states[target]

	state, gateway, address := f.node()
	name := address

	nodes, err := cluster.Accept(
		targetState, target, name, address, cluster.SchemaVersion, len(version.APIExtensions), osarch.ARCH_64BIT_INTEL_X86)
	require.NoError(f.t, err)

	err = cluster.Join(state, gateway, target.NetworkCert(), target.ServerCert(), name, nodes)
	require.NoError(f.t, err)

	return gateway
}

// Return the leader gateway in the cluster.
func (f *heartbeatFixture) Leader() *cluster.Gateway {
	timeout := time.Second
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	for {
		for _, gateway := range f.gateways {
			isLeader, err := gateway.IsLeader()
			if err != nil {
				f.t.Errorf("failed to check leadership: %v", err)
			}
			if isLeader {
				return gateway
			}
		}

		select {
		case <-ctx.Done():
			f.t.Errorf("no leader was elected within %s", timeout)
		default:
		}

		// Wait a bit for election to take place
		time.Sleep(10 * time.Millisecond)
	}
}

// Return a follower gateway in the cluster.
func (f *heartbeatFixture) Follower() *cluster.Gateway {
	timeout := time.Second
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	for {
		for _, gateway := range f.gateways {
			isLeader, err := gateway.IsLeader()
			if err != nil {
				f.t.Errorf("failed to check leadership: %v", err)
			}
			if !isLeader {
				return gateway
			}
		}

		select {
		case <-ctx.Done():
			f.t.Errorf("no node running as follower")
		default:
		}

		// Wait a bit for election to take place
		time.Sleep(10 * time.Millisecond)
	}
}

// Return the cluster index of the given gateway.
func (f *heartbeatFixture) Index(gateway *cluster.Gateway) int {
	for i := range f.gateways {
		if f.gateways[i] == gateway {
			return i
		}
	}
	return -1
}

// Return the state associated with the given gateway.
func (f *heartbeatFixture) State(gateway *cluster.Gateway) *state.State {
	return f.states[gateway]
}

// Return the HTTP server associated with the given gateway.
func (f *heartbeatFixture) Server(gateway *cluster.Gateway) *httptest.Server {
	return f.servers[gateway]
}

// Creates a new node, without either bootstrapping or joining it.
//
// Return the associated gateway and network address.
func (f *heartbeatFixture) node() (*state.State, *cluster.Gateway, string) {
	if f.gateways == nil {
		f.gateways = make(map[int]*cluster.Gateway)
		f.states = make(map[*cluster.Gateway]*state.State)
		f.servers = make(map[*cluster.Gateway]*httptest.Server)
	}

	state, cleanup := state.NewTestState(f.t)
	f.cleanups = append(f.cleanups, cleanup)

	serverCert := shared.TestingKeyPair()
	state.ServerCert = func() *shared.CertInfo { return serverCert }
	gateway := newGateway(f.t, state.Node, serverCert, serverCert)
	f.cleanups = append(f.cleanups, func() { gateway.Shutdown() })

	mux := http.NewServeMux()
	server := newServer(serverCert, mux)

	trustedCerts := func() map[int]map[string]x509.Certificate {
		return nil
	}

	for path, handler := range gateway.HandlerFuncs(nil, trustedCerts) {
		mux.HandleFunc(path, handler)
	}

	address := server.Listener.Addr().String()
	mf := &membershipFixtures{t: f.t, state: state}
	mf.ClusterAddress(address)

	var err error
	require.NoError(f.t, state.Cluster.Close())
	store := gateway.NodeStore()
	dial := gateway.DialFunc()
	state.Cluster, err = db.OpenCluster(
		"db.bin", store, address, "/unused/db/dir", 5*time.Second, nil,
		driver.WithDialFunc(dial))
	require.NoError(f.t, err)

	f.gateways[len(f.gateways)] = gateway
	f.states[gateway] = state
	f.servers[gateway] = server

	return state, gateway, address
}

func (f *heartbeatFixture) Cleanup() {
	// Run the cleanups in reverse order
	for i := len(f.cleanups) - 1; i >= 0; i-- {
		f.cleanups[i]()
	}
	for _, server := range f.servers {
		server.Close()
	}
}
<|endoftext|>