<commit_before>package numbers

import (
	"fmt"
	"math"
)

// FactorsList lists all prime factors for a positive integer position.
// Does not include repeated factors.
func FactorsList(n int) ([]int, error) {
	if n < 2 {
		return nil, fmt.Errorf("no prime factors for numbers below two. received '%d'", n)
	}
	if n == 2 {
		return []int{2}, nil
	}
	var factors = make([]int, 0)
	for i := 2; i <= n; i++ {
		for n%i == 0 {
			factors = append(factors, i)
			n /= i
			i++
		}
	}
	return factors, nil
}

// IsPrime checks if a given positive int is a prime number.
func IsPrime(n int) bool {
	// Considering that primes are greater than 1
	if n <= 0 {
		return false
	}
	// For even, only true if equals to two
	if n%2 == 0 {
		return n == 2
	}
	root := int(math.Sqrt(float64(n)))
	// Tries to divide n for all odd numbers from 3 to n
	for i := 3; i <= root; i += 2 {
		if n%i == 0 {
			return false
		}
	}
	return true
}

// FibonacciGen emits an infinite stream of Fibonacci values.
func FibonacciGen() chan int {
	c := make(chan int)
	go func() {
		for i, j := 0, 1; ; i, j = i+j, i {
			c <- i
		}
	}()
	return c
}

// NthFibonacci returns the nth Fibonacci value for given a int position.
func NthFibonacci(pos int) int {
	c := FibonacciGen()
	f := make([]int, pos)
	for i := 0; i <= pos; i++ {
		f = append(f, <-c)
	}
	return f[len(f)-1]
}

// EvenNumbers returns a list of even numbers from A to B.
func EvenNumbers(a, b int) ([]int, error) {
	even, _, err := SliceByParity(a, b)
	if err != nil {
		return nil, err
	}
	return even, nil
}

// OddNumbers returns a list of even numbers from A to B.
func OddNumbers(a, b int) ([]int, error) {
	_, odd, err := SliceByParity(a, b)
	if err != nil {
		return nil, err
	}
	return odd, nil
}

// NthEven returns the nth even number for a given position.
func NthEven(pos int) (int, error) {
	if pos < 0 {
		return 0, fmt.Errorf("input must be a positive number. received '%d'", pos)
	}
	even, _ := EvenNumbers(0, (pos*2)-1)
	return even[len(even)-1], nil
}
<commit_msg>Implement NthOdd function<commit_after>package numbers

import (
	"fmt"
	"math"
)

// FactorsList lists all prime factors for a positive integer position.
// Does not include repeated factors.
func FactorsList(n int) ([]int, error) {
	if n < 2 {
		return nil, fmt.Errorf("no prime factors for numbers below two. received '%d'", n)
	}
	if n == 2 {
		return []int{2}, nil
	}
	var factors = make([]int, 0)
	for i := 2; i <= n; i++ {
		for n%i == 0 {
			factors = append(factors, i)
			n /= i
			i++
		}
	}
	return factors, nil
}

// IsPrime checks if a given positive int is a prime number.
func IsPrime(n int) bool {
	// Considering that primes are greater than 1
	if n <= 0 {
		return false
	}
	// For even, only true if equals to two
	if n%2 == 0 {
		return n == 2
	}
	root := int(math.Sqrt(float64(n)))
	// Tries to divide n for all odd numbers from 3 to n
	for i := 3; i <= root; i += 2 {
		if n%i == 0 {
			return false
		}
	}
	return true
}

// FibonacciGen emits an infinite stream of Fibonacci values.
func FibonacciGen() chan int {
	c := make(chan int)
	go func() {
		for i, j := 0, 1; ; i, j = i+j, i {
			c <- i
		}
	}()
	return c
}

// NthFibonacci returns the nth Fibonacci value for given a int position.
func NthFibonacci(pos int) int {
	c := FibonacciGen()
	f := make([]int, pos)
	for i := 0; i <= pos; i++ {
		f = append(f, <-c)
	}
	return f[len(f)-1]
}

// EvenNumbers returns a list of even numbers from A to B.
func EvenNumbers(a, b int) ([]int, error) {
	even, _, err := SliceByParity(a, b)
	if err != nil {
		return nil, err
	}
	return even, nil
}

// OddNumbers returns a list of even numbers from A to B.
func OddNumbers(a, b int) ([]int, error) {
	_, odd, err := SliceByParity(a, b)
	if err != nil {
		return nil, err
	}
	return odd, nil
}

// NthEven returns the nth even number for a given position.
func NthEven(pos int) (int, error) {
	if pos < 0 {
		return 0, fmt.Errorf("input must be a positive number. received '%d'", pos)
	}
	even, _ := EvenNumbers(0, (pos*2)-1)
	return even[len(even)-1], nil
}

// NthOdd returns the nth odd number for a given position.
func NthOdd(pos int) (int, error) {
	if pos < 0 {
		return 0, fmt.Errorf("input must be a positive number. received '%d'", pos)
	}
	odd, _ := OddNumbers(0, (pos*2)-1)
	return odd[len(odd)-1], nil
}
<|endoftext|>


<commit_before>package cri_test

import (
	"testing"

	"github.com/bmizerany/assert"
	"github.com/weaveworks/scope/probe/cri"
)

var nonUnixSocketsTest = []struct {
	endpoint     string
	errorMessage string
}{
	{"http://xyz.com", "protocol \"http\" not supported"},
	{"tcp://var/unix.sock", "endpoint was not unix socket tcp"},
	{"http://[fe80::%31]/", "parse http://[fe80::%31]/: invalid URL escape \"%31\""},
}

func TestParseNonUnixEndpointUrl(t *testing.T) {
	for _, tt := range nonUnixSocketsTest {
		_, err := cri.NewCRIClient(tt.endpoint)

		assert.Equal(t, tt.errorMessage, err.Error())
	}
}

var unixSocketsTest = []string{
	"127.0.0.1", // tests the fallback endpoint
	"unix://127.0.0.1",
	"unix///var/run/dockershim.sock",
	"var/run/dockershim.sock",
}

func TestParseUnixEndpointUrl(t *testing.T) {
	for _, tt := range unixSocketsTest {
		client, err := cri.NewCRIClient(tt)

		assert.Equal(t, nil, err)
		assert.NotEqual(t, nil, client)
	}

}
<commit_msg>Fix up test for go1.14 change<commit_after>package cri_test

import (
	"testing"

	"github.com/bmizerany/assert"
	"github.com/weaveworks/scope/probe/cri"
)

var nonUnixSocketsTest = []struct {
	endpoint     string
	errorMessage string
}{
	{"http://xyz.com", "protocol \"http\" not supported"},
	{"tcp://var/unix.sock", "endpoint was not unix socket tcp"},
	{"http://[fe80::%31]/", "parse \"http://[fe80::%31]/\": invalid URL escape \"%31\""},
}

func TestParseNonUnixEndpointUrl(t *testing.T) {
	for _, tt := range nonUnixSocketsTest {
		_, err := cri.NewCRIClient(tt.endpoint)

		assert.Equal(t, tt.errorMessage, err.Error())
	}
}

var unixSocketsTest = []string{
	"127.0.0.1", // tests the fallback endpoint
	"unix://127.0.0.1",
	"unix///var/run/dockershim.sock",
	"var/run/dockershim.sock",
}

func TestParseUnixEndpointUrl(t *testing.T) {
	for _, tt := range unixSocketsTest {
		client, err := cri.NewCRIClient(tt)

		assert.Equal(t, nil, err)
		assert.NotEqual(t, nil, client)
	}

}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "flag"
    "log"
    "runtime"
    "strconv"
    "functorama.com/demo/libgodelbrot"
)

// Golang entry point
func main() {
    // Set number of cores
    runtime.GOMAXPROCS(runtime.NumCPU())

    args := parseArguments()
    request, argErr := extractRenderParameters(args)
    if argErr != nil {
        log.Fatal("Error:", argErr)
    }

    info, godelErr := libgodelbrot.AutoConf(request)

    if godelErr != nil {
        log.Fatal(godelErr)
    }

    text, jsonErr := libgodelbrot.ToJSON(info)
    if jsonErr == nil {
        fmt.Printf("%s", text)
    } else {
        log.Fatal("Error creating JSON:", jsonErr)
    }
}

// Structure representing our command line arguments
type commandLine struct {
    iterateLimit   uint
    divergeLimit   float64
    width          uint
    height         uint
    realMin        string
    realMax        string
    imagMin        string
    imagMax        string
    mode           string
    regionCollapse uint
    jobs  uint
    storedPalette  string
    fixAspect      bool
    numerics string
    glitchSamples uint
    precision uint
}

// Parse command line arguments into a `commandLine' structure
func parseArguments() commandLine {
    args := commandLine{}

    components := []float64{
        real(libgodelbrot.MandelbrotMin),
        imag(libgodelbrot.MandelbrotMin),
        real(libgodelbrot.MandelbrotMax),
        imag(libgodelbrot.MandelbrotMax),
    }
    bounds := make([]string, len(components))
    for i, num := range components {
        bounds[i] = strconv.FormatFloat(num, 'e', -1, 64)
    }

    renderThreads := uint(runtime.NumCPU())

    flag.UintVar(&args.iterateLimit, "iterateLimit",
        uint(libgodelbrot.DefaultIterations), "Maximum number of iterations")
    flag.Float64Var(&args.divergeLimit, "divergeLimit",
        libgodelbrot.DefaultDivergeLimit, "Limit where function is said to diverge to infinity")
    flag.UintVar(&args.width, "imageWidth",
        libgodelbrot.DefaultImageWidth, "Width of output PNG")
    flag.UintVar(&args.height, "imageHeight",
        libgodelbrot.DefaultImageHeight, "Height of output PNG")
    flag.StringVar(&args.realMin, "realMin",
        bounds[0], "Leftmost position on complex plane")
    flag.StringVar(&args.imagMin, "imagMin",
        bounds[1], "Bottommost position on complex plane")
    flag.StringVar(&args.realMax, "realMax",
        bounds[2], "Rightmost position on complex plane")
    flag.StringVar(&args.imagMax, "imagMax",
        bounds[3], "Topmost position on complex plane")
    flag.StringVar(&args.mode, "mode", "auto",
        "Render mode.  (auto|sequence|region|concurrent)")
    flag.UintVar(&args.regionCollapse, "collapse",
        libgodelbrot.DefaultCollapse, "Pixel width of region at which sequential render is forced")
    flag.UintVar(&args.jobs, "jobs",
        renderThreads, "Number of rendering threads in concurrent renderer")
    flag.UintVar(&args.glitchSamples, "regionGlitchSamples",
        libgodelbrot.DefaultGlitchSamples, "Size of region render glitch-correncting sample set")
    flag.UintVar(&args.precision, "prec",
        libgodelbrot.DefaultPrecision, "Precision for big.Float render mode")
    flag.StringVar(&args.storedPalette, "storedPalette",
        "pretty", "Name of stored palette (pretty|redscale)")
    flag.StringVar(&args.numerics, "numerics",
        "auto", "Numerical system (auto|native|bigfloat)")
    flag.BoolVar(&args.fixAspect, "fixAspect",
        true, "Resize plane window to fit image aspect ratio")
    flag.Parse()

    return args
}

// Validate and extract a render description from the command line arguments
func extractRenderParameters(args commandLine) (*libgodelbrot.Request, error) {
    const max8 = uint(^uint8(0))
    if args.iterateLimit > max8 {
        return nil, fmt.Errorf("iterateLimit out of bounds.  Valid values in range (0,%v)", max8)
    }

    if args.divergeLimit <= 0.0 {
        return nil, fmt.Errorf("divergeLimit out of bounds.  Valid values in range (0,)")
    }

    const max16 = uint(^uint16(0))
    if args.jobs > max16 {
        return nil, fmt.Errorf("jobs out of bounds.  Valid values in range (0,%v)", max16)
    }

    numerics := libgodelbrot.AutoDetectNumericsMode
    switch args.numerics {
    case "auto":
        // No change
    case "bigfloat":
        numerics = libgodelbrot.BigFloatNumericsMode
    case "native":
        numerics = libgodelbrot.NativeNumericsMode
    default:
        log.Fatal("Unknown numerics mode:", args.numerics)
    }

    renderer := libgodelbrot.AutoDetectRenderMode
    switch args.mode {
    case "auto":
        // No change
    case "sequence":
        renderer = libgodelbrot.SequenceRenderMode
    case "region":
        renderer = libgodelbrot.RegionRenderMode
    case "concurrent":
        renderer = libgodelbrot.SharedRegionRenderMode
    default:
        log.Fatal("Unknown render mode:", args.mode)
    }

    description := &libgodelbrot.Request {
        IterateLimit: uint8(args.iterateLimit),
        DivergeLimit: args.divergeLimit,
        GlitchSamples: args.glitchSamples,
        RealMin: args.realMin,
        RealMax: args.realMax,
        ImagMin: args.imagMin,
        ImagMax: args.imagMax,
        ImageWidth: args.width,
        ImageHeight: args.height,
        PaletteType: libgodelbrot.StoredPalette,
        PaletteCode: args.storedPalette,
        FixAspect: args.fixAspect,
        Numerics: numerics,
        Renderer: renderer,
        RegionCollapse: args.regionCollapse,
        Jobs: uint16(args.jobs),
    }

    return description, nil
}<commit_msg>Remove newline<commit_after>package main

import (
    "fmt"
    "flag"
    "log"
    "runtime"
    "strconv"
    "functorama.com/demo/libgodelbrot"
)

// Golang entry point
func main() {
    // Set number of cores
    runtime.GOMAXPROCS(runtime.NumCPU())

    args := parseArguments()
    request, argErr := extractRenderParameters(args)
    if argErr != nil {
        log.Fatal("Error:", argErr)
    }

    info, godelErr := libgodelbrot.AutoConf(request)

    if godelErr != nil {
        log.Fatal(godelErr)
    }

    text, jsonErr := libgodelbrot.ToJSON(info)
    if jsonErr == nil {
        fmt.Printf("%s", text)
    } else {
        log.Fatal("Error creating JSON:", jsonErr)
    }
}

// Structure representing our command line arguments
type commandLine struct {
    iterateLimit   uint
    divergeLimit   float64
    width          uint
    height         uint
    realMin        string
    realMax        string
    imagMin        string
    imagMax        string
    mode           string
    regionCollapse uint
    jobs  uint
    storedPalette  string
    fixAspect      bool
    numerics string
    glitchSamples uint
    precision uint
}

// Parse command line arguments into a `commandLine' structure
func parseArguments() commandLine {
    args := commandLine{}

    components := []float64{
        real(libgodelbrot.MandelbrotMin),
        imag(libgodelbrot.MandelbrotMin),
        real(libgodelbrot.MandelbrotMax),
        imag(libgodelbrot.MandelbrotMax),
    }
    bounds := make([]string, len(components))
    for i, num := range components {
        bounds[i] = strconv.FormatFloat(num, 'e', -1, 64)
    }

    renderThreads := uint(runtime.NumCPU())

    flag.UintVar(&args.iterateLimit, "iterateLimit",
        uint(libgodelbrot.DefaultIterations), "Maximum number of iterations")
    flag.Float64Var(&args.divergeLimit, "divergeLimit",
        libgodelbrot.DefaultDivergeLimit, "Limit where function is said to diverge to infinity")
    flag.UintVar(&args.width, "imageWidth",
        libgodelbrot.DefaultImageWidth, "Width of output PNG")
    flag.UintVar(&args.height, "imageHeight",
        libgodelbrot.DefaultImageHeight, "Height of output PNG")
    flag.StringVar(&args.realMin, "realMin",
        bounds[0], "Leftmost position on complex plane")
    flag.StringVar(&args.imagMin, "imagMin",
        bounds[1], "Bottommost position on complex plane")
    flag.StringVar(&args.realMax, "realMax",
        bounds[2], "Rightmost position on complex plane")
    flag.StringVar(&args.imagMax, "imagMax",
        bounds[3], "Topmost position on complex plane")
    flag.StringVar(&args.mode, "mode", "auto",
        "Render mode.  (auto|sequence|region|concurrent)")
    flag.UintVar(&args.regionCollapse, "collapse",
        libgodelbrot.DefaultCollapse, "Pixel width of region at which sequential render is forced")
    flag.UintVar(&args.jobs, "jobs",
        renderThreads, "Number of rendering threads in concurrent renderer")
    flag.UintVar(&args.glitchSamples, "regionGlitchSamples",
        libgodelbrot.DefaultGlitchSamples, "Size of region render glitch-correncting sample set")
    flag.UintVar(&args.precision, "prec",
        libgodelbrot.DefaultPrecision, "Precision for big.Float render mode")
    flag.StringVar(&args.storedPalette, "storedPalette",
        "pretty", "Name of stored palette (pretty|redscale)")
    flag.StringVar(&args.numerics, "numerics",
        "auto", "Numerical system (auto|native|bigfloat)")
    flag.BoolVar(&args.fixAspect, "fixAspect",
        true, "Resize plane window to fit image aspect ratio")
    flag.Parse()

    return args
}

// Validate and extract a render description from the command line arguments
func extractRenderParameters(args commandLine) (*libgodelbrot.Request, error) {
    const max8 = uint(^uint8(0))
    if args.iterateLimit > max8 {
        return nil, fmt.Errorf("iterateLimit out of bounds.  Valid values in range (0,%v)", max8)
    }

    if args.divergeLimit <= 0.0 {
        return nil, fmt.Errorf("divergeLimit out of bounds.  Valid values in range (0,)")
    }

    const max16 = uint(^uint16(0))
    if args.jobs > max16 {
        return nil, fmt.Errorf("jobs out of bounds.  Valid values in range (0,%v)", max16)
    }

    numerics := libgodelbrot.AutoDetectNumericsMode
    switch args.numerics {
    case "auto":
        // No change
    case "bigfloat":
        numerics = libgodelbrot.BigFloatNumericsMode
    case "native":
        numerics = libgodelbrot.NativeNumericsMode
    default:
        log.Fatal("Unknown numerics mode:", args.numerics)
    }

    renderer := libgodelbrot.AutoDetectRenderMode
    switch args.mode {
    case "auto":
        // No change
    case "sequence":
        renderer = libgodelbrot.SequenceRenderMode
    case "region":
        renderer = libgodelbrot.RegionRenderMode
    case "concurrent":
        renderer = libgodelbrot.SharedRegionRenderMode
    default:
        log.Fatal("Unknown render mode:", args.mode)
    }

    description := &libgodelbrot.Request {
        IterateLimit: uint8(args.iterateLimit),
        DivergeLimit: args.divergeLimit,
        GlitchSamples: args.glitchSamples,
        RealMin: args.realMin,
        RealMax: args.realMax,
        ImagMin: args.imagMin,
        ImagMax: args.imagMax,
        ImageWidth: args.width,
        ImageHeight: args.height,
        PaletteType: libgodelbrot.StoredPalette,
        PaletteCode: args.storedPalette,
        FixAspect: args.fixAspect,
        Numerics: numerics,
        Renderer: renderer,
        RegionCollapse: args.regionCollapse,
        Jobs: uint16(args.jobs),
    }

    return description, nil
}<|endoftext|>


<commit_before>/* package producer provides simplified usage of Kafka producers build on top of https://github.com/Shopify/sarama */
package producer

import ("github.com/Shopify/sarama"
	"code.google.com/p/go-uuid/uuid"
)

// KafkaProducer publishes Kafka messages to a given topic.
// You MUST call Close() on a producer to avoid leaks, it will not be garbage-collected automatically when
// it passes out of scope.
type KafkaProducer struct {
	//the topic to consume from
	Topic      string

	/* This is for bootstrapping and the producer will only use it for getting metadata (topics, partitions and replicas).
    The socket connections for sending the actual data will be established based on the broker information returned in
    the metadata. */
	BrokerList []string
	client *sarama.Client
	producer *sarama.Producer
}

// NewKafkaProducer creates a new produce. It will publish messages to the given topic.
// You may also provide a sarama.ProducerConfig with more precise configurations or nil to use default configuration
func NewKafkaProducer(topic string, brokerList []string, config *sarama.ProducerConfig) *KafkaProducer {
	client, err := sarama.NewClient(uuid.New(), brokerList, sarama.NewClientConfig())
	if err != nil {
		panic(err)
	}

	producer, err := sarama.NewProducer(client, config)
	if err != nil {
		panic(err)
	}

	return &KafkaProducer{topic, brokerList, client, producer}
}

// Synchronously sends a message with this produces
func (kafkaProducer *KafkaProducer) Send(message string) error {
	//TODO do we need keys? what about partitioning?
	return kafkaProducer.producer.SendMessage(kafkaProducer.Topic, nil, sarama.StringEncoder(message))
}

func (kafkaProducer *KafkaProducer) SendBytes(message []byte) error {
	return kafkaProducer.producer.SendMessage(kafkaProducer.Topic, nil, sarama.ByteEncoder(message))
}

// Close indicates that no more messages will be produced with this producer and closes all underlying connections. It is required to call this function before
// a producer object passes out of scope, as it will otherwise leak memory.
func (kafkaProducer *KafkaProducer) Close() {
	kafkaProducer.producer.Close()
	kafkaProducer.client.Close()
}
<commit_msg>Update producer to new sarama producer API<commit_after>/* package producer provides simplified usage of Kafka producers build on top of https://github.com/Shopify/sarama */
package producer

import ("github.com/Shopify/sarama"
	"code.google.com/p/go-uuid/uuid"
)

// KafkaProducer publishes Kafka messages to a given topic.
// You MUST call Close() on a producer to avoid leaks, it will not be garbage-collected automatically when
// it passes out of scope.
type KafkaProducer struct {
	//the topic to consume from
	Topic      string

	/* This is for bootstrapping and the producer will only use it for getting metadata (topics, partitions and replicas).
    The socket connections for sending the actual data will be established based on the broker information returned in
    the metadata. */
	BrokerList []string
	client *sarama.Client
	producer *sarama.Producer
}

// NewKafkaProducer creates a new produce. It will publish messages to the given topic.
// You may also provide a sarama.ProducerConfig with more precise configurations or nil to use default configuration
func NewKafkaProducer(topic string, brokerList []string, config *sarama.ProducerConfig) *KafkaProducer {
	client, err := sarama.NewClient(uuid.New(), brokerList, sarama.NewClientConfig())
	if err != nil {
		panic(err)
	}

	producer, err := sarama.NewProducer(client, config)
	if err != nil {
		panic(err)
	}

	return &KafkaProducer{topic, brokerList, client, producer}
}

// Synchronously sends a message with this producer
func (kafkaProducer *KafkaProducer) Send(message string) *sarama.ProduceError {
	//TODO do we need keys? what about partitioning?
	kafkaProducer.producer.Input() <- &sarama.MessageToSend{Topic: kafkaProducer.Topic, Key: nil, Value: sarama.StringEncoder(message)}
	return <- kafkaProducer.producer.Errors()
}

func (kafkaProducer *KafkaProducer) SendBytes(message []byte) *sarama.ProduceError {
	kafkaProducer.producer.Input() <- &sarama.MessageToSend{Topic: kafkaProducer.Topic, Key: nil, Value: sarama.ByteEncoder(message)}
	return <- kafkaProducer.producer.Errors()
}

// Close indicates that no more messages will be produced with this producer and closes all underlying connections. It is required to call this function before
// a producer object passes out of scope, as it will otherwise leak memory.
func (kafkaProducer *KafkaProducer) Close() {
	kafkaProducer.producer.Close()
	kafkaProducer.client.Close()
}
<|endoftext|>


<commit_before>package main

import (
  "bytes"
  "conf"
  "inotify"
  "log"
  "os"
  "os/exec"
  "strconv"
  "strings"
  "sync/atomic"
  "time"
)

var Config *conf.ConfigFile
var ConfigName string
var Home string
var Lock int64
var Locks []int64
var Paths []string
var RemoteCount int

func handleEventOld() {
  var cmd *exec.Cmd
  //var pid string
  //var pid_out bytes.Buffer
  var cmdStdout bytes.Buffer
  var e error

  if !atomic.CompareAndSwapInt64(&Lock, 0, 1) {
    return
  }

  /*// Get the pid and stop the server.
  log.Println("cat: preparing...")
  cmd = exec.Command("cat", "build/curve_https.pid")
  cmd.Stdout = &pid_out
  e = cmd.Run()
  if e != nil {
    log.Println("cat:", e)
    goto next
  }
  //pid, e := strconv.ParseInt(out.String(), 10, 32)
  //if e != nil { continue }
  pid = pid_out.String()
  log.Println("pid:", pid)
  log.Println("kill: preparing...")
  e = exec.Command("kill", pid).Run()
  if e != nil {
    log.Println("kill:", e)
    goto next
  }*/

  // Wait at least a short while before pulling the repo.
  log.Println("sleeping...")
  time.Sleep(5 * time.Second)

  // Pull from local repository.
  log.Println("git-pull: preparing...")
  e = exec.Command("git", "pull", "origin", "master").Run()
  if e != nil {
    log.Println("git-pull:", e)
    goto next
  }

  // Wait at least a short while before installing.
  log.Println("sleeping...")
  time.Sleep(5 * time.Second)

  // Build and install the code.
  log.Println("make: preparing...")
  cmd = exec.Command("make")
  cmd.Stdout = &cmdStdout
  e = cmd.Run()
  if e != nil {
    log.Println(cmdStdout.String())
    log.Println("make:", e)
  }

  // Start the server.
  log.Println("start: preparing...")
  e = exec.Command("foreman", "start").Start()
  if e != nil {
    log.Println("start:", e)
  }

next:
  atomic.CompareAndSwapInt64(&Lock, 1, 0)
  return
}

func handleEvent(ev *inotify.Event) {
  var cmd *exec.Cmd
  var cmdStdout bytes.Buffer
  var e error

  //log.Println(ev)
  name := ev.Name

  log.Println("getting parent path...")
  idx := -1
  path := ""
  for i := 0; i < RemoteCount; i++ {
    if strings.HasPrefix(name, Paths[i]) {
      idx = i
      path = Paths[i]
      break
    }
  }
  if idx == -1 {
    log.Println("couldnt find parent path")
    return
  }

  //log.Println("acquiring lock", idx)
  if !atomic.CompareAndSwapInt64(&Locks[idx], 0, 1) {
    //log.Println("failed to acquire lock", idx)
    return
  }
  log.Println("acquired lock", idx)

  log.Println("sleeping...")
  time.Sleep(5 * time.Second)

  checkoutPath := strings.Join([]string{"/var/eggd", path}, "/")
  e = os.MkdirAll(checkoutPath, 0755)
  if e != nil {
    log.Println("os.MkdirAll:", e)
    goto next
  }
  e = os.Chdir(checkoutPath)
  if e != nil {
    log.Println("os.Chdir:", e)
    goto next
  }
  if os.IsNotExist(os.Chdir(".git")) {
    log.Println("running git-clone...")
    cmd = exec.Command("git", "clone", path, ".")
    cmd.Stdout = &cmdStdout
    e = cmd.Run()
    if e != nil {
      log.Println("git-clone:", e)
      log.Println(cmdStdout.String())
      goto next
    }
  } else {
    os.Chdir("..")
  }

  log.Println("running git-pull...")
  cmd = exec.Command("git", "pull", "origin", "master")
  cmd.Stdout = &cmdStdout
  cmd.Run()
  if e != nil {
    log.Println("git-pull:", e)
    log.Println(cmdStdout.String())
    goto next
  }

  log.Println("sleeping...")
  time.Sleep(5 * time.Second)

  log.Println("running make...")
  cmd = exec.Command("make")
  cmd.Stdout = &cmdStdout
  e = cmd.Run()
  if e != nil {
    log.Println("make:", e)
    log.Println(cmdStdout.String())
    goto next
  }

  log.Println("running foreman...")
  cmd = exec.Command("foreman", "start")
  cmd.Stdout = &cmdStdout
  e = cmd.Run()
  if e != nil {
    log.Println("foreman:", e)
    log.Println(cmdStdout.String())
    goto next
  }

next:
  log.Println("releasing lock", idx)
  atomic.CompareAndSwapInt64(&Locks[idx], 1, 0)
  return
}

func initConfig() {
  // Check that the configfile exists.
  Home = os.Getenv("HOME")
  //ConfigName = strings.Join([]string{Home, ".eggconfig"}, "/")
  ConfigName = "/etc/eggconfig"
  fd, e := os.OpenFile(ConfigName, os.O_RDWR | os.O_CREATE, 0644)
  if e != nil { log.Fatal(e) }
  e = fd.Close()
  if e != nil { log.Fatal(e) }

  // Make sure the configfile is set up correctly.
  Config, e := conf.ReadConfigFile(ConfigName)
  if e != nil { log.Fatal(e) }
  Config.AddSection("global")
  if !Config.HasOption("global", "count") {
    Config.AddOption("global", "count", "0")
  }

  // Modify the configfile through cmdline args.
  if len(os.Args) > 2 && os.Args[1] == "add" {
    log.Println("adding", os.Args[2], "to eggd path")
    count, _ := Config.GetInt("global", "count")
    count = count + 1
    Config.AddOption("global", "count", strconv.Itoa(count))
    section := strings.Join([]string{"remote-", strconv.Itoa(count)}, "")
    Config.AddOption(section, "path", os.Args[2])
    Config.WriteConfigFile(ConfigName, 0644, "")
    os.Exit(0)
  }

  RemoteCount, e = Config.GetInt("global", "count")
  if e != nil { log.Fatal(e) }
  Config.WriteConfigFile(ConfigName, 0644, "")
}

func startWatcher() {
  // Start the event loops. Use inotify to watch the configfile and each
  // repository path.
  Config, e := conf.ReadConfigFile(ConfigName)
  if e != nil { log.Fatal(e) }
  watcher, e := inotify.NewWatcher()
  if e != nil { log.Fatal(e) }
  log.Println("watching configfile")
  e = watcher.Watch(ConfigName)
  if e != nil { log.Fatal(e) }
  Locks = make([]int64, RemoteCount)
  Paths = make([]string, RemoteCount)
  for i := 1; i <= RemoteCount; i++ {
    section := strings.Join([]string{"remote-", strconv.Itoa(i)}, "")
    if !Config.HasOption(section, "path") {
      log.Println("doesnt have path")
      continue
    }
    path, e := Config.GetRawString(section, "path")
    if e != nil { log.Fatal(e) }
    log.Println("watching path", path)
    e = watcher.Watch(path)
    if e != nil { log.Fatal(e) }
    Locks[i-1] = 0
    Paths[i-1] = path
  }
  for {
    select {
      case ev := <-watcher.Event:
        go handleEvent(ev)
      case err := <-watcher.Error:
        log.Println("error:", err)
    }
  }
}

func main() {
  initConfig()
  startWatcher()
}
<commit_msg>Logging stderr.<commit_after>package main

import (
  "bytes"
  "conf"
  "inotify"
  "log"
  "os"
  "os/exec"
  "strconv"
  "strings"
  "sync/atomic"
  "time"
)

var Config *conf.ConfigFile
var ConfigName string
var Home string
var Lock int64
var Locks []int64
var Paths []string
var RemoteCount int

func handleEventOld() {
  var cmd *exec.Cmd
  //var pid string
  //var pid_out bytes.Buffer
  var cmdStdout bytes.Buffer
  var e error

  if !atomic.CompareAndSwapInt64(&Lock, 0, 1) {
    return
  }

  /*// Get the pid and stop the server.
  log.Println("cat: preparing...")
  cmd = exec.Command("cat", "build/curve_https.pid")
  cmd.Stdout = &pid_out
  e = cmd.Run()
  if e != nil {
    log.Println("cat:", e)
    goto next
  }
  //pid, e := strconv.ParseInt(out.String(), 10, 32)
  //if e != nil { continue }
  pid = pid_out.String()
  log.Println("pid:", pid)
  log.Println("kill: preparing...")
  e = exec.Command("kill", pid).Run()
  if e != nil {
    log.Println("kill:", e)
    goto next
  }*/

  // Wait at least a short while before pulling the repo.
  log.Println("sleeping...")
  time.Sleep(5 * time.Second)

  // Pull from local repository.
  log.Println("git-pull: preparing...")
  e = exec.Command("git", "pull", "origin", "master").Run()
  if e != nil {
    log.Println("git-pull:", e)
    goto next
  }

  // Wait at least a short while before installing.
  log.Println("sleeping...")
  time.Sleep(5 * time.Second)

  // Build and install the code.
  log.Println("make: preparing...")
  cmd = exec.Command("make")
  cmd.Stdout = &cmdStdout
  e = cmd.Run()
  if e != nil {
    log.Println(cmdStdout.String())
    log.Println("make:", e)
  }

  // Start the server.
  log.Println("start: preparing...")
  e = exec.Command("foreman", "start").Start()
  if e != nil {
    log.Println("start:", e)
  }

next:
  atomic.CompareAndSwapInt64(&Lock, 1, 0)
  return
}

func handleEvent(ev *inotify.Event) {
  var cmd *exec.Cmd
  var cmdStdout bytes.Buffer
  var cmdStderr bytes.Buffer
  var e error

  //log.Println(ev)
  name := ev.Name

  //log.Println("getting parent path...")
  idx := -1
  path := ""
  for i := 0; i < RemoteCount; i++ {
    if strings.HasPrefix(name, Paths[i]) {
      idx = i
      path = Paths[i]
      break
    }
  }
  if idx == -1 {
    log.Println("couldnt find parent path")
    return
  }

  //log.Println("acquiring lock", idx)
  if !atomic.CompareAndSwapInt64(&Locks[idx], 0, 1) {
    //log.Println("failed to acquire lock", idx)
    return
  }
  log.Println("acquired lock", idx)

  log.Println("sleeping...")
  time.Sleep(5 * time.Second)

  checkoutPath := strings.Join([]string{"/var/eggd", path}, "/")
  e = os.MkdirAll(checkoutPath, 0755)
  if e != nil {
    log.Println("os.MkdirAll:", e)
    goto next
  }
  e = os.Chdir(checkoutPath)
  if e != nil {
    log.Println("os.Chdir:", e)
    goto next
  }
  if os.IsNotExist(os.Chdir(".git")) {
    log.Println("running git-clone...")
    cmd = exec.Command("git", "clone", path, ".")
    cmd.Stdout = &cmdStdout
    cmd.Stderr = &cmdStderr
    e = cmd.Run()
    if e != nil {
      log.Println("git-clone:", e)
      log.Println(cmdStdout.String())
      log.Println(cmdStderr.String())
      goto next
    }
  } else {
    os.Chdir("..")
  }

  log.Println("running git-pull...")
  cmd = exec.Command("git", "pull", "origin", "master")
  cmd.Stdout = &cmdStdout
  cmd.Stderr = &cmdStderr
  cmd.Run()
  if e != nil {
    log.Println("git-pull:", e)
    log.Println(cmdStdout.String())
    goto next
  }

  log.Println("sleeping...")
  time.Sleep(2 * time.Second)

  log.Println("running make...")
  cmd = exec.Command("make")
  cmd.Stdout = &cmdStdout
  e = cmd.Run()
  if e != nil {
    log.Println("make:", e)
    log.Println(cmdStdout.String())
    log.Println(cmdStderr.String())
    goto next
  }

  log.Println("sleeping...")
  time.Sleep(2 * time.Second)

  log.Println("running foreman...")
  cmd = exec.Command("foreman", "start")
  cmd.Stdout = &cmdStdout
  cmd.Stderr = &cmdStderr
  e = cmd.Run()
  if e != nil {
    log.Println("foreman:", e)
    log.Println(cmdStdout.String())
    log.Println(cmdStderr.String())
    goto next
  }

next:
  log.Println("releasing lock", idx)
  atomic.CompareAndSwapInt64(&Locks[idx], 1, 0)
  return
}

func initConfig() {
  // Check that the configfile exists.
  Home = os.Getenv("HOME")
  //ConfigName = strings.Join([]string{Home, ".eggconfig"}, "/")
  ConfigName = "/etc/eggconfig"
  fd, e := os.OpenFile(ConfigName, os.O_RDWR | os.O_CREATE, 0644)
  if e != nil { log.Fatal(e) }
  e = fd.Close()
  if e != nil { log.Fatal(e) }

  // Make sure the configfile is set up correctly.
  Config, e := conf.ReadConfigFile(ConfigName)
  if e != nil { log.Fatal(e) }
  Config.AddSection("global")
  if !Config.HasOption("global", "count") {
    Config.AddOption("global", "count", "0")
  }

  // Modify the configfile through cmdline args.
  if len(os.Args) > 2 && os.Args[1] == "add" {
    log.Println("adding", os.Args[2], "to eggd path")
    count, _ := Config.GetInt("global", "count")
    count = count + 1
    Config.AddOption("global", "count", strconv.Itoa(count))
    section := strings.Join([]string{"remote-", strconv.Itoa(count)}, "")
    Config.AddOption(section, "path", os.Args[2])
    Config.WriteConfigFile(ConfigName, 0644, "")
    os.Exit(0)
  }

  RemoteCount, e = Config.GetInt("global", "count")
  if e != nil { log.Fatal(e) }
  Config.WriteConfigFile(ConfigName, 0644, "")
}

func startWatcher() {
  // Start the event loops. Use inotify to watch the configfile and each
  // repository path.
  Config, e := conf.ReadConfigFile(ConfigName)
  if e != nil { log.Fatal(e) }
  watcher, e := inotify.NewWatcher()
  if e != nil { log.Fatal(e) }
  log.Println("watching configfile")
  e = watcher.Watch(ConfigName)
  if e != nil { log.Fatal(e) }
  Locks = make([]int64, RemoteCount)
  Paths = make([]string, RemoteCount)
  for i := 1; i <= RemoteCount; i++ {
    section := strings.Join([]string{"remote-", strconv.Itoa(i)}, "")
    if !Config.HasOption(section, "path") {
      log.Println("doesnt have path")
      continue
    }
    path, e := Config.GetRawString(section, "path")
    if e != nil { log.Fatal(e) }
    log.Println("watching path", path)
    e = watcher.Watch(path)
    if e != nil { log.Fatal(e) }
    Locks[i-1] = 0
    Paths[i-1] = path
  }
  for {
    select {
      case ev := <-watcher.Event:
        go handleEvent(ev)
      case err := <-watcher.Error:
        log.Println("error:", err)
    }
  }
}

func main() {
  initConfig()
  startWatcher()
}
<|endoftext|>


<commit_before>//Triggered when an extension changes its status.
package event

type ExtensionStatus struct {
	Privilege []string
	Extension string `AMI:"Exten"`
	Context   string `AMI:"Context"`
	Hint      string `AMI:"String"`
	Status    string `AMI:"String"`
}

func init() {
	eventTrap["ExtensionStatus"] = ExtensionStatus{}
}
<commit_msg>extensionStatus corr AMI<commit_after>//Triggered when an extension changes its status.
package event

type ExtensionStatus struct {
	Privilege []string
	Extension string `AMI:"Exten"`
	Context   string `AMI:"Context"`
	Hint      string `AMI:"Hint"`
	Status    string `AMI:"Status"`
}

func init() {
	eventTrap["ExtensionStatus"] = ExtensionStatus{}
}
<|endoftext|>


<commit_before>package events

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"sync"
	"time"
)

// LimitExceeded is returned when the number of simultaneous connections to
// Urban Airship's Event API is exceeded. The API responds with a 402 Payment
// Required status which is translated into this error.
var LimitExceeded = errors.New("request was rate limited")

// Event is the envelope for a single even from Urban Airship's event stream.
// Users should inspect the Event's Type and call the corresponding method to
// receive a typed event body.
type Event struct {
	// ID uniquely identifies the event.
	ID       string    `json:"id"`
	Type     Type      `json:"type"`
	Occurred time.Time `json:"occurred"`

	// Processed is when the event was ingested by Urban Airship. There may be
	// lag between when the event occurred, and when it was processed.
	Processed time.Time `json:"processed"`

	// Offset is the event's location in the stream. Used to resume the stream
	// after severing a connection. Clients should store this value for the case
	// that the connection is severed.
	Offset uint64 `json:"offset,string"`

	// Body is the raw event body. Use the Type specific methods to unmarshal the
	// body.
	Body   json.RawMessage `json:"body"`
	Device *Device         `json:"device,omitempty"`
}

type Push struct {
	// PushID is the unique identifier for the push, included in responses to the
	// push API.
	PushID string `json:"push_id"`

	// GroupID is an optional identifier of the group this push is associated
	// with; group IDs are created by both automation and push to local time.
	GroupID string `json:"group_id"`
}

type PushBody struct {
	Push

	// Payload is the specification of the push as sent via the API.
	Payload []byte `json:"payload"`
}

func (e *Event) PushBody() (*PushBody, error) {
	if e.Type != TypePush {
		return nil, WrongType
	}
	p := PushBody{}
	if err := json.Unmarshal(e.Body, &p); err != nil {
		return nil, err
	}
	return &p, nil
}

type Open struct {
	// LastDelivered contains the push identifier of the last notification Urban
	// Airship attempted to deliver to this device, if known. It may also include
	// a group identifier if the push was scheduled to the device’s local time or
	// if the push was an automation rule.
	//
	LastDelivered *Push `json:"last_delivered,omitempty"`

	// Triggering is present if the event was associated with a push. An
	// object containing the push ID of that notification. It may also include a
	// group ID if the push was a push to local time or automation rule.
	//
	TriggeringPush *Push `json:"triggering_push,omitempty"`

	// SessionID is an identifier for the "session" of user activity. This key
	// will be absent if the application was initialized while backgrounded.
	SessionID string `json:"session_id"`
}

// Open returns an Open struct for OPEN events. Non-OPEN events will return
// the WrongType error.
func (e *Event) Open() (*Open, error) {
	if e.Type != TypeOpen {
		return nil, WrongType
	}
	o := Open{}
	if err := json.Unmarshal(e.Body, &o); err != nil {
		return nil, err
	}
	return &o, nil
}

// Send events are emitted for each device identified by the audience selection
// of a push. device will be present in the event to specify which channel
// received the push.
type Send struct {
	Push
}

// Send returns a Send struct for SEND events. Non-SEND events will return the
// WrongType error.
func (e *Event) Send() (*Send, error) {
	if e.Type != TypeSend {
		return nil, WrongType
	}
	s := Send{}
	if err := json.Unmarshal(e.Body, &s); err != nil {
		return nil, err
	}
	return &s, nil
}

// Close events are emitted Each time a user closes the application. Note that
// close events are often latent, as they may not be delivered over the network
// until much later.
type Close struct {
	SessionID string `json:"session_id"`
}

func (e *Event) Close() (*Close, error) {
	if e.Type != TypeClose {
		return nil, WrongType
	}
	c := Close{}
	if err := json.Unmarshal(e.Body, &c); err != nil {
		return nil, err
	}
	return &c, nil
}

// TagChange events are emitted Each time a tag is added or removed from a
// channel.
type TagChange struct {
	// Add maps tag groups to tags. The set of tag group/tag pairs in this object
	// define the tags added to the device.
	Add map[string][]string `json:"add"`

	// Remove maps tag groups to tags. The set of tag group/tag pairs in this
	// object define the tags removed from the device.
	Remove map[string][]string `json:"remove"`

	// Current maps tag groups to tags. The set of tag group/tag pairs in this
	// object define the current state of the device AFTER the mutation has taken
	// effect.
	Current map[string][]string `json:"current"`
}

func (e *Event) TagChange() (*TagChange, error) {
	if e.Type != TypeTagChange {
		return nil, WrongType
	}
	t := TagChange{}
	if err := json.Unmarshal(e.Body, &t); err != nil {
		return nil, err
	}
	return &t, nil
}

// Location events include the latitude and longitude of the device.
type Location struct {
	Lat json.Number `json:"latitude"`
	Lon json.Number `json:"longitude"`

	// Foreground indicates whether the application was foregrounded when the
	// event fired.
	Foreground bool `json:"foreground"`
}

func (e *Event) Location() (*Location, error) {
	if e.Type != TypeLocation {
		return nil, WrongType
	}
	loc := Location{}
	if err := json.Unmarshal(e.Body, &loc); err != nil {
		return nil, err
	}
	return &loc, nil
}

type InAppMessageDisplay struct {
	Push

	// A triggering push is present if the user started the current session by opening
	// a push notification.
	TriggeringPush Push `json:"triggering_push"`
}

func (e *Event) InAppMessageDisplay() (*InAppMessageDisplay, error) {
	if e.Type != TypeInAppMessageDisplay {
		return nil, WrongType
	}
	disp := InAppMessageDisplay{}
	if err := json.Unmarshal(e.Body, &disp); err != nil {
		return nil, err
	}
	return &disp, nil
}

type InAppMessageResolution struct {
	InAppMessageDisplay

	TimeSent time.Time `json:"time_sent"`

	// Type indicates how the In-app message was resolved, and can take on one
	// of the following values: BUTTON_CLICK, MESSAGE_CLICK, TIMED_OUT, USER_DISMISSED
	Type string `json:"type"`

	// Duration is the amount of time for which the message was displayed, in milliseconds.
	Duration int64 `json:"duration"`

	// Additional optional fields describing the button that was clicked:
	ButtonID          string `json:"button_id,omitempty"`
	ButtonGroup       string `json:"button_group,omitempty"`
	ButtonDescription string `json:"button_description,omitempty"`
}

func (e *Event) InAppMessageResolution() (*InAppMessageResolution, error) {
	if e.Type != TypeInAppMessageResolution {
		return nil, WrongType
	}
	res := InAppMessageResolution{}
	if err := json.Unmarshal(e.Body, &res); err != nil {
		return nil, err
	}
	return &res, nil
}

type InAppMessageExpiration struct {
	InAppMessageResolution

	// ReplacingPush is present if Type is equal to REPLACED. It identifies
	// the push specification defining the In-App message which should replace the
	// current message.
	ReplacingPush Push `json:"replacing_push,omitempty"`
}

func (e *Event) InAppMessageExpiration() (*InAppMessageExpiration, error) {
	if e.Type != TypeInAppMessageExpiration {
		return nil, WrongType
	}
	exp := InAppMessageExpiration{}
	if err := json.Unmarshal(e.Body, &exp); err != nil {
		return nil, err
	}
	return &exp, nil
}

func (e *Event) RichEvent() (*Push, error) {
	if e.Type != TypeRichDelete && e.Type != TypeRichDelivery && e.Type != TypeRichRead {
		return nil, WrongType
	}
	p := Push{}
	if err := json.Unmarshal(e.Body, &p); err != nil {
		return nil, err
	}
	return &p, nil
}

// Response streams Events from a Fetch call.
type Response struct {
	// ID is the UA-Operation-Id header from Urban Airship's response.
	ID string

	out  chan *Event
	body io.ReadCloser

	mu     *sync.Mutex
	closed chan struct{}
	err    error
}

// NewResponse creates an events iterator from an http.Response. Fetch is a
// shortcut for creating a Response, but users can manually create a Response
// from a custom HTTP request with this function.
func NewResponse(resp *http.Response) (*Response, error) {
	if resp.StatusCode == 402 {
		return nil, LimitExceeded
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("unexpected non-200 response: %d", resp.StatusCode)
	}
	r := &Response{
		ID:     resp.Header.Get("UA-Operation-Id"),
		out:    make(chan *Event, 10), // provide some buffering
		body:   resp.Body,
		mu:     new(sync.Mutex),
		closed: make(chan struct{}),
	}
	go func() {
		// Always close Event chan to indicate to callers that response is done.
		defer close(r.out)
		dec := json.NewDecoder(r.body)
		for {
			var ev Event
			if err := dec.Decode(&ev); err != nil {
				select {
				case <-r.closed:
					//TODO Only ignore "closed" errors
					return
				default:
					r.mu.Lock()
					defer r.mu.Unlock()
					r.err = err
					return
				}
			}
			select {
			case r.out <- &ev:
			case <-r.closed:
				return
			}
		}
	}()
	return r, nil
}

// Events returns a chan that emits Events until closed. Events is safe for
// concurrent calls and shares an underlying chan. This means events are not
// duplicated between multiple receivers.
func (r *Response) Events() <-chan *Event { return r.out }

// Close the events stream. Safe to call concurrently.
func (r *Response) Close() {
	r.mu.Lock()
	defer r.mu.Unlock()
	select {
	case <-r.closed:
		return
	default:
		close(r.closed)
		r.body.Close()
	}
}

// Err returns the error which caused the event stream to end or nil. May be
// checked when the chan returned by Events() is closed. Safe for concurrent
// access.
func (r *Response) Err() error {
	r.mu.Lock()
	defer r.mu.Unlock()
	return r.err
}
<commit_msg>set variant_id to integer pointer<commit_after>package events

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"sync"
	"time"
)

// LimitExceeded is returned when the number of simultaneous connections to
// Urban Airship's Event API is exceeded. The API responds with a 402 Payment
// Required status which is translated into this error.
var LimitExceeded = errors.New("request was rate limited")

// Event is the envelope for a single even from Urban Airship's event stream.
// Users should inspect the Event's Type and call the corresponding method to
// receive a typed event body.
type Event struct {
	// ID uniquely identifies the event.
	ID       string    `json:"id"`
	Type     Type      `json:"type"`
	Occurred time.Time `json:"occurred"`

	// Processed is when the event was ingested by Urban Airship. There may be
	// lag between when the event occurred, and when it was processed.
	Processed time.Time `json:"processed"`

	// Offset is the event's location in the stream. Used to resume the stream
	// after severing a connection. Clients should store this value for the case
	// that the connection is severed.
	Offset uint64 `json:"offset,string"`

	// Body is the raw event body. Use the Type specific methods to unmarshal the
	// body.
	Body   json.RawMessage `json:"body"`
	Device *Device         `json:"device,omitempty"`
}

type Push struct {
	// PushID is the unique identifier for the push, included in responses to the
	// push API.
	PushID string `json:"push_id"`

	// GroupID is an optional identifier of the group this push is associated
	// with; group IDs are created by both automation and push to local time.
	GroupID string `json:"group_id"`
}

type PushBody struct {
	Push

	// Payload is the specification of the push as sent via the API.
	Payload []byte `json:"payload"`
}

func (e *Event) PushBody() (*PushBody, error) {
	if e.Type != TypePush {
		return nil, WrongType
	}
	p := PushBody{}
	if err := json.Unmarshal(e.Body, &p); err != nil {
		return nil, err
	}
	return &p, nil
}

type Open struct {
	// LastDelivered contains the push identifier of the last notification Urban
	// Airship attempted to deliver to this device, if known. It may also include
	// a group identifier if the push was scheduled to the device’s local time or
	// if the push was an automation rule.
	//
	LastDelivered *Push `json:"last_delivered,omitempty"`

	// Triggering is present if the event was associated with a push. An
	// object containing the push ID of that notification. It may also include a
	// group ID if the push was a push to local time or automation rule.
	//
	TriggeringPush *Push `json:"triggering_push,omitempty"`

	// SessionID is an identifier for the "session" of user activity. This key
	// will be absent if the application was initialized while backgrounded.
	SessionID string `json:"session_id"`
}

// Open returns an Open struct for OPEN events. Non-OPEN events will return
// the WrongType error.
func (e *Event) Open() (*Open, error) {
	if e.Type != TypeOpen {
		return nil, WrongType
	}
	o := Open{}
	if err := json.Unmarshal(e.Body, &o); err != nil {
		return nil, err
	}
	return &o, nil
}

// Send events are emitted for each device identified by the audience selection
// of a push. device will be present in the event to specify which channel
// received the push.
type Send struct {
	Push

	// VariantID is only present if the notification was sent as part of an
	// experiment.  Identifies the payload ultimately sent to a device.
	VariantID *int `json:"variant_id,omitempty"`
}

// Send returns a Send struct for SEND events. Non-SEND events will return the
// WrongType error.
func (e *Event) Send() (*Send, error) {
	if e.Type != TypeSend {
		return nil, WrongType
	}
	s := Send{}
	if err := json.Unmarshal(e.Body, &s); err != nil {
		return nil, err
	}
	return &s, nil
}

// Close events are emitted Each time a user closes the application. Note that
// close events are often latent, as they may not be delivered over the network
// until much later.
type Close struct {
	SessionID string `json:"session_id"`
}

func (e *Event) Close() (*Close, error) {
	if e.Type != TypeClose {
		return nil, WrongType
	}
	c := Close{}
	if err := json.Unmarshal(e.Body, &c); err != nil {
		return nil, err
	}
	return &c, nil
}

// TagChange events are emitted Each time a tag is added or removed from a
// channel.
type TagChange struct {
	// Add maps tag groups to tags. The set of tag group/tag pairs in this object
	// define the tags added to the device.
	Add map[string][]string `json:"add"`

	// Remove maps tag groups to tags. The set of tag group/tag pairs in this
	// object define the tags removed from the device.
	Remove map[string][]string `json:"remove"`

	// Current maps tag groups to tags. The set of tag group/tag pairs in this
	// object define the current state of the device AFTER the mutation has taken
	// effect.
	Current map[string][]string `json:"current"`
}

func (e *Event) TagChange() (*TagChange, error) {
	if e.Type != TypeTagChange {
		return nil, WrongType
	}
	t := TagChange{}
	if err := json.Unmarshal(e.Body, &t); err != nil {
		return nil, err
	}
	return &t, nil
}

// Location events include the latitude and longitude of the device.
type Location struct {
	Lat json.Number `json:"latitude"`
	Lon json.Number `json:"longitude"`

	// Foreground indicates whether the application was foregrounded when the
	// event fired.
	Foreground bool `json:"foreground"`
}

func (e *Event) Location() (*Location, error) {
	if e.Type != TypeLocation {
		return nil, WrongType
	}
	loc := Location{}
	if err := json.Unmarshal(e.Body, &loc); err != nil {
		return nil, err
	}
	return &loc, nil
}

type InAppMessageDisplay struct {
	Push

	// A triggering push is present if the user started the current session by opening
	// a push notification.
	TriggeringPush Push `json:"triggering_push"`
}

func (e *Event) InAppMessageDisplay() (*InAppMessageDisplay, error) {
	if e.Type != TypeInAppMessageDisplay {
		return nil, WrongType
	}
	disp := InAppMessageDisplay{}
	if err := json.Unmarshal(e.Body, &disp); err != nil {
		return nil, err
	}
	return &disp, nil
}

type InAppMessageResolution struct {
	InAppMessageDisplay

	TimeSent time.Time `json:"time_sent"`

	// Type indicates how the In-app message was resolved, and can take on one
	// of the following values: BUTTON_CLICK, MESSAGE_CLICK, TIMED_OUT, USER_DISMISSED
	Type string `json:"type"`

	// Duration is the amount of time for which the message was displayed, in milliseconds.
	Duration int64 `json:"duration"`

	// Additional optional fields describing the button that was clicked:
	ButtonID          string `json:"button_id,omitempty"`
	ButtonGroup       string `json:"button_group,omitempty"`
	ButtonDescription string `json:"button_description,omitempty"`
}

func (e *Event) InAppMessageResolution() (*InAppMessageResolution, error) {
	if e.Type != TypeInAppMessageResolution {
		return nil, WrongType
	}
	res := InAppMessageResolution{}
	if err := json.Unmarshal(e.Body, &res); err != nil {
		return nil, err
	}
	return &res, nil
}

type InAppMessageExpiration struct {
	InAppMessageResolution

	// ReplacingPush is present if Type is equal to REPLACED. It identifies
	// the push specification defining the In-App message which should replace the
	// current message.
	ReplacingPush Push `json:"replacing_push,omitempty"`
}

func (e *Event) InAppMessageExpiration() (*InAppMessageExpiration, error) {
	if e.Type != TypeInAppMessageExpiration {
		return nil, WrongType
	}
	exp := InAppMessageExpiration{}
	if err := json.Unmarshal(e.Body, &exp); err != nil {
		return nil, err
	}
	return &exp, nil
}

func (e *Event) RichEvent() (*Push, error) {
	if e.Type != TypeRichDelete && e.Type != TypeRichDelivery && e.Type != TypeRichRead {
		return nil, WrongType
	}
	p := Push{}
	if err := json.Unmarshal(e.Body, &p); err != nil {
		return nil, err
	}
	return &p, nil
}

// Response streams Events from a Fetch call.
type Response struct {
	// ID is the UA-Operation-Id header from Urban Airship's response.
	ID string

	out  chan *Event
	body io.ReadCloser

	mu     *sync.Mutex
	closed chan struct{}
	err    error
}

// NewResponse creates an events iterator from an http.Response. Fetch is a
// shortcut for creating a Response, but users can manually create a Response
// from a custom HTTP request with this function.
func NewResponse(resp *http.Response) (*Response, error) {
	if resp.StatusCode == 402 {
		return nil, LimitExceeded
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("unexpected non-200 response: %d", resp.StatusCode)
	}
	r := &Response{
		ID:     resp.Header.Get("UA-Operation-Id"),
		out:    make(chan *Event, 10), // provide some buffering
		body:   resp.Body,
		mu:     new(sync.Mutex),
		closed: make(chan struct{}),
	}
	go func() {
		// Always close Event chan to indicate to callers that response is done.
		defer close(r.out)
		dec := json.NewDecoder(r.body)
		for {
			var ev Event
			if err := dec.Decode(&ev); err != nil {
				select {
				case <-r.closed:
					//TODO Only ignore "closed" errors
					return
				default:
					r.mu.Lock()
					defer r.mu.Unlock()
					r.err = err
					return
				}
			}
			select {
			case r.out <- &ev:
			case <-r.closed:
				return
			}
		}
	}()
	return r, nil
}

// Events returns a chan that emits Events until closed. Events is safe for
// concurrent calls and shares an underlying chan. This means events are not
// duplicated between multiple receivers.
func (r *Response) Events() <-chan *Event { return r.out }

// Close the events stream. Safe to call concurrently.
func (r *Response) Close() {
	r.mu.Lock()
	defer r.mu.Unlock()
	select {
	case <-r.closed:
		return
	default:
		close(r.closed)
		r.body.Close()
	}
}

// Err returns the error which caused the event stream to end or nil. May be
// checked when the chan returned by Events() is closed. Safe for concurrent
// access.
func (r *Response) Err() error {
	r.mu.Lock()
	defer r.mu.Unlock()
	return r.err
}
<|endoftext|>


<commit_before>package events

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"sync"
	"time"
)

// LimitExceeded is returned when the number of simultaneous connections to
// Urban Airship's Event API is exceeded. The API responds with a 402 Payment
// Required status which is translated into this error.
var LimitExceeded = errors.New("request was rate limited")

// Event is the envelope for a single even from Urban Airship's event stream.
// Users should inspect the Event's Type and call the corresponding method to
// receive a typed event body.
type Event struct {
	// ID uniquely identifies the event.
	ID       string    `json:"id"`
	Type     Type      `json:"type"`
	Occurred time.Time `json:"occurred"`

	// Processed is when the event was ingested by Urban Airship. There may be
	// lag between when the event occurred, and when it was processed.
	Processed time.Time `json:"processed"`

	// Offset is the event's location in the stream. Used to resume the stream
	// after severing a connection. Clients should store this value for the case
	// that the connection is severed.
	Offset uint64 `json:"offset,string"`

	// Body is the raw event body. Use the Type specific methods to unmarshal the
	// body.
	Body   json.RawMessage `json:"body"`
	Device *Device         `json:"device,omitempty"`
}

type Push struct {
	// PushID is the unique identifier for the push, included in responses to the
	// push API.
	PushID string `json:"push_id"`

	// GroupID is an optional identifier of the group this push is associated
	// with; group IDs are created by both automation and push to local time.
	GroupID string `json:"group_id"`
}

type PushBody struct {
	Push

	// Payload is the specification of the push as sent via the API.
	Payload []byte `json:"payload"`
}

func (e *Event) PushBody() (*PushBody, error) {
	if e.Type != TypePush {
		return nil, WrongType
	}
	p := PushBody{}
	if err := json.Unmarshal(e.Body, &p); err != nil {
		return nil, err
	}
	return &p, nil
}

type Open struct {
	// LastReceived contains the push identifier of the last notification Urban
	// Airship attempted to deliver to this device, if known. It may also include
	// a group identifier if the push was scheduled to the device’s local time or
	// if the push was an automation rule.
	//
	//TODO sync with post-2015-05-27 docs
	LastReceived *Push `json:"last_push_received,omitempty"`

	// ConvertingPush is present if the event was associated with a push. An
	// object containing the push ID of that notification. It may also include a
	// group ID if the push was a push to local time or automation rule.
	//
	//TODO sync with post-2015-05-27 docs
	ConvertingPush *Push `json:"converting_push,omitempty"`

	// SessionID is an identifier for the "session" of user activity. This key
	// will be absent if the application was initialized while backgrounded.
	SessionID string `json:"session_id"`
}

// Open returns an Open struct for OPEN events. Non-OPEN events will return
// the WrongType error.
func (e *Event) Open() (*Open, error) {
	if e.Type != TypeOpen {
		return nil, WrongType
	}
	o := Open{}
	if err := json.Unmarshal(e.Body, &o); err != nil {
		return nil, err
	}
	return &o, nil
}

// Send events are emitted for each device identified by the audience selection
// of a push. device will be present in the event to specify which channel
// received the push.
type Send struct {
	Push

	// VariantID is only present if the notification was sent as part of an
	// experiment.  Identifies the payload ultimately sent to a device.
	VariantID string `json:"variant_id,omitempty"`
}

// Send returns a Send struct for SEND events. Non-SEND events will return the
// WrongType error.
func (e *Event) Send() (*Send, error) {
	if e.Type != TypeSend {
		return nil, WrongType
	}
	s := Send{}
	if err := json.Unmarshal(e.Body, &s); err != nil {
		return nil, err
	}
	return &s, nil
}

// Close events are emitted Each time a user closes the application. Note that
// close events are often latent, as they may not be delivered over the network
// until much later.
type Close struct {
	SessionID string `json:"session_id"`
}

func (e *Event) Close() (*Close, error) {
	if e.Type != TypeClose {
		return nil, WrongType
	}
	c := Close{}
	if err := json.Unmarshal(e.Body, &c); err != nil {
		return nil, err
	}
	return &c, nil
}

// TagChange events are emitted Each time a tag is added or removed from a
// channel.
type TagChange struct {
	// Add maps tag groups to tags. The set of tag group/tag pairs in this object
	// define the tags added to the device.
	Add map[string][]string `json:"add"`

	// Remove maps tag groups to tags. The set of tag group/tag pairs in this
	// object define the tags removed from the device.
	Remove map[string][]string `json:"remove"`

	// Current maps tag groups to tags. The set of tag group/tag pairs in this
	// object define the current state of the device AFTER the mutation has taken
	// effect.
	Current map[string][]string `json:"current"`
}

func (e *Event) TagChange() (*TagChange, error) {
	if e.Type != TypeTagChange {
		return nil, WrongType
	}
	t := TagChange{}
	if err := json.Unmarshal(e.Body, &t); err != nil {
		return nil, err
	}
	return &t, nil
}

// Location events include the latitude and longitude of the device.
type Location struct {
	Lat json.Number `json:"latitude"`
	Lon json.Number `json:"longitude"`

	// Foreground indicates whether the application was foregrounded when the
	// event fired.
	Foreground bool `json:"foreground"`
}

func (e *Event) Location() (*Location, error) {
	if e.Type != TypeLocation {
		return nil, WrongType
	}
	loc := Location{}
	if err := json.Unmarshal(e.Body, &loc); err != nil {
		return nil, err
	}
	return &loc, nil
}

// Response streams Events from a Fetch call.
type Response struct {
	// ID is the UA-Operation-Id header from Urban Airship's response.
	ID string

	out  chan *Event
	body io.ReadCloser

	mu     *sync.Mutex
	closed chan struct{}
	err    error
}

// NewResponse creates an events iterator from an http.Response. Fetch is a
// shortcut for creating a Response, but users can manually create a Response
// from a custom HTTP request with this function.
func NewResponse(resp *http.Response) (*Response, error) {
	if resp.StatusCode == 402 {
		return nil, LimitExceeded
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("unexpected non-200 response: %d", resp.StatusCode)
	}
	r := &Response{
		ID:     resp.Header.Get("UA-Operation-Id"),
		out:    make(chan *Event, 10), // provide some buffering
		body:   resp.Body,
		mu:     new(sync.Mutex),
		closed: make(chan struct{}),
	}
	go func() {
		dec := json.NewDecoder(r.body)
		for {
			var ev Event
			if err := dec.Decode(&ev); err != nil {
				select {
				case <-r.closed:
					return
				default:
					r.mu.Lock()
					defer r.mu.Unlock()
					r.err = err
					close(r.out)
					return
				}
			}
			select {
			case r.out <- &ev:
			case <-r.closed:
				return
			}
		}
	}()
	return r, nil
}

// Events returns a chan that emits Events until closed. Events is safe for
// concurrent calls and shares an underlying chan. This means events are not
// duplicated between multiple receivers.
func (r *Response) Events() <-chan *Event { return r.out }

// Close the events stream. Safe to call concurrently.
func (r *Response) Close() {
	r.mu.Lock()
	defer r.mu.Unlock()
	select {
	case <-r.closed:
		return
	default:
		close(r.closed)
		r.body.Close()
	}
}

// Err returns the error which caused the event stream to end or nil. May be
// checked when the chan returned by Events() is closed. Safe for concurrent
// access.
func (r *Response) Err() error {
	r.mu.Lock()
	defer r.mu.Unlock()
	return r.err
}
<commit_msg>comment for why it's safe to ignore errors<commit_after>package events

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"sync"
	"time"
)

// LimitExceeded is returned when the number of simultaneous connections to
// Urban Airship's Event API is exceeded. The API responds with a 402 Payment
// Required status which is translated into this error.
var LimitExceeded = errors.New("request was rate limited")

// Event is the envelope for a single even from Urban Airship's event stream.
// Users should inspect the Event's Type and call the corresponding method to
// receive a typed event body.
type Event struct {
	// ID uniquely identifies the event.
	ID       string    `json:"id"`
	Type     Type      `json:"type"`
	Occurred time.Time `json:"occurred"`

	// Processed is when the event was ingested by Urban Airship. There may be
	// lag between when the event occurred, and when it was processed.
	Processed time.Time `json:"processed"`

	// Offset is the event's location in the stream. Used to resume the stream
	// after severing a connection. Clients should store this value for the case
	// that the connection is severed.
	Offset uint64 `json:"offset,string"`

	// Body is the raw event body. Use the Type specific methods to unmarshal the
	// body.
	Body   json.RawMessage `json:"body"`
	Device *Device         `json:"device,omitempty"`
}

type Push struct {
	// PushID is the unique identifier for the push, included in responses to the
	// push API.
	PushID string `json:"push_id"`

	// GroupID is an optional identifier of the group this push is associated
	// with; group IDs are created by both automation and push to local time.
	GroupID string `json:"group_id"`
}

type PushBody struct {
	Push

	// Payload is the specification of the push as sent via the API.
	Payload []byte `json:"payload"`
}

func (e *Event) PushBody() (*PushBody, error) {
	if e.Type != TypePush {
		return nil, WrongType
	}
	p := PushBody{}
	if err := json.Unmarshal(e.Body, &p); err != nil {
		return nil, err
	}
	return &p, nil
}

type Open struct {
	// LastReceived contains the push identifier of the last notification Urban
	// Airship attempted to deliver to this device, if known. It may also include
	// a group identifier if the push was scheduled to the device’s local time or
	// if the push was an automation rule.
	//
	//TODO sync with post-2015-05-27 docs
	LastReceived *Push `json:"last_push_received,omitempty"`

	// ConvertingPush is present if the event was associated with a push. An
	// object containing the push ID of that notification. It may also include a
	// group ID if the push was a push to local time or automation rule.
	//
	//TODO sync with post-2015-05-27 docs
	ConvertingPush *Push `json:"converting_push,omitempty"`

	// SessionID is an identifier for the "session" of user activity. This key
	// will be absent if the application was initialized while backgrounded.
	SessionID string `json:"session_id"`
}

// Open returns an Open struct for OPEN events. Non-OPEN events will return
// the WrongType error.
func (e *Event) Open() (*Open, error) {
	if e.Type != TypeOpen {
		return nil, WrongType
	}
	o := Open{}
	if err := json.Unmarshal(e.Body, &o); err != nil {
		return nil, err
	}
	return &o, nil
}

// Send events are emitted for each device identified by the audience selection
// of a push. device will be present in the event to specify which channel
// received the push.
type Send struct {
	Push

	// VariantID is only present if the notification was sent as part of an
	// experiment.  Identifies the payload ultimately sent to a device.
	VariantID string `json:"variant_id,omitempty"`
}

// Send returns a Send struct for SEND events. Non-SEND events will return the
// WrongType error.
func (e *Event) Send() (*Send, error) {
	if e.Type != TypeSend {
		return nil, WrongType
	}
	s := Send{}
	if err := json.Unmarshal(e.Body, &s); err != nil {
		return nil, err
	}
	return &s, nil
}

// Close events are emitted Each time a user closes the application. Note that
// close events are often latent, as they may not be delivered over the network
// until much later.
type Close struct {
	SessionID string `json:"session_id"`
}

func (e *Event) Close() (*Close, error) {
	if e.Type != TypeClose {
		return nil, WrongType
	}
	c := Close{}
	if err := json.Unmarshal(e.Body, &c); err != nil {
		return nil, err
	}
	return &c, nil
}

// TagChange events are emitted Each time a tag is added or removed from a
// channel.
type TagChange struct {
	// Add maps tag groups to tags. The set of tag group/tag pairs in this object
	// define the tags added to the device.
	Add map[string][]string `json:"add"`

	// Remove maps tag groups to tags. The set of tag group/tag pairs in this
	// object define the tags removed from the device.
	Remove map[string][]string `json:"remove"`

	// Current maps tag groups to tags. The set of tag group/tag pairs in this
	// object define the current state of the device AFTER the mutation has taken
	// effect.
	Current map[string][]string `json:"current"`
}

func (e *Event) TagChange() (*TagChange, error) {
	if e.Type != TypeTagChange {
		return nil, WrongType
	}
	t := TagChange{}
	if err := json.Unmarshal(e.Body, &t); err != nil {
		return nil, err
	}
	return &t, nil
}

// Location events include the latitude and longitude of the device.
type Location struct {
	Lat json.Number `json:"latitude"`
	Lon json.Number `json:"longitude"`

	// Foreground indicates whether the application was foregrounded when the
	// event fired.
	Foreground bool `json:"foreground"`
}

func (e *Event) Location() (*Location, error) {
	if e.Type != TypeLocation {
		return nil, WrongType
	}
	loc := Location{}
	if err := json.Unmarshal(e.Body, &loc); err != nil {
		return nil, err
	}
	return &loc, nil
}

// Response streams Events from a Fetch call.
type Response struct {
	// ID is the UA-Operation-Id header from Urban Airship's response.
	ID string

	out  chan *Event
	body io.ReadCloser

	mu     *sync.Mutex
	closed chan struct{}
	err    error
}

// NewResponse creates an events iterator from an http.Response. Fetch is a
// shortcut for creating a Response, but users can manually create a Response
// from a custom HTTP request with this function.
func NewResponse(resp *http.Response) (*Response, error) {
	if resp.StatusCode == 402 {
		return nil, LimitExceeded
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("unexpected non-200 response: %d", resp.StatusCode)
	}
	r := &Response{
		ID:     resp.Header.Get("UA-Operation-Id"),
		out:    make(chan *Event, 10), // provide some buffering
		body:   resp.Body,
		mu:     new(sync.Mutex),
		closed: make(chan struct{}),
	}
	go func() {
		dec := json.NewDecoder(r.body)
		for {
			var ev Event
			if err := dec.Decode(&ev); err != nil {
				select {
				case <-r.closed:
					//TODO Only ignore "closed" errors
					return
				default:
					r.mu.Lock()
					defer r.mu.Unlock()
					r.err = err
					close(r.out)
					return
				}
			}
			select {
			case r.out <- &ev:
			case <-r.closed:
				return
			}
		}
	}()
	return r, nil
}

// Events returns a chan that emits Events until closed. Events is safe for
// concurrent calls and shares an underlying chan. This means events are not
// duplicated between multiple receivers.
func (r *Response) Events() <-chan *Event { return r.out }

// Close the events stream. Safe to call concurrently.
func (r *Response) Close() {
	r.mu.Lock()
	defer r.mu.Unlock()
	select {
	case <-r.closed:
		return
	default:
		close(r.closed)
		r.body.Close()
	}
}

// Err returns the error which caused the event stream to end or nil. May be
// checked when the chan returned by Events() is closed. Safe for concurrent
// access.
func (r *Response) Err() error {
	r.mu.Lock()
	defer r.mu.Unlock()
	return r.err
}
<|endoftext|>


<commit_before>// +build ccm

package gocql

import (
	"log"
	"testing"
	"time"

	"github.com/gocql/gocql/internal/ccm"
)

func TestEventDiscovery(t *testing.T) {
	if err := ccm.AllUp(); err != nil {
		t.Fatal(err)
	}

	session := createSession(t)
	defer session.Close()

	status, err := ccm.Status()
	if err != nil {
		t.Fatal(err)
	}
	t.Logf("status=%+v\n", status)

	session.pool.mu.RLock()
	poolHosts := session.pool.hostConnPools // TODO: replace with session.ring
	t.Logf("poolhosts=%+v\n", poolHosts)
	// check we discovered all the nodes in the ring
	for _, host := range status {
		if _, ok := poolHosts[host.Addr]; !ok {
			t.Errorf("did not discover %q", host.Addr)
		}
	}
	session.pool.mu.RUnlock()
	if t.Failed() {
		t.FailNow()
	}
}

func TestEventNodeDownControl(t *testing.T) {
	const targetNode = "node1"
	t.Log("marking " + targetNode + " as down")
	if err := ccm.AllUp(); err != nil {
		t.Fatal(err)
	}

	session := createSession(t)
	defer session.Close()

	if err := ccm.NodeDown(targetNode); err != nil {
		t.Fatal(err)
	}

	status, err := ccm.Status()
	if err != nil {
		t.Fatal(err)
	}
	t.Logf("status=%+v\n", status)
	t.Logf("marking node %q down: %v\n", targetNode, status[targetNode])

	time.Sleep(5 * time.Second)

	session.pool.mu.RLock()

	poolHosts := session.pool.hostConnPools
	node := status[targetNode]
	t.Logf("poolhosts=%+v\n", poolHosts)

	if _, ok := poolHosts[node.Addr]; ok {
		session.pool.mu.RUnlock()
		t.Fatal("node not removed after remove event")
	}
	session.pool.mu.RUnlock()

	host := session.ring.getHost(node.Addr)
	if host == nil {
		t.Fatal("node not in metadata ring")
	} else if host.IsUp() {
		t.Fatalf("not not marked as down after event in metadata: %v", host)
	}
}

func TestEventNodeDown(t *testing.T) {
	const targetNode = "node3"
	if err := ccm.AllUp(); err != nil {
		t.Fatal(err)
	}

	session := createSession(t)
	defer session.Close()

	if err := ccm.NodeDown(targetNode); err != nil {
		t.Fatal(err)
	}

	status, err := ccm.Status()
	if err != nil {
		t.Fatal(err)
	}
	t.Logf("status=%+v\n", status)
	t.Logf("marking node %q down: %v\n", targetNode, status[targetNode])

	time.Sleep(5 * time.Second)

	session.pool.mu.RLock()
	defer session.pool.mu.RUnlock()

	poolHosts := session.pool.hostConnPools
	node := status[targetNode]
	t.Logf("poolhosts=%+v\n", poolHosts)

	if _, ok := poolHosts[node.Addr]; ok {
		t.Fatal("node not removed after remove event")
	}

	host := session.ring.getHost(node.Addr)
	if host == nil {
		t.Fatal("node not in metadata ring")
	} else if host.IsUp() {
		t.Fatalf("not not marked as down after event in metadata: %v", host)
	}
}

func TestEventNodeUp(t *testing.T) {
	if err := ccm.AllUp(); err != nil {
		t.Fatal(err)
	}

	status, err := ccm.Status()
	if err != nil {
		t.Fatal(err)
	}
	log.Printf("status=%+v\n", status)

	session := createSession(t)
	defer session.Close()

	const targetNode = "node2"
	node := status[targetNode]

	_, ok := session.pool.getPool(node.Addr)
	if !ok {
		session.pool.mu.RLock()
		t.Errorf("target pool not in connection pool: addr=%q pools=%v", status[targetNode].Addr, session.pool.hostConnPools)
		session.pool.mu.RUnlock()
		t.FailNow()
	}

	if err := ccm.NodeDown(targetNode); err != nil {
		t.Fatal(err)
	}

	time.Sleep(5 * time.Second)

	_, ok = session.pool.getPool(node.Addr)
	if ok {
		t.Fatal("node not removed after remove event")
	}

	if err := ccm.NodeUp(targetNode); err != nil {
		t.Fatal(err)
	}

	// cassandra < 2.2 needs 10 seconds to start up the binary service
	time.Sleep(15 * time.Second)

	_, ok = session.pool.getPool(node.Addr)
	if !ok {
		t.Fatal("node not added after node added event")
	}

	host := session.ring.getHost(node.Addr)
	if host == nil {
		t.Fatal("node not in metadata ring")
	} else if !host.IsUp() {
		t.Fatalf("not not marked as UP after event in metadata: addr=%q host=%p: %v", node.Addr, host, host)
	}
}

func TestEventFilter(t *testing.T) {
	if err := ccm.AllUp(); err != nil {
		t.Fatal(err)
	}

	status, err := ccm.Status()
	if err != nil {
		t.Fatal(err)
	}
	log.Printf("status=%+v\n", status)

	cluster := createCluster()
	cluster.HostFilter = WhiteListHostFilter(status["node1"].Addr)
	session := createSessionFromCluster(cluster, t)
	defer session.Close()

	if _, ok := session.pool.getPool(status["node1"].Addr); !ok {
		t.Errorf("should have %v in pool but dont", "node1")
	}

	for _, host := range [...]string{"node2", "node3"} {
		_, ok := session.pool.getPool(status[host].Addr)
		if ok {
			t.Errorf("should not have %v in pool", host)
		}
	}

	if t.Failed() {
		t.FailNow()
	}

	if err := ccm.NodeDown("node2"); err != nil {
		t.Fatal(err)
	}

	time.Sleep(5 * time.Second)

	if err := ccm.NodeUp("node2"); err != nil {
		t.Fatal(err)
	}

	time.Sleep(15 * time.Second)
	for _, host := range [...]string{"node2", "node3"} {
		_, ok := session.pool.getPool(status[host].Addr)
		if ok {
			t.Errorf("should not have %v in pool", host)
		}
	}

	if t.Failed() {
		t.FailNow()
	}

}
<commit_msg>for the control down test only supply one host<commit_after>// +build ccm

package gocql

import (
	"log"
	"testing"
	"time"

	"github.com/gocql/gocql/internal/ccm"
)

func TestEventDiscovery(t *testing.T) {
	if err := ccm.AllUp(); err != nil {
		t.Fatal(err)
	}

	session := createSession(t)
	defer session.Close()

	status, err := ccm.Status()
	if err != nil {
		t.Fatal(err)
	}
	t.Logf("status=%+v\n", status)

	session.pool.mu.RLock()
	poolHosts := session.pool.hostConnPools // TODO: replace with session.ring
	t.Logf("poolhosts=%+v\n", poolHosts)
	// check we discovered all the nodes in the ring
	for _, host := range status {
		if _, ok := poolHosts[host.Addr]; !ok {
			t.Errorf("did not discover %q", host.Addr)
		}
	}
	session.pool.mu.RUnlock()
	if t.Failed() {
		t.FailNow()
	}
}

func TestEventNodeDownControl(t *testing.T) {
	const targetNode = "node1"
	if err := ccm.AllUp(); err != nil {
		t.Fatal(err)
	}

	status, err := ccm.Status()
	if err != nil {
		t.Fatal(err)
	}

	cluster := createCluster()
	cluster.Hosts = []string{status[targetNode].Addr}
	session := createSessionFromCluster(cluster, t)
	defer session.Close()

	t.Log("marking " + targetNode + " as down")
	if err := ccm.NodeDown(targetNode); err != nil {
		t.Fatal(err)
	}

	t.Logf("status=%+v\n", status)
	t.Logf("marking node %q down: %v\n", targetNode, status[targetNode])

	time.Sleep(5 * time.Second)

	session.pool.mu.RLock()

	poolHosts := session.pool.hostConnPools
	node := status[targetNode]
	t.Logf("poolhosts=%+v\n", poolHosts)

	if _, ok := poolHosts[node.Addr]; ok {
		session.pool.mu.RUnlock()
		t.Fatal("node not removed after remove event")
	}
	session.pool.mu.RUnlock()

	host := session.ring.getHost(node.Addr)
	if host == nil {
		t.Fatal("node not in metadata ring")
	} else if host.IsUp() {
		t.Fatalf("not not marked as down after event in metadata: %v", host)
	}
}

func TestEventNodeDown(t *testing.T) {
	const targetNode = "node3"
	if err := ccm.AllUp(); err != nil {
		t.Fatal(err)
	}

	session := createSession(t)
	defer session.Close()

	if err := ccm.NodeDown(targetNode); err != nil {
		t.Fatal(err)
	}

	status, err := ccm.Status()
	if err != nil {
		t.Fatal(err)
	}
	t.Logf("status=%+v\n", status)
	t.Logf("marking node %q down: %v\n", targetNode, status[targetNode])

	time.Sleep(5 * time.Second)

	session.pool.mu.RLock()
	defer session.pool.mu.RUnlock()

	poolHosts := session.pool.hostConnPools
	node := status[targetNode]
	t.Logf("poolhosts=%+v\n", poolHosts)

	if _, ok := poolHosts[node.Addr]; ok {
		t.Fatal("node not removed after remove event")
	}

	host := session.ring.getHost(node.Addr)
	if host == nil {
		t.Fatal("node not in metadata ring")
	} else if host.IsUp() {
		t.Fatalf("not not marked as down after event in metadata: %v", host)
	}
}

func TestEventNodeUp(t *testing.T) {
	if err := ccm.AllUp(); err != nil {
		t.Fatal(err)
	}

	status, err := ccm.Status()
	if err != nil {
		t.Fatal(err)
	}
	log.Printf("status=%+v\n", status)

	session := createSession(t)
	defer session.Close()

	const targetNode = "node2"
	node := status[targetNode]

	_, ok := session.pool.getPool(node.Addr)
	if !ok {
		session.pool.mu.RLock()
		t.Errorf("target pool not in connection pool: addr=%q pools=%v", status[targetNode].Addr, session.pool.hostConnPools)
		session.pool.mu.RUnlock()
		t.FailNow()
	}

	if err := ccm.NodeDown(targetNode); err != nil {
		t.Fatal(err)
	}

	time.Sleep(5 * time.Second)

	_, ok = session.pool.getPool(node.Addr)
	if ok {
		t.Fatal("node not removed after remove event")
	}

	if err := ccm.NodeUp(targetNode); err != nil {
		t.Fatal(err)
	}

	// cassandra < 2.2 needs 10 seconds to start up the binary service
	time.Sleep(15 * time.Second)

	_, ok = session.pool.getPool(node.Addr)
	if !ok {
		t.Fatal("node not added after node added event")
	}

	host := session.ring.getHost(node.Addr)
	if host == nil {
		t.Fatal("node not in metadata ring")
	} else if !host.IsUp() {
		t.Fatalf("not not marked as UP after event in metadata: addr=%q host=%p: %v", node.Addr, host, host)
	}
}

func TestEventFilter(t *testing.T) {
	if err := ccm.AllUp(); err != nil {
		t.Fatal(err)
	}

	status, err := ccm.Status()
	if err != nil {
		t.Fatal(err)
	}
	log.Printf("status=%+v\n", status)

	cluster := createCluster()
	cluster.HostFilter = WhiteListHostFilter(status["node1"].Addr)
	session := createSessionFromCluster(cluster, t)
	defer session.Close()

	if _, ok := session.pool.getPool(status["node1"].Addr); !ok {
		t.Errorf("should have %v in pool but dont", "node1")
	}

	for _, host := range [...]string{"node2", "node3"} {
		_, ok := session.pool.getPool(status[host].Addr)
		if ok {
			t.Errorf("should not have %v in pool", host)
		}
	}

	if t.Failed() {
		t.FailNow()
	}

	if err := ccm.NodeDown("node2"); err != nil {
		t.Fatal(err)
	}

	time.Sleep(5 * time.Second)

	if err := ccm.NodeUp("node2"); err != nil {
		t.Fatal(err)
	}

	time.Sleep(15 * time.Second)
	for _, host := range [...]string{"node2", "node3"} {
		_, ok := session.pool.getPool(status[host].Addr)
		if ok {
			t.Errorf("should not have %v in pool", host)
		}
	}

	if t.Failed() {
		t.FailNow()
	}

}
<|endoftext|>


<commit_before>// snippet-comment:[These are tags for the AWS doc team's sample catalog. Do not remove.]
// snippet-sourceauthor:[Doug-AWS]
// snippet-sourcedescription:[DynamoDBLoadItems.go adds items from a JSON file to an Amazon DynamoDB table.]
// snippet-keyword:[Amazon DynamoDB]
// snippet-keyword:[PutItem function]
// snippet-keyword:[Go]
// snippet-service:[dynamodb]
// snippet-keyword:[Code Sample]
// snippet-sourcetype:[full-example]
// snippet-sourcedate:[2019-03-19]
/*
   Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.

   This file is licensed under the Apache License, Version 2.0 (the "License").
   You may not use this file except in compliance with the License. A copy of
   the License is located at

    http://aws.amazon.com/apache2.0/

   This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied. See the License for the
   specific language governing permissions and limitations under the License.
*/
// snippet-start:[dynamodb.go.load_items]
package main

// snippet-start:[dynamodb.go.load_items.imports]
import (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/dynamodb"
    "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"

    "encoding/json"
    "fmt"
    "io/ioutil"
    "os"
    "strconv"
)
// snippet-end:[dynamodb.go.load_items.imports]

// snippet-start:[dynamodb.go.load_items.struct]
// Create struct to hold info about new item
type Item struct {
    Year   int
    Title  string
    Plot   string
    Rating float64
}
// snippet-end:[dynamodb.go.load_items.struct]

// snippet-start:[dynamodb.go.load_items.func]
// Get table items from JSON file
func getItems() []Item {
    raw, err := ioutil.ReadFile("./movie_data.json")
    if err != nil {
        fmt.Println(err.Error())
        os.Exit(1)
    }

    var items []Item
    json.Unmarshal(raw, &items)
    return items
}
// snippet-end:[dynamodb.go.load_items.func]

func main() {
    // snippet-start:[dynamodb.go.load_items.session]
    // Initialize a session that the SDK will use to load
    // credentials from the shared credentials file ~/.aws/credentials
    // and region from the shared configuration file ~/.aws/config.
    sess := session.Must(session.NewSessionWithOptions(session.Options{
        SharedConfigState: session.SharedConfigEnable,
    }))

    // Create DynamoDB client
    svc := dynamodb.New(sess)
    // snippet-end:[dynamodb.go.load_items.session]

    // snippet-start:[dynamodb.go.load_items.call]
    // Get table items from movie_data.json
    items := getItems()

    // Add each item to Movies table:
    tableName := "Movies"

    for _, item := range items {
        av, err := dynamodbattribute.MarshalMap(item)
        if err != nil {
            fmt.Println("Got error marshalling map:")
            fmt.Println(err.Error())
            os.Exit(1)
        }

        // Create item in table Movies
        input := &dynamodb.PutItemInput{
            Item:      av,
            TableName: aws.String(tableName),
        }

        _, err = svc.PutItem(input)
        if err != nil {
            fmt.Println("Got error calling PutItem:")
            fmt.Println(err.Error())
            os.Exit(1)
        }

        year := strconv.Itoa(item.Year)

        fmt.Println("Successfully added '" + item.Title + "' (" + year + ") to table " + tableName)
        // snippet-start:[dynamodb.go.load_items.call]
    }
}
// snippet-end:[dynamodb.go.load_items]
<commit_msg>Update DynamoDBLoadItems.go<commit_after>// snippet-comment:[These are tags for the AWS doc team's sample catalog. Do not remove.]
// snippet-sourceauthor:[Doug-AWS]
// snippet-sourcedescription:[DynamoDBLoadItems.go adds items from a JSON file to an Amazon DynamoDB table.]
// snippet-keyword:[Amazon DynamoDB]
// snippet-keyword:[PutItem function]
// snippet-keyword:[Go]
// snippet-service:[dynamodb]
// snippet-keyword:[Code Sample]
// snippet-sourcetype:[full-example]
// snippet-sourcedate:[2019-03-19]
/*
   Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.

   This file is licensed under the Apache License, Version 2.0 (the "License").
   You may not use this file except in compliance with the License. A copy of
   the License is located at

    http://aws.amazon.com/apache2.0/

   This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied. See the License for the
   specific language governing permissions and limitations under the License.
*/
// snippet-start:[dynamodb.go.load_items]
package main

// snippet-start:[dynamodb.go.load_items.imports]
import (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/dynamodb"
    "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"

    "encoding/json"
    "fmt"
    "io/ioutil"
    "os"
    "strconv"
)
// snippet-end:[dynamodb.go.load_items.imports]

// snippet-start:[dynamodb.go.load_items.struct]
// Create struct to hold info about new item
type Item struct {
    Year   int
    Title  string
    Plot   string
    Rating float64
}
// snippet-end:[dynamodb.go.load_items.struct]

// snippet-start:[dynamodb.go.load_items.func]
// Get table items from JSON file
func getItems() []Item {
    raw, err := ioutil.ReadFile("./movie_data.json")
    if err != nil {
        fmt.Println(err.Error())
        os.Exit(1)
    }

    var items []Item
    json.Unmarshal(raw, &items)
    return items
}
// snippet-end:[dynamodb.go.load_items.func]

func main() {
    // snippet-start:[dynamodb.go.load_items.session]
    // Initialize a session that the SDK will use to load
    // credentials from the shared credentials file ~/.aws/credentials
    // and region from the shared configuration file ~/.aws/config.
    sess := session.Must(session.NewSessionWithOptions(session.Options{
        SharedConfigState: session.SharedConfigEnable,
    }))

    // Create DynamoDB client
    svc := dynamodb.New(sess)
    // snippet-end:[dynamodb.go.load_items.session]

    // snippet-start:[dynamodb.go.load_items.call]
    // Get table items from movie_data.json
    items := getItems()

    // Add each item to Movies table:
    tableName := "Movies"

    for _, item := range items {
        av, err := dynamodbattribute.MarshalMap(item)
        if err != nil {
            fmt.Println("Got error marshalling map:")
            fmt.Println(err.Error())
            os.Exit(1)
        }

        // Create item in table Movies
        input := &dynamodb.PutItemInput{
            Item:      av,
            TableName: aws.String(tableName),
        }

        _, err = svc.PutItem(input)
        if err != nil {
            fmt.Println("Got error calling PutItem:")
            fmt.Println(err.Error())
            os.Exit(1)
        }

        year := strconv.Itoa(item.Year)

        fmt.Println("Successfully added '" + item.Title + "' (" + year + ") to table " + tableName)
        // snippet-end:[dynamodb.go.load_items.call]
    }
}
// snippet-end:[dynamodb.go.load_items]
<|endoftext|>