<commit_before>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package watch

import (
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"time"

	"github.com/davecgh/go-spew/spew"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/net"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/tools/cache"
	"k8s.io/klog/v2"
)

// resourceVersionGetter is an interface used to get resource version from events.
// We can't reuse an interface from meta otherwise it would be a cyclic dependency and we need just this one method
type resourceVersionGetter interface {
	GetResourceVersion() string
}

// RetryWatcher will make sure that in case the underlying watcher is closed (e.g. due to API timeout or etcd timeout)
// it will get restarted from the last point without the consumer even knowing about it.
// RetryWatcher does that by inspecting events and keeping track of resourceVersion.
// Especially useful when using watch.UntilWithoutRetry where premature termination is causing issues and flakes.
// Please note that this is not resilient to etcd cache not having the resource version anymore - you would need to
// use Informers for that.
type RetryWatcher struct {
	lastResourceVersion string
	watcherClient       cache.Watcher
	resultChan          chan watch.Event
	stopChan            chan struct{}
	doneChan            chan struct{}
	minRestartDelay     time.Duration
}

// NewRetryWatcher creates a new RetryWatcher.
// It will make sure that watches gets restarted in case of recoverable errors.
// The initialResourceVersion will be given to watch method when first called.
func NewRetryWatcher(initialResourceVersion string, watcherClient cache.Watcher) (*RetryWatcher, error) {
	return newRetryWatcher(initialResourceVersion, watcherClient, 1*time.Second)
}

func newRetryWatcher(initialResourceVersion string, watcherClient cache.Watcher, minRestartDelay time.Duration) (*RetryWatcher, error) {
	switch initialResourceVersion {
	case "", "0":
		// TODO: revisit this if we ever get WATCH v2 where it means start "now"
		//       without doing the synthetic list of objects at the beginning (see #74022)
		return nil, fmt.Errorf("initial RV %q is not supported due to issues with underlying WATCH", initialResourceVersion)
	default:
		break
	}

	rw := &RetryWatcher{
		lastResourceVersion: initialResourceVersion,
		watcherClient:       watcherClient,
		stopChan:            make(chan struct{}),
		doneChan:            make(chan struct{}),
		resultChan:          make(chan watch.Event, 0),
		minRestartDelay:     minRestartDelay,
	}

	go rw.receive()
	return rw, nil
}

func (rw *RetryWatcher) send(event watch.Event) bool {
	// Writing to an unbuffered channel is blocking operation
	// and we need to check if stop wasn't requested while doing so.
	select {
	case rw.resultChan <- event:
		return true
	case <-rw.stopChan:
		return false
	}
}

// doReceive returns true when it is done, false otherwise.
// If it is not done the second return value holds the time to wait before calling it again.
func (rw *RetryWatcher) doReceive() (bool, time.Duration) {
	watcher, err := rw.watcherClient.Watch(metav1.ListOptions{
		ResourceVersion:     rw.lastResourceVersion,
		AllowWatchBookmarks: true,
	})
	// We are very unlikely to hit EOF here since we are just establishing the call,
	// but it may happen that the apiserver is just shutting down (e.g. being restarted)
	// This is consistent with how it is handled for informers
	switch err {
	case nil:
		break

	case io.EOF:
		// watch closed normally
		return false, 0

	case io.ErrUnexpectedEOF:
		klog.V(1).InfoS("Watch closed with unexpected EOF", "err", err)
		return false, 0

	default:
		msg := "Watch failed"
		if net.IsProbableEOF(err) || net.IsTimeout(err) {
			klog.V(5).InfoS(msg, "err", err)
			// Retry
			return false, 0
		}

		klog.ErrorS(err, msg)
		// Retry
		return false, 0
	}

	if watcher == nil {
		klog.ErrorS(nil, "Watch returned nil watcher")
		// Retry
		return false, 0
	}

	ch := watcher.ResultChan()
	defer watcher.Stop()

	for {
		select {
		case <-rw.stopChan:
			klog.V(4).InfoS("Stopping RetryWatcher.")
			return true, 0
		case event, ok := <-ch:
			if !ok {
				klog.V(4).InfoS("Failed to get event! Re-creating the watcher.", "resourceVersion", rw.lastResourceVersion)
				return false, 0
			}

			// We need to inspect the event and get ResourceVersion out of it
			switch event.Type {
			case watch.Added, watch.Modified, watch.Deleted, watch.Bookmark:
				metaObject, ok := event.Object.(resourceVersionGetter)
				if !ok {
					_ = rw.send(watch.Event{
						Type:   watch.Error,
						Object: &apierrors.NewInternalError(errors.New("retryWatcher: doesn't support resourceVersion")).ErrStatus,
					})
					// We have to abort here because this might cause lastResourceVersion inconsistency by skipping a potential RV with valid data!
					return true, 0
				}

				resourceVersion := metaObject.GetResourceVersion()
				if resourceVersion == "" {
					_ = rw.send(watch.Event{
						Type:   watch.Error,
						Object: &apierrors.NewInternalError(fmt.Errorf("retryWatcher: object %#v doesn't support resourceVersion", event.Object)).ErrStatus,
					})
					// We have to abort here because this might cause lastResourceVersion inconsistency by skipping a potential RV with valid data!
					return true, 0
				}

				// All is fine; send the non-bookmark events and update resource version.
				if event.Type != watch.Bookmark {
					ok = rw.send(event)
					if !ok {
						return true, 0
					}
				}
				rw.lastResourceVersion = resourceVersion

				continue

			case watch.Error:
				// This round trip allows us to handle unstructured status
				errObject := apierrors.FromObject(event.Object)
				statusErr, ok := errObject.(*apierrors.StatusError)
				if !ok {
					klog.Error(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object))
					// Retry unknown errors
					return false, 0
				}

				status := statusErr.ErrStatus

				statusDelay := time.Duration(0)
				if status.Details != nil {
					statusDelay = time.Duration(status.Details.RetryAfterSeconds) * time.Second
				}

				switch status.Code {
				case http.StatusGone:
					// Never retry RV too old errors
					_ = rw.send(event)
					return true, 0

				case http.StatusGatewayTimeout, http.StatusInternalServerError:
					// Retry
					return false, statusDelay

				default:
					// We retry by default. RetryWatcher is meant to proceed unless it is certain
					// that it can't. If we are not certain, we proceed with retry and leave it
					// up to the user to timeout if needed.

					// Log here so we have a record of hitting the unexpected error
					// and we can whitelist some error codes if we missed any that are expected.
					klog.V(5).Info(spew.Sprintf("Retrying after unexpected error: %#+v", event.Object))

					// Retry
					return false, statusDelay
				}

			default:
				klog.Errorf("Failed to recognize Event type %q", event.Type)
				_ = rw.send(watch.Event{
					Type:   watch.Error,
					Object: &apierrors.NewInternalError(fmt.Errorf("retryWatcher failed to recognize Event type %q", event.Type)).ErrStatus,
				})
				// We are unable to restart the watch and have to stop the loop or this might cause lastResourceVersion inconsistency by skipping a potential RV with valid data!
				return true, 0
			}
		}
	}
}

// receive reads the result from a watcher, restarting it if necessary.
func (rw *RetryWatcher) receive() {
	defer close(rw.doneChan)
	defer close(rw.resultChan)

	klog.V(4).Info("Starting RetryWatcher.")
	defer klog.V(4).Info("Stopping RetryWatcher.")

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	go func() {
		select {
		case <-rw.stopChan:
			cancel()
			return
		case <-ctx.Done():
			return
		}
	}()

	// We use non sliding until so we don't introduce delays on happy path when WATCH call
	// timeouts or gets closed and we need to reestablish it while also avoiding hot loops.
	wait.NonSlidingUntilWithContext(ctx, func(ctx context.Context) {
		done, retryAfter := rw.doReceive()
		if done {
			cancel()
			return
		}

		time.Sleep(retryAfter)

		klog.V(4).Infof("Restarting RetryWatcher at RV=%q", rw.lastResourceVersion)
	}, rw.minRestartDelay)
}

// ResultChan implements Interface.
func (rw *RetryWatcher) ResultChan() <-chan watch.Event {
	return rw.resultChan
}

// Stop implements Interface.
func (rw *RetryWatcher) Stop() {
	close(rw.stopChan)
}

// Done allows the caller to be notified when Retry watcher stops.
func (rw *RetryWatcher) Done() <-chan struct{} {
	return rw.doneChan
}
<commit_msg>Make sleep interruptible<commit_after>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package watch

import (
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"time"

	"github.com/davecgh/go-spew/spew"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/net"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/tools/cache"
	"k8s.io/klog/v2"
)

// resourceVersionGetter is an interface used to get resource version from events.
// We can't reuse an interface from meta otherwise it would be a cyclic dependency and we need just this one method
type resourceVersionGetter interface {
	GetResourceVersion() string
}

// RetryWatcher will make sure that in case the underlying watcher is closed (e.g. due to API timeout or etcd timeout)
// it will get restarted from the last point without the consumer even knowing about it.
// RetryWatcher does that by inspecting events and keeping track of resourceVersion.
// Especially useful when using watch.UntilWithoutRetry where premature termination is causing issues and flakes.
// Please note that this is not resilient to etcd cache not having the resource version anymore - you would need to
// use Informers for that.
type RetryWatcher struct {
	lastResourceVersion string
	watcherClient       cache.Watcher
	resultChan          chan watch.Event
	stopChan            chan struct{}
	doneChan            chan struct{}
	minRestartDelay     time.Duration
}

// NewRetryWatcher creates a new RetryWatcher.
// It will make sure that watches gets restarted in case of recoverable errors.
// The initialResourceVersion will be given to watch method when first called.
func NewRetryWatcher(initialResourceVersion string, watcherClient cache.Watcher) (*RetryWatcher, error) {
	return newRetryWatcher(initialResourceVersion, watcherClient, 1*time.Second)
}

func newRetryWatcher(initialResourceVersion string, watcherClient cache.Watcher, minRestartDelay time.Duration) (*RetryWatcher, error) {
	switch initialResourceVersion {
	case "", "0":
		// TODO: revisit this if we ever get WATCH v2 where it means start "now"
		//       without doing the synthetic list of objects at the beginning (see #74022)
		return nil, fmt.Errorf("initial RV %q is not supported due to issues with underlying WATCH", initialResourceVersion)
	default:
		break
	}

	rw := &RetryWatcher{
		lastResourceVersion: initialResourceVersion,
		watcherClient:       watcherClient,
		stopChan:            make(chan struct{}),
		doneChan:            make(chan struct{}),
		resultChan:          make(chan watch.Event, 0),
		minRestartDelay:     minRestartDelay,
	}

	go rw.receive()
	return rw, nil
}

func (rw *RetryWatcher) send(event watch.Event) bool {
	// Writing to an unbuffered channel is blocking operation
	// and we need to check if stop wasn't requested while doing so.
	select {
	case rw.resultChan <- event:
		return true
	case <-rw.stopChan:
		return false
	}
}

// doReceive returns true when it is done, false otherwise.
// If it is not done the second return value holds the time to wait before calling it again.
func (rw *RetryWatcher) doReceive() (bool, time.Duration) {
	watcher, err := rw.watcherClient.Watch(metav1.ListOptions{
		ResourceVersion:     rw.lastResourceVersion,
		AllowWatchBookmarks: true,
	})
	// We are very unlikely to hit EOF here since we are just establishing the call,
	// but it may happen that the apiserver is just shutting down (e.g. being restarted)
	// This is consistent with how it is handled for informers
	switch err {
	case nil:
		break

	case io.EOF:
		// watch closed normally
		return false, 0

	case io.ErrUnexpectedEOF:
		klog.V(1).InfoS("Watch closed with unexpected EOF", "err", err)
		return false, 0

	default:
		msg := "Watch failed"
		if net.IsProbableEOF(err) || net.IsTimeout(err) {
			klog.V(5).InfoS(msg, "err", err)
			// Retry
			return false, 0
		}

		klog.ErrorS(err, msg)
		// Retry
		return false, 0
	}

	if watcher == nil {
		klog.ErrorS(nil, "Watch returned nil watcher")
		// Retry
		return false, 0
	}

	ch := watcher.ResultChan()
	defer watcher.Stop()

	for {
		select {
		case <-rw.stopChan:
			klog.V(4).InfoS("Stopping RetryWatcher.")
			return true, 0
		case event, ok := <-ch:
			if !ok {
				klog.V(4).InfoS("Failed to get event! Re-creating the watcher.", "resourceVersion", rw.lastResourceVersion)
				return false, 0
			}

			// We need to inspect the event and get ResourceVersion out of it
			switch event.Type {
			case watch.Added, watch.Modified, watch.Deleted, watch.Bookmark:
				metaObject, ok := event.Object.(resourceVersionGetter)
				if !ok {
					_ = rw.send(watch.Event{
						Type:   watch.Error,
						Object: &apierrors.NewInternalError(errors.New("retryWatcher: doesn't support resourceVersion")).ErrStatus,
					})
					// We have to abort here because this might cause lastResourceVersion inconsistency by skipping a potential RV with valid data!
					return true, 0
				}

				resourceVersion := metaObject.GetResourceVersion()
				if resourceVersion == "" {
					_ = rw.send(watch.Event{
						Type:   watch.Error,
						Object: &apierrors.NewInternalError(fmt.Errorf("retryWatcher: object %#v doesn't support resourceVersion", event.Object)).ErrStatus,
					})
					// We have to abort here because this might cause lastResourceVersion inconsistency by skipping a potential RV with valid data!
					return true, 0
				}

				// All is fine; send the non-bookmark events and update resource version.
				if event.Type != watch.Bookmark {
					ok = rw.send(event)
					if !ok {
						return true, 0
					}
				}
				rw.lastResourceVersion = resourceVersion

				continue

			case watch.Error:
				// This round trip allows us to handle unstructured status
				errObject := apierrors.FromObject(event.Object)
				statusErr, ok := errObject.(*apierrors.StatusError)
				if !ok {
					klog.Error(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object))
					// Retry unknown errors
					return false, 0
				}

				status := statusErr.ErrStatus

				statusDelay := time.Duration(0)
				if status.Details != nil {
					statusDelay = time.Duration(status.Details.RetryAfterSeconds) * time.Second
				}

				switch status.Code {
				case http.StatusGone:
					// Never retry RV too old errors
					_ = rw.send(event)
					return true, 0

				case http.StatusGatewayTimeout, http.StatusInternalServerError:
					// Retry
					return false, statusDelay

				default:
					// We retry by default. RetryWatcher is meant to proceed unless it is certain
					// that it can't. If we are not certain, we proceed with retry and leave it
					// up to the user to timeout if needed.

					// Log here so we have a record of hitting the unexpected error
					// and we can whitelist some error codes if we missed any that are expected.
					klog.V(5).Info(spew.Sprintf("Retrying after unexpected error: %#+v", event.Object))

					// Retry
					return false, statusDelay
				}

			default:
				klog.Errorf("Failed to recognize Event type %q", event.Type)
				_ = rw.send(watch.Event{
					Type:   watch.Error,
					Object: &apierrors.NewInternalError(fmt.Errorf("retryWatcher failed to recognize Event type %q", event.Type)).ErrStatus,
				})
				// We are unable to restart the watch and have to stop the loop or this might cause lastResourceVersion inconsistency by skipping a potential RV with valid data!
				return true, 0
			}
		}
	}
}

// receive reads the result from a watcher, restarting it if necessary.
func (rw *RetryWatcher) receive() {
	defer close(rw.doneChan)
	defer close(rw.resultChan)

	klog.V(4).Info("Starting RetryWatcher.")
	defer klog.V(4).Info("Stopping RetryWatcher.")

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	go func() {
		select {
		case <-rw.stopChan:
			cancel()
			return
		case <-ctx.Done():
			return
		}
	}()

	// We use non sliding until so we don't introduce delays on happy path when WATCH call
	// timeouts or gets closed and we need to reestablish it while also avoiding hot loops.
	wait.NonSlidingUntilWithContext(ctx, func(ctx context.Context) {
		done, retryAfter := rw.doReceive()
		if done {
			cancel()
			return
		}

		timer := time.NewTimer(retryAfter)
		select {
		case <-ctx.Done():
			timer.Stop()
			return
		case <-timer.C:
		}

		klog.V(4).Infof("Restarting RetryWatcher at RV=%q", rw.lastResourceVersion)
	}, rw.minRestartDelay)
}

// ResultChan implements Interface.
func (rw *RetryWatcher) ResultChan() <-chan watch.Event {
	return rw.resultChan
}

// Stop implements Interface.
func (rw *RetryWatcher) Stop() {
	close(rw.stopChan)
}

// Done allows the caller to be notified when Retry watcher stops.
func (rw *RetryWatcher) Done() <-chan struct{} {
	return rw.doneChan
}
<|endoftext|>


<commit_before>/*
 * Inflector Pkg (Go)
 *
 * Copyright (c) 2013 Ivan Torres
 * Released under the MIT license
 * https://github.com/mexpolk/inflector/blob/master/LICENSE
 *
 */

package inflector

import (
	"testing"
)

type inflectionSample struct {
	str, out string
}

func TestToCamel(t *testing.T) {
	samples := []inflectionSample{
		{"sample text", "sampleText"},
		{"sample-text", "sampleText"},
		{"sample_text", "sampleText"},
		{"sampleText", "sampleText"},
		{"sample 2 Text", "sample2Text"},
	}

	for _, sample := range samples {
		if out := ToCamel(sample.str); out != sample.out {
			t.Errorf("got %q, expected %q", out, sample.out)
		}
	}
}

func TestToDash(t *testing.T) {
	samples := []inflectionSample{
		{"sample text", "sample-text"},
		{"sample-text", "sample-text"},
		{"sample_text", "sample-text"},
		{"sampleText", "sample-text"},
		{"sample 2 Text", "sample-2-text"},
	}

	for _, sample := range samples {
		if out := ToDash(sample.str); out != sample.out {
			t.Errorf("got %q, expected %q", out, sample.out)
		}
	}
}

func TestToPascal(t *testing.T) {
	samples := []inflectionSample{
		{"sample text", "SampleText"},
		{"sample-text", "SampleText"},
		{"sample_text", "SampleText"},
		{"sampleText", "SampleText"},
		{"sample 2 Text", "Sample2Text"},
	}

	for _, sample := range samples {
		if out := ToPascal(sample.str); out != sample.out {
			t.Errorf("got %q, expected %q", out, sample.out)
		}
	}
}

func TestToUnderscore(t *testing.T) {
	samples := []inflectionSample{
		{"sample text", "sample_text"},
		{"sample-text", "sample_text"},
		{"sample_text", "sample_text"},
		{"sampleText", "sample_text"},
		{"sample 2 Text", "sample_2_text"},
		{"SAMPLE 2 TEXT", "sample_2_text"},
		{"Base64Encode", "base64_encode"},
	}

	for _, sample := range samples {
		if out := ToUnderscore(sample.str); out != sample.out {
			t.Errorf("got %q, expected %q", out, sample.out)
		}
	}
}
<commit_msg>add dot test<commit_after>/*
 * Inflector Pkg (Go)
 *
 * Copyright (c) 2013 Ivan Torres
 * Released under the MIT license
 * https://github.com/mexpolk/inflector/blob/master/LICENSE
 *
 */

package inflector

import (
	"testing"
)

type inflectionSample struct {
	str, out string
}

func TestToCamel(t *testing.T) {
	samples := []inflectionSample{
		{"sample text", "sampleText"},
		{"sample-text", "sampleText"},
		{"sample_text", "sampleText"},
		{"sampleText", "sampleText"},
		{"sample 2 Text", "sample2Text"},
	}

	for _, sample := range samples {
		if out := ToCamel(sample.str); out != sample.out {
			t.Errorf("got %q, expected %q", out, sample.out)
		}
	}
}

func TestToDash(t *testing.T) {
	samples := []inflectionSample{
		{"sample text", "sample-text"},
		{"sample-text", "sample-text"},
		{"sample_text", "sample-text"},
		{"sampleText", "sample-text"},
		{"sample 2 Text", "sample-2-text"},
	}

	for _, sample := range samples {
		if out := ToDash(sample.str); out != sample.out {
			t.Errorf("got %q, expected %q", out, sample.out)
		}
	}
}

func TestToPascal(t *testing.T) {
	samples := []inflectionSample{
		{"sample text", "SampleText"},
		{"sample-text", "SampleText"},
		{"sample_text", "SampleText"},
		{"sampleText", "SampleText"},
		{"sample 2 Text", "Sample2Text"},
	}

	for _, sample := range samples {
		if out := ToPascal(sample.str); out != sample.out {
			t.Errorf("got %q, expected %q", out, sample.out)
		}
	}
}

func TestToUnderscore(t *testing.T) {
	samples := []inflectionSample{
		{"sample text", "sample_text"},
		{"sample-text", "sample_text"},
		{"sample_text", "sample_text"},
		{"sampleText", "sample_text"},
		{"sample 2 Text", "sample_2_text"},
		{"SAMPLE 2 TEXT", "sample_2_text"},
		{"Base64Encode", "base64_encode"},
		{"something.com", "something_com"},
	}

	for _, sample := range samples {
		if out := ToUnderscore(sample.str); out != sample.out {
			t.Errorf("got %q, expected %q", out, sample.out)
		}
	}
}
<|endoftext|>


<commit_before>package glimmer

import (
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

var (
	conn *websocket.Conn

	delay     int
	delayLock sync.RWMutex
)

func init() {
	upgrader := websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
	}

	var err error

	conn, err = upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}
}

func handler(w http.ResponseWriter, r *http.Request) {
	for {
		messageType, p, err := conn.ReadMessage()
		if err != nil {
			return
		}
		if err = conn.WriteMessage(messageType, p); err != nil {
			return err
		}
	}
}

func ProcessRecieve(ch, value interface{}) {
	fmt.Println("recieve", &ch, &value)
}

func ProcessSend(ch, value interface{}) {
	fmt.Println("send", &ch, &value)
}

func Sleep() {
	delayLock.RLock()
	amount := delay
	delayLock.RUnlock()

	time.Sleep(amount * time.Millisecond)
}
<commit_msg>Some work for the runtime to be able to write message events on a websocket<commit_after>package glimmer

import (
	"fmt"
	"log"
	"net/http"
	"runtime"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

type MessageEvent struct {
	Func  string
	Type  bool // true is recieving, false is sending
	Chan  string
	Value string
}

var (
	forSendingQueue chan *MessageEvent

	delay     int = 1000
	delayLock sync.RWMutex
)

func init() {
	// 1024 seems a reasonable buffer size for this
	// TODO: consider using the channels with infinite buffers
	// from https://github.com/eapache/channels
	forSendingQueue = make(chan *MessageEvent, 1024)
}

func handler(w http.ResponseWriter, r *http.Request) {
	upgrader := websocket.Upgrader{}
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Error(err)
		return
	}
	defer conn.Close()

	for {
		select {
		// TODO: read
		// write message events to the websocket
		case m := <-forSendingQueue:
			if err := conn.WriteJSON(<-forSendingQueue); err != nil {
				log.Error(err)
				return
			}
		}
	}
}

func ProcessRecieve(ch, value interface{}) {
	// get the caller of the caller of this function
	// we get two levels below the current because
	// this function is being called by the function literal
	// that substitutes the recieve expression
	programCounter, _, _, ok := runtime.Caller(2)
	if !ok {
		panic("Can't read the stack trace to find who called the ProcessRecieve function. Have no idea how to handle this.")
	}

	caller := runtime.FuncForPC(programCounter)
	fmt.Println("Recieve called from", caller.Name())

	sendMessageEvent(caller.Name(), fmt.Sprintf("%d", &ch), fmt.Sprintf("%d", &value), true)
}

func ProcessSend(ch, value interface{}) {
	// get the caller of the caller of this function
	// we get two levels below the current because
	// this function is being called by the function literal
	// that substitutes the recieve expression
	programCounter, _, _, ok := runtime.Caller(2)
	if !ok {
		panic("Can't read the stack trace to find who called the ProcessRecieve function. Have no idea how to handle this.")
	}

	caller := runtime.FuncForPC(programCounter)
	fmt.Println("Send called from", caller.Name())

	sendMessageEvent(caller.Name(), fmt.Sprintf("%d", &ch), fmt.Sprintf("%d", &value), false)
}

func sendMessageEvent(funcName, ch, value string, eventType bool) {
	messageEvent := &MessageEvent{
		Func:  funcName,
		Type:  eventType,
		Chan:  ch,
		Value: value,
	}

	forSendingQueue <- messageEvent
}

func Sleep() {
	delayLock.RLock()
	amount := delay
	delayLock.RUnlock()

	time.Sleep(time.Duration(amount) * time.Millisecond)
}
<|endoftext|>


<commit_before>package sudoku

import (
	"fmt"
	"strconv"
)

// Field is a sudoku field
type Field struct {
	Index     int
	Value     int
	NonValues *IntSet
	sudoku    *Sudoku
}

// NewField creates a new Field
func NewField(sudoku *Sudoku, index, value int) Field {
	f := Field{
		sudoku:    sudoku,
		Index:     index,
		Value:     value,
		NonValues: NewIntSet(),
	}
	return f
}

// DenyValue denies a value
func (f *Field) DenyValue(value int) {
	f.NonValues.Add(value)
}

// Solve solves this Field
func (f *Field) Solve() bool {
	// if newly solved, return true
	if len(f.NonValues.set) != f.sudoku.MaxValue-1 {
		return false
	}
	for i := 1; i <= f.sudoku.MaxValue; i++ {
		if !f.NonValues.Contains(i) {
			f.sudoku.addSolution(f, i)
			break
		}
	}
	return true
}

// IsSolved checks if the Field is solved
func (f Field) IsSolved() bool {
	return f.Value != 0
}

// Solvable checks if the Field can be solved (all other values excluded)
func (f Field) Solvable() bool {
	return false
}

// String returns a human-friendly value
func (f Field) String() string {
	if f.Value == 0 {
		return "."
	}
	fieldLengthString := strconv.Itoa(f.sudoku.FieldLength)
	return fmt.Sprintf("%"+fieldLengthString+"d", f.Value)
}
<commit_msg>Add PossibleValues method to Field<commit_after>package sudoku

import (
	"fmt"
	"strconv"
)

// Field is a sudoku field
type Field struct {
	Index     int
	Value     int
	NonValues *IntSet
	sudoku    *Sudoku
}

// NewField creates a new Field
func NewField(sudoku *Sudoku, index, value int) Field {
	f := Field{
		sudoku:    sudoku,
		Index:     index,
		Value:     value,
		NonValues: NewIntSet(),
	}
	return f
}

// DenyValue denies a value
func (f *Field) DenyValue(value int) {
	f.NonValues.Add(value)
}

// Solve solves this Field
func (f *Field) Solve() bool {
	// if newly solved, return true
	if len(f.NonValues.set) != f.sudoku.MaxValue-1 {
		return false
	}
	for i := 1; i <= f.sudoku.MaxValue; i++ {
		if !f.NonValues.Contains(i) {
			f.sudoku.addSolution(f, i)
			break
		}
	}
	return true
}

// IsSolved checks if the Field is solved
func (f Field) IsSolved() bool {
	return f.Value != 0
}

// Solvable checks if the Field can be solved (all other values excluded)
func (f Field) Solvable() bool {
	// TODO implement
	return false
}

// PossibleValues returns the list of possible values for this field
func (f Field) PossibleValues() []int {
	result := make([]int, 0)
	for p := 1; p <= f.sudoku.MaxValue; p++ {
		if f.NonValues.Contains(p) {
			continue
		}
		result = append(result, p)
	}
	return result
}

// String returns a human-friendly value
func (f Field) String() string {
	if f.Value == 0 {
		return "."
	}
	fieldLengthString := strconv.Itoa(f.sudoku.FieldLength)
	return fmt.Sprintf("%"+fieldLengthString+"d", f.Value)
}
<|endoftext|>


<commit_before>// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

package revel

import (
	"reflect"
	"strings"
)

// Field represents a data field that may be collected in a web form.
type Field struct {
	Name       string
	Error      *ValidationError
	viewArgs   map[string]interface{}
	controller *Controller
}

func NewField(name string, viewArgs map[string]interface{}) *Field {
	err, _ := viewArgs["errors"].(map[string]*ValidationError)[name]
	controller, _ := viewArgs["_controller"].(*Controller)
	return &Field{
		Name:       name,
		Error:      err,
		viewArgs:   viewArgs,
		controller: controller,
	}
}

// ID returns an identifier suitable for use as an HTML id.
func (f *Field) ID() string {
	return strings.Replace(f.Name, ".", "_", -1)
}

// Flash returns the flashed value of this Field.
func (f *Field) Flash() string {
	v, _ := f.viewArgs["flash"].(map[string]string)[f.Name]
	return v
}

// FlashArray returns the flashed value of this Field as a list split on comma.
func (f *Field) FlashArray() []string {
	v := f.Flash()
	if v == "" {
		return []string{}
	}
	return strings.Split(v, ",")
}

func readNext(nextKey string) (string, string) {
	switch nextKey[0] {
	case '[':
		idx := strings.IndexRune(nextKey, ']')
		if idx < 0 {
			return nextKey[1:], ""
		} else {
			return nextKey[1:idx], nextKey[idx+1:]
		}
	case '.':
		nextKey = nextKey[1:]
		fallthrough
	default:
		idx := strings.IndexAny(nextKey, ".[")
		if idx < 0 {
			return nextKey, ""
		} else if nextKey[idx] == '.' {
			return nextKey[:idx], nextKey[idx+1:]
		} else {
			return nextKey[:idx], nextKey[idx:]
		}
	}
}

// Value returns the current value of this Field.
func (f *Field) Value() interface{} {
	var fieldName string

	var nextKey = f.Name
	var val interface{} = f.viewArgs
	for nextKey != "" {
		fieldName, nextKey = readNext(nextKey)

		rVal := reflect.ValueOf(val)
		kind := rVal.Kind()
		if kind == reflect.Map {
			rFieldName := reflect.ValueOf(fieldName)
			rVal = rVal.MapIndex(rFieldName)
			if !rVal.IsValid() {
				return nil
			}

			val = rVal.Interface()
			if val == nil {
				return nil
			}
			continue
		}

		if kind == reflect.Ptr {
			rVal = rVal.Elem()
		}
		rVal = rVal.FieldByName(fieldName)
		if !rVal.IsValid() {
			return nil
		}
		val = rVal.Interface()
		if val == nil {
			return nil
		}
	}

	return val
}

// ErrorClass returns ErrorCSSClass if this field has a validation error, else empty string.
func (f *Field) ErrorClass() string {
	if f.Error != nil {
		if errorClass, ok := f.viewArgs["ERROR_CLASS"]; ok {
			return errorClass.(string)
		}
		return ErrorCSSClass
	}
	return ""
}

// Get the short name and translate it
func (f *Field) ShortName() string {
	name := f.Name
	if i := strings.LastIndex(name, "."); i > 0 {
		name = name[i+1:]
	}
	return f.Translate(name)
}

// Translate the text
func (f *Field) Translate(text string, args ...interface{}) string {
	if f.controller != nil {
		text = f.controller.Message(text, args...)
	}
	return text
}
<commit_msg>fix MapIndex panic<commit_after>// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

package revel

import (
	"reflect"
	"strconv"
	"strings"
)

// Field represents a data field that may be collected in a web form.
type Field struct {
	Name       string
	Error      *ValidationError
	viewArgs   map[string]interface{}
	controller *Controller
}

func NewField(name string, viewArgs map[string]interface{}) *Field {
	err, _ := viewArgs["errors"].(map[string]*ValidationError)[name]
	controller, _ := viewArgs["_controller"].(*Controller)
	return &Field{
		Name:       name,
		Error:      err,
		viewArgs:   viewArgs,
		controller: controller,
	}
}

// ID returns an identifier suitable for use as an HTML id.
func (f *Field) ID() string {
	return strings.Replace(f.Name, ".", "_", -1)
}

// Flash returns the flashed value of this Field.
func (f *Field) Flash() string {
	v, _ := f.viewArgs["flash"].(map[string]string)[f.Name]
	return v
}

// FlashArray returns the flashed value of this Field as a list split on comma.
func (f *Field) FlashArray() []string {
	v := f.Flash()
	if v == "" {
		return []string{}
	}
	return strings.Split(v, ",")
}

func readNext(nextKey string) (string, string) {
	switch nextKey[0] {
	case '[':
		idx := strings.IndexRune(nextKey, ']')
		if idx < 0 {
			return nextKey[1:], ""
		} else {
			return nextKey[1:idx], nextKey[idx+1:]
		}
	case '.':
		nextKey = nextKey[1:]
		fallthrough
	default:
		idx := strings.IndexAny(nextKey, ".[")
		if idx < 0 {
			return nextKey, ""
		} else if nextKey[idx] == '.' {
			return nextKey[:idx], nextKey[idx+1:]
		} else {
			return nextKey[:idx], nextKey[idx:]
		}
	}
}

// Value returns the current value of this Field.
func (f *Field) Value() interface{} {
	var fieldName string

	var nextKey = f.Name
	var val interface{} = f.viewArgs
	for nextKey != "" {
		fieldName, nextKey = readNext(nextKey)

		rVal := reflect.ValueOf(val)
		kind := rVal.Kind()
		if kind == reflect.Map {

			rFieldName := reflect.ValueOf(fieldName)

			keyKind := rVal.Type().Key().Kind()
			if keyKind != reflect.String {
				switch keyKind {
				case reflect.Int64:
					i64, err := strconv.ParseInt(fieldName, 10, 64)
					if err != nil {
						panic(err)
					}
					rFieldName = reflect.ValueOf(i64)
				case reflect.Int:
					i64, err := strconv.Atoi(fieldName)
					if err != nil {
						panic(err)
					}
					rFieldName = reflect.ValueOf(i64)
				}
			}

			rVal = rVal.MapIndex(rFieldName)
			if !rVal.IsValid() {
				return nil
			}

			val = rVal.Interface()
			if val == nil {
				return nil
			}
			continue
		}

		if kind == reflect.Ptr {
			rVal = rVal.Elem()
		}
		rVal = rVal.FieldByName(fieldName)
		if !rVal.IsValid() {
			return nil
		}
		val = rVal.Interface()
		if val == nil {
			return nil
		}
	}

	return val
}

// ErrorClass returns ErrorCSSClass if this field has a validation error, else empty string.
func (f *Field) ErrorClass() string {
	if f.Error != nil {
		if errorClass, ok := f.viewArgs["ERROR_CLASS"]; ok {
			return errorClass.(string)
		}
		return ErrorCSSClass
	}
	return ""
}

// Get the short name and translate it
func (f *Field) ShortName() string {
	name := f.Name
	if i := strings.LastIndex(name, "."); i > 0 {
		name = name[i+1:]
	}
	return f.Translate(name)
}

// Translate the text
func (f *Field) Translate(text string, args ...interface{}) string {
	if f.controller != nil {
		text = f.controller.Message(text, args...)
	}
	return text
}
<|endoftext|>


<commit_before>// Copyright ©2014 The bíogo Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package internal provides shared code for BAI and tabix index implementations.
package internal

import (
	"errors"
	"sort"

	"github.com/biogo/hts/bgzf"
	"github.com/biogo/hts/bgzf/index"
)

const (
	// TileWidth is the length of the interval tiling used
	// in BAI and tabix indexes.
	TileWidth = 0x4000

	// StatsDummyBin is the bin number of the reference
	// statistics bin used in BAI and tabix indexes.
	StatsDummyBin = 0x924a
)

// Index is a coordinate based index.
type Index struct {
	Refs       []RefIndex
	Unmapped   *uint64
	IsSorted   bool
	LastRecord int
}

// RefIndex is the index of a single reference.
type RefIndex struct {
	Bins      []Bin
	Stats     *ReferenceStats
	Intervals []bgzf.Offset
}

// Bin is an index bin.
type Bin struct {
	Bin    uint32
	Chunks []bgzf.Chunk
}

// ReferenceStats holds mapping statistics for a genomic reference.
type ReferenceStats struct {
	// Chunk is the span of the indexed BGZF
	// holding alignments to the reference.
	Chunk bgzf.Chunk

	// Mapped is the count of mapped reads.
	Mapped uint64

	// Unmapped is the count of unmapped reads.
	Unmapped uint64
}

// Record wraps types that may be indexed by an Index.
type Record interface {
	RefID() int
	Start() int
	End() int
}

// Add records the SAM record as having being located at the given chunk.
func (i *Index) Add(r Record, bin uint32, c bgzf.Chunk, placed, mapped bool) error {
	if !IsValidIndexPos(r.Start()) || !IsValidIndexPos(r.End()) {
		return errors.New("index: attempt to add record outside indexable range")
	}

	if i.Unmapped == nil {
		i.Unmapped = new(uint64)
	}
	if !placed {
		*i.Unmapped++
		return nil
	}

	rid := r.RefID()
	if rid < len(i.Refs)-1 {
		return errors.New("index: attempt to add record out of reference ID sort order")
	}
	if rid == len(i.Refs) {
		i.Refs = append(i.Refs, RefIndex{})
		i.LastRecord = 0
	} else if rid > len(i.Refs) {
		Refs := make([]RefIndex, rid+1)
		copy(Refs, i.Refs)
		i.Refs = Refs
		i.LastRecord = 0
	}
	ref := &i.Refs[rid]

	// Record bin information.
	for i, b := range ref.Bins {
		if b.Bin == bin {
			for j, chunk := range ref.Bins[i].Chunks {
				if vOffset(chunk.End) > vOffset(c.Begin) {
					ref.Bins[i].Chunks[j].End = c.End
					goto found
				}
			}
			ref.Bins[i].Chunks = append(ref.Bins[i].Chunks, c)
			goto found
		}
	}
	i.IsSorted = false // TODO(kortschak) Consider making use of this more effectively for bin search.
	ref.Bins = append(ref.Bins, Bin{
		Bin:    bin,
		Chunks: []bgzf.Chunk{c},
	})
found:

	// Record interval tile information.
	biv := r.Start() / TileWidth
	if r.Start() < i.LastRecord {
		return errors.New("index: attempt to add record out of position sort order")
	}
	i.LastRecord = r.Start()
	eiv := r.End() / TileWidth
	if eiv == len(ref.Intervals) {
		if eiv > biv {
			panic("index: unexpected alignment length")
		}
		ref.Intervals = append(ref.Intervals, c.Begin)
	} else if eiv > len(ref.Intervals) {
		intvs := make([]bgzf.Offset, eiv)
		if len(ref.Intervals) > biv {
			biv = len(ref.Intervals)
		}
		for iv, offset := range intvs[biv:eiv] {
			if !isZero(offset) {
				panic("index: unexpected non-zero offset")
			}
			intvs[iv+biv] = c.Begin
		}
		copy(intvs, ref.Intervals)
		ref.Intervals = intvs
	}

	// Record index stats.
	if ref.Stats == nil {
		ref.Stats = &ReferenceStats{
			Chunk: c,
		}
	} else {
		ref.Stats.Chunk.End = c.End
	}
	if mapped {
		ref.Stats.Mapped++
	} else {
		ref.Stats.Unmapped++
	}

	return nil
}

// Chunks returns a []bgzf.Chunk that corresponds to the given genomic interval.
func (i *Index) Chunks(rid, beg, end int) ([]bgzf.Chunk, error) {
	if rid < 0 || rid >= len(i.Refs) {
		return nil, index.ErrNoReference
	}
	i.sort()
	ref := i.Refs[rid]

	iv := beg / TileWidth
	if iv >= len(ref.Intervals) {
		return nil, index.ErrInvalid
	}

	// Collect candidate chunks according to the scheme described in
	// the SAM spec under section 5 Indexing BAM.
	var chunks []bgzf.Chunk
	for _, b := range OverlappingBinsFor(beg, end) {
		c := sort.Search(len(ref.Bins), func(i int) bool { return ref.Bins[i].Bin >= b })
		if c < len(ref.Bins) && ref.Bins[c].Bin == b {
			for _, chunk := range ref.Bins[c].Chunks {
				// Here we check all tiles starting from the left end of the
				// query region until we get a non-zero offset. The spec states
				// that we only need to check tiles that contain beg. That is
				// not correct since we may have no alignments at the left end
				// of the query region.
				chunkEndOffset := vOffset(chunk.End)
				haveNonZero := false
				for j, tile := range ref.Intervals[iv:] {
					// If we have found a non-zero tile, all subsequent active
					// tiles must also be non-zero, so skip zero tiles.
					if haveNonZero && isZero(tile) {
						continue
					}
					haveNonZero = true
					tbeg := (j + iv) * TileWidth
					tend := tbeg + TileWidth
					// We allow adjacent alignment since samtools behaviour here
					// has always irritated me and it is cheap to discard these
					// later if they are not wanted.
					if tend >= beg && tbeg <= end && chunkEndOffset > vOffset(tile) {
						chunks = append(chunks, chunk)
						break
					}
				}
			}
		}
	}

	// Sort and merge overlaps.
	if !sort.IsSorted(byBeginOffset(chunks)) {
		sort.Sort(byBeginOffset(chunks))
	}

	return chunks, nil
}

func (i *Index) sort() {
	if !i.IsSorted {
		for _, ref := range i.Refs {
			sort.Sort(byBinNumber(ref.Bins))
			for _, bin := range ref.Bins {
				sort.Sort(byBeginOffset(bin.Chunks))
			}
			sort.Sort(byVirtOffset(ref.Intervals))
		}
		i.IsSorted = true
	}
}

// MergeChunks applies the given MergeStrategy to all bins in the Index.
func (i *Index) MergeChunks(s func([]bgzf.Chunk) []bgzf.Chunk) {
	if s == nil {
		return
	}
	for _, ref := range i.Refs {
		for b, bin := range ref.Bins {
			if !sort.IsSorted(byBeginOffset(bin.Chunks)) {
				sort.Sort(byBeginOffset(bin.Chunks))
			}
			ref.Bins[b].Chunks = s(bin.Chunks)
			if !sort.IsSorted(byBeginOffset(bin.Chunks)) {
				sort.Sort(byBeginOffset(bin.Chunks))
			}
		}
	}
}

const (
	indexWordBits = 29
	nextBinShift  = 3
)

// IsValidIndexPos returns a boolean indicating whether
// the given position is in the valid range for BAM/SAM.
func IsValidIndexPos(i int) bool { return -1 <= i && i <= (1<<indexWordBits-1)-1 } // 0-based.

const (
	level0 = uint32(((1 << (iota * nextBinShift)) - 1) / 7)
	level1
	level2
	level3
	level4
	level5
)

const (
	level0Shift = indexWordBits - (iota * nextBinShift)
	level1Shift
	level2Shift
	level3Shift
	level4Shift
	level5Shift
)

// BinFor returns the bin number for given an interval covering
// [beg,end) (zero-based, half-close-half-open).
func BinFor(beg, end int) uint32 {
	end--
	switch {
	case beg>>level5Shift == end>>level5Shift:
		return level5 + uint32(beg>>level5Shift)
	case beg>>level4Shift == end>>level4Shift:
		return level4 + uint32(beg>>level4Shift)
	case beg>>level3Shift == end>>level3Shift:
		return level3 + uint32(beg>>level3Shift)
	case beg>>level2Shift == end>>level2Shift:
		return level2 + uint32(beg>>level2Shift)
	case beg>>level1Shift == end>>level1Shift:
		return level1 + uint32(beg>>level1Shift)
	}
	return level0
}

// OverlappingBinsFor returns the bin numbers for all bins overlapping
// an interval covering [beg,end) (zero-based, half-close-half-open).
func OverlappingBinsFor(beg, end int) []uint32 {
	end--
	list := []uint32{level0}
	for _, r := range []struct {
		offset, shift uint32
	}{
		{level1, level1Shift},
		{level2, level2Shift},
		{level3, level3Shift},
		{level4, level4Shift},
		{level5, level5Shift},
	} {
		for k := r.offset + uint32(beg>>r.shift); k <= r.offset+uint32(end>>r.shift); k++ {
			list = append(list, k)
		}
	}
	return list
}

func makeOffset(vOff uint64) bgzf.Offset {
	return bgzf.Offset{
		File:  int64(vOff >> 16),
		Block: uint16(vOff),
	}
}

func isZero(o bgzf.Offset) bool {
	return o == bgzf.Offset{}
}

func vOffset(o bgzf.Offset) int64 {
	return o.File<<16 | int64(o.Block)
}

type byBinNumber []Bin

func (b byBinNumber) Len() int           { return len(b) }
func (b byBinNumber) Less(i, j int) bool { return b[i].Bin < b[j].Bin }
func (b byBinNumber) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }

type byBeginOffset []bgzf.Chunk

func (c byBeginOffset) Len() int           { return len(c) }
func (c byBeginOffset) Less(i, j int) bool { return vOffset(c[i].Begin) < vOffset(c[j].Begin) }
func (c byBeginOffset) Swap(i, j int)      { c[i], c[j] = c[j], c[i] }

type byVirtOffset []bgzf.Offset

func (o byVirtOffset) Len() int           { return len(o) }
func (o byVirtOffset) Less(i, j int) bool { return vOffset(o[i]) < vOffset(o[j]) }
func (o byVirtOffset) Swap(i, j int)      { o[i], o[j] = o[j], o[i] }
<commit_msg>internal: make stats dummy bin identity clearer<commit_after>// Copyright ©2014 The bíogo Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package internal provides shared code for BAI and tabix index implementations.
package internal

import (
	"errors"
	"sort"

	"github.com/biogo/hts/bgzf"
	"github.com/biogo/hts/bgzf/index"
)

const (
	// TileWidth is the length of the interval tiling used
	// in BAI and tabix indexes.
	TileWidth = 0x4000

	// Levels is the number of levels in the index tree.
	Levels = 6

	// BinLimit is the maximum number of bins available in
	// a BAI or tabix index.
	BinLimit = ((1 << (Levels * nextBinShift)) - 1) / 7

	// StatsDummyBin is the bin number of the reference
	// statistics bin used in BAI and tabix indexes.
	StatsDummyBin = BinLimit + 1
)

// Index is a coordinate based index.
type Index struct {
	Refs       []RefIndex
	Unmapped   *uint64
	IsSorted   bool
	LastRecord int
}

// RefIndex is the index of a single reference.
type RefIndex struct {
	Bins      []Bin
	Stats     *ReferenceStats
	Intervals []bgzf.Offset
}

// Bin is an index bin.
type Bin struct {
	Bin    uint32
	Chunks []bgzf.Chunk
}

// ReferenceStats holds mapping statistics for a genomic reference.
type ReferenceStats struct {
	// Chunk is the span of the indexed BGZF
	// holding alignments to the reference.
	Chunk bgzf.Chunk

	// Mapped is the count of mapped reads.
	Mapped uint64

	// Unmapped is the count of unmapped reads.
	Unmapped uint64
}

// Record wraps types that may be indexed by an Index.
type Record interface {
	RefID() int
	Start() int
	End() int
}

// Add records the SAM record as having being located at the given chunk.
func (i *Index) Add(r Record, bin uint32, c bgzf.Chunk, placed, mapped bool) error {
	if !IsValidIndexPos(r.Start()) || !IsValidIndexPos(r.End()) {
		return errors.New("index: attempt to add record outside indexable range")
	}

	if i.Unmapped == nil {
		i.Unmapped = new(uint64)
	}
	if !placed {
		*i.Unmapped++
		return nil
	}

	rid := r.RefID()
	if rid < len(i.Refs)-1 {
		return errors.New("index: attempt to add record out of reference ID sort order")
	}
	if rid == len(i.Refs) {
		i.Refs = append(i.Refs, RefIndex{})
		i.LastRecord = 0
	} else if rid > len(i.Refs) {
		Refs := make([]RefIndex, rid+1)
		copy(Refs, i.Refs)
		i.Refs = Refs
		i.LastRecord = 0
	}
	ref := &i.Refs[rid]

	// Record bin information.
	for i, b := range ref.Bins {
		if b.Bin == bin {
			for j, chunk := range ref.Bins[i].Chunks {
				if vOffset(chunk.End) > vOffset(c.Begin) {
					ref.Bins[i].Chunks[j].End = c.End
					goto found
				}
			}
			ref.Bins[i].Chunks = append(ref.Bins[i].Chunks, c)
			goto found
		}
	}
	i.IsSorted = false // TODO(kortschak) Consider making use of this more effectively for bin search.
	ref.Bins = append(ref.Bins, Bin{
		Bin:    bin,
		Chunks: []bgzf.Chunk{c},
	})
found:

	// Record interval tile information.
	biv := r.Start() / TileWidth
	if r.Start() < i.LastRecord {
		return errors.New("index: attempt to add record out of position sort order")
	}
	i.LastRecord = r.Start()
	eiv := r.End() / TileWidth
	if eiv == len(ref.Intervals) {
		if eiv > biv {
			panic("index: unexpected alignment length")
		}
		ref.Intervals = append(ref.Intervals, c.Begin)
	} else if eiv > len(ref.Intervals) {
		intvs := make([]bgzf.Offset, eiv)
		if len(ref.Intervals) > biv {
			biv = len(ref.Intervals)
		}
		for iv, offset := range intvs[biv:eiv] {
			if !isZero(offset) {
				panic("index: unexpected non-zero offset")
			}
			intvs[iv+biv] = c.Begin
		}
		copy(intvs, ref.Intervals)
		ref.Intervals = intvs
	}

	// Record index stats.
	if ref.Stats == nil {
		ref.Stats = &ReferenceStats{
			Chunk: c,
		}
	} else {
		ref.Stats.Chunk.End = c.End
	}
	if mapped {
		ref.Stats.Mapped++
	} else {
		ref.Stats.Unmapped++
	}

	return nil
}

// Chunks returns a []bgzf.Chunk that corresponds to the given genomic interval.
func (i *Index) Chunks(rid, beg, end int) ([]bgzf.Chunk, error) {
	if rid < 0 || rid >= len(i.Refs) {
		return nil, index.ErrNoReference
	}
	i.sort()
	ref := i.Refs[rid]

	iv := beg / TileWidth
	if iv >= len(ref.Intervals) {
		return nil, index.ErrInvalid
	}

	// Collect candidate chunks according to the scheme described in
	// the SAM spec under section 5 Indexing BAM.
	var chunks []bgzf.Chunk
	for _, b := range OverlappingBinsFor(beg, end) {
		c := sort.Search(len(ref.Bins), func(i int) bool { return ref.Bins[i].Bin >= b })
		if c < len(ref.Bins) && ref.Bins[c].Bin == b {
			for _, chunk := range ref.Bins[c].Chunks {
				// Here we check all tiles starting from the left end of the
				// query region until we get a non-zero offset. The spec states
				// that we only need to check tiles that contain beg. That is
				// not correct since we may have no alignments at the left end
				// of the query region.
				chunkEndOffset := vOffset(chunk.End)
				haveNonZero := false
				for j, tile := range ref.Intervals[iv:] {
					// If we have found a non-zero tile, all subsequent active
					// tiles must also be non-zero, so skip zero tiles.
					if haveNonZero && isZero(tile) {
						continue
					}
					haveNonZero = true
					tbeg := (j + iv) * TileWidth
					tend := tbeg + TileWidth
					// We allow adjacent alignment since samtools behaviour here
					// has always irritated me and it is cheap to discard these
					// later if they are not wanted.
					if tend >= beg && tbeg <= end && chunkEndOffset > vOffset(tile) {
						chunks = append(chunks, chunk)
						break
					}
				}
			}
		}
	}

	// Sort and merge overlaps.
	if !sort.IsSorted(byBeginOffset(chunks)) {
		sort.Sort(byBeginOffset(chunks))
	}

	return chunks, nil
}

func (i *Index) sort() {
	if !i.IsSorted {
		for _, ref := range i.Refs {
			sort.Sort(byBinNumber(ref.Bins))
			for _, bin := range ref.Bins {
				sort.Sort(byBeginOffset(bin.Chunks))
			}
			sort.Sort(byVirtOffset(ref.Intervals))
		}
		i.IsSorted = true
	}
}

// MergeChunks applies the given MergeStrategy to all bins in the Index.
func (i *Index) MergeChunks(s func([]bgzf.Chunk) []bgzf.Chunk) {
	if s == nil {
		return
	}
	for _, ref := range i.Refs {
		for b, bin := range ref.Bins {
			if !sort.IsSorted(byBeginOffset(bin.Chunks)) {
				sort.Sort(byBeginOffset(bin.Chunks))
			}
			ref.Bins[b].Chunks = s(bin.Chunks)
			if !sort.IsSorted(byBeginOffset(bin.Chunks)) {
				sort.Sort(byBeginOffset(bin.Chunks))
			}
		}
	}
}

const (
	indexWordBits = 29
	nextBinShift  = 3
)

// IsValidIndexPos returns a boolean indicating whether
// the given position is in the valid range for BAM/SAM.
func IsValidIndexPos(i int) bool { return -1 <= i && i <= (1<<indexWordBits-1)-1 } // 0-based.

const (
	level0 = uint32(((1 << (iota * nextBinShift)) - 1) / 7)
	level1
	level2
	level3
	level4
	level5
)

const (
	level0Shift = indexWordBits - (iota * nextBinShift)
	level1Shift
	level2Shift
	level3Shift
	level4Shift
	level5Shift
)

// BinFor returns the bin number for given an interval covering
// [beg,end) (zero-based, half-close-half-open).
func BinFor(beg, end int) uint32 {
	end--
	switch {
	case beg>>level5Shift == end>>level5Shift:
		return level5 + uint32(beg>>level5Shift)
	case beg>>level4Shift == end>>level4Shift:
		return level4 + uint32(beg>>level4Shift)
	case beg>>level3Shift == end>>level3Shift:
		return level3 + uint32(beg>>level3Shift)
	case beg>>level2Shift == end>>level2Shift:
		return level2 + uint32(beg>>level2Shift)
	case beg>>level1Shift == end>>level1Shift:
		return level1 + uint32(beg>>level1Shift)
	}
	return level0
}

// OverlappingBinsFor returns the bin numbers for all bins overlapping
// an interval covering [beg,end) (zero-based, half-close-half-open).
func OverlappingBinsFor(beg, end int) []uint32 {
	end--
	list := []uint32{level0}
	for _, r := range []struct {
		offset, shift uint32
	}{
		{level1, level1Shift},
		{level2, level2Shift},
		{level3, level3Shift},
		{level4, level4Shift},
		{level5, level5Shift},
	} {
		for k := r.offset + uint32(beg>>r.shift); k <= r.offset+uint32(end>>r.shift); k++ {
			list = append(list, k)
		}
	}
	return list
}

func makeOffset(vOff uint64) bgzf.Offset {
	return bgzf.Offset{
		File:  int64(vOff >> 16),
		Block: uint16(vOff),
	}
}

func isZero(o bgzf.Offset) bool {
	return o == bgzf.Offset{}
}

func vOffset(o bgzf.Offset) int64 {
	return o.File<<16 | int64(o.Block)
}

type byBinNumber []Bin

func (b byBinNumber) Len() int           { return len(b) }
func (b byBinNumber) Less(i, j int) bool { return b[i].Bin < b[j].Bin }
func (b byBinNumber) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }

type byBeginOffset []bgzf.Chunk

func (c byBeginOffset) Len() int           { return len(c) }
func (c byBeginOffset) Less(i, j int) bool { return vOffset(c[i].Begin) < vOffset(c[j].Begin) }
func (c byBeginOffset) Swap(i, j int)      { c[i], c[j] = c[j], c[i] }

type byVirtOffset []bgzf.Offset

func (o byVirtOffset) Len() int           { return len(o) }
func (o byVirtOffset) Less(i, j int) bool { return vOffset(o[i]) < vOffset(o[j]) }
func (o byVirtOffset) Swap(i, j int)      { o[i], o[j] = o[j], o[i] }
<|endoftext|>


<commit_before>// Copyright 2015 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package internal

import (
	"log"
	"os"
	"os/exec"
	"strings"
	"syscall"
)

// Capture runs an executable from a directory returns the output, exit code
// and error if appropriate. It sets the environment variables specified.
func Capture(wd string, env []string, args ...string) (string, int, error) {
	exitCode := -1
	log.Printf("Capture(%s, %s, %s)", wd, env, args)
	c := exec.Command(args[0], args[1:]...)
	if wd != "" {
		c.Dir = wd
	}
	procEnv := map[string]string{}
	for _, item := range os.Environ() {
		items := strings.SplitN(item, "=", 2)
		procEnv[items[0]] = items[1]
	}
	procEnv["LANG"] = "en_US.UTF-8"
	procEnv["LANGUAGE"] = "en_US.UTF-8"
	for _, item := range env {
		items := strings.SplitN(item, "=", 2)
		procEnv[items[0]] = items[1]
	}
	c.Env = make([]string, 0, len(procEnv))
	for k, v := range procEnv {
		c.Env = append(c.Env, k+"="+v)
	}
	out, err := c.CombinedOutput()
	if c.ProcessState != nil {
		if waitStatus, ok := c.ProcessState.Sys().(syscall.WaitStatus); ok {
			exitCode = waitStatus.ExitStatus()
			if exitCode != 0 {
				err = nil
			}
		}
	}
	// TODO(maruel): Handle code page on Windows.
	return string(out), exitCode, err
}
<commit_msg>Fix a crash in internal.Capture() for command without arg.<commit_after>// Copyright 2015 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package internal

import (
	"os"
	"os/exec"
	"strings"
	"syscall"
)

// Capture runs an executable from a directory returns the output, exit code
// and error if appropriate. It sets the environment variables specified.
func Capture(wd string, env []string, args ...string) (string, int, error) {
	exitCode := -1
	//log.Printf("Capture(%s, %s, %s)", wd, env, args)
	var c *exec.Cmd
	if len(args) > 1 {
		c = exec.Command(args[0], args[1:]...)
	} else {
		c = exec.Command(args[0])
	}
	if wd != "" {
		c.Dir = wd
	}
	procEnv := map[string]string{}
	for _, item := range os.Environ() {
		items := strings.SplitN(item, "=", 2)
		procEnv[items[0]] = items[1]
	}
	procEnv["LANG"] = "en_US.UTF-8"
	procEnv["LANGUAGE"] = "en_US.UTF-8"
	for _, item := range env {
		items := strings.SplitN(item, "=", 2)
		procEnv[items[0]] = items[1]
	}
	c.Env = make([]string, 0, len(procEnv))
	for k, v := range procEnv {
		c.Env = append(c.Env, k+"="+v)
	}
	out, err := c.CombinedOutput()
	if c.ProcessState != nil {
		if waitStatus, ok := c.ProcessState.Sys().(syscall.WaitStatus); ok {
			exitCode = waitStatus.ExitStatus()
			if exitCode != 0 {
				err = nil
			}
		}
	}
	// TODO(maruel): Handle code page on Windows.
	return string(out), exitCode, err
}
<|endoftext|>


<commit_before>package ring

import (
	"bytes"
	"encoding/binary"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net"
	"testing"
	"time"
)

func newRingConn(conn net.Conn) *ringConn {
	return &ringConn{
		state:  _STATE_CONNECTED,
		conn:   conn,
		reader: newTimeoutReader(conn, 16*1024, 2*time.Second),
		writer: newTimeoutWriter(conn, 16*1024, 2*time.Second),
	}
}

// Mock up a bunch of stuff

func newTestRing() (Ring, Node, Node) {
	b := NewBuilder()
	b.SetReplicaCount(3)
	nA := b.AddNode(true, 1, nil, []string{"127.0.0.1:9999"}, "", []byte("Conf"))
	nB := b.AddNode(true, 1, nil, []string{"127.0.0.1:8888"}, "", []byte("Conf"))
	r := b.Ring()
	r.SetLocalNode(nA.ID())
	return r, nA, nB
}

var testMsg = []byte("Testing")
var testStr = "Testing"

type TestMsg struct {
}

func (m *TestMsg) MsgType() uint64 {
	return 1
}

func (m *TestMsg) MsgLength() uint64 {
	return 7
}

func (m *TestMsg) WriteContent(writer io.Writer) (uint64, error) {
	count, err := writer.Write(testMsg)
	return uint64(count), err
}

func (m *TestMsg) Done() {
	return
}

// Following mock stuff borrowed from golang.org/src/net/http/serve_test.go
type dummyAddr string

func (a dummyAddr) Network() string {
	return string(a)
}

func (a dummyAddr) String() string {
	return string(a)
}

type noopConn struct{}

func (noopConn) LocalAddr() net.Addr                { return dummyAddr("local-addr") }
func (noopConn) RemoteAddr() net.Addr               { return dummyAddr("remote-addr") }
func (noopConn) SetDeadline(t time.Time) error      { return nil }
func (noopConn) SetReadDeadline(t time.Time) error  { return nil }
func (noopConn) SetWriteDeadline(t time.Time) error { return nil }

type testConn struct {
	readBuf  bytes.Buffer
	writeBuf bytes.Buffer
	noopConn
}

func (c *testConn) Read(b []byte) (int, error) {
	return c.readBuf.Read(b)
}

func (c *testConn) Write(b []byte) (int, error) {
	return c.writeBuf.Write(b)
}

func (c *testConn) Close() error {
	return nil
}

/***** Actual tests start here *****/

func TestTCPMsgRingIsMsgRing(t *testing.T) {
	r, _, _ := newTestRing()
	tmr := NewTCPMsgRing(r)
	func(mr MsgRing) {}(tmr)
}

func Test_NewTCPMsgRing(t *testing.T) {
	r, _, _ := newTestRing()
	msgring := NewTCPMsgRing(r)
	if msgring.Ring().LocalNode().Address(0) != "127.0.0.1:9999" {
		t.Error("Error initializing TCPMsgRing")
	}
}

func Test_TCPMsgRingSetRing(t *testing.T) {
	r, _, _ := newTestRing()
	msgring := NewTCPMsgRing(r)

	r2, _, _ := newTestRing()
	msgring.SetRing(r2)

	if msgring.Ring() != r {
		t.Error("Error setting TCPMsgRing Ring")
	}
}

func test_stringmarshaller(reader io.Reader, size uint64) (uint64, error) {
	buf := make([]byte, size)
	c, err := reader.Read(buf)
	if !bytes.Equal(buf, testMsg) {
		err = errors.New("Unmarshaller didn't read the correct value")
	}
	return uint64(c), err
}

func Test_handle(t *testing.T) {
	log.SetOutput(ioutil.Discard)
	conn := new(testConn)
	binary.Write(&conn.readBuf, binary.BigEndian, uint64(1))
	binary.Write(&conn.readBuf, binary.BigEndian, uint64(7))
	conn.readBuf.WriteString(testStr)
	r, _, _ := newTestRing()
	msgring := NewTCPMsgRing(r)
	msgring.SetMsgHandler(1, test_stringmarshaller)
	msgring.handleForever(newRingConn(conn))
}

func Test_MsgToNode(t *testing.T) {
	conn := new(testConn)
	r, _, nB := newTestRing()
	msgring := NewTCPMsgRing(r)
	msgring.conns[nB.Address(0)] = newRingConn(conn)
	msg := TestMsg{}
	msgring.MsgToNode(nB.ID(), &msg)
	var msgtype uint64
	binary.Read(&conn.writeBuf, binary.BigEndian, &msgtype)
	if int(msgtype) != 1 {
		t.Error("Message type not written correctly")
	}
	var msgsize uint64
	binary.Read(&conn.writeBuf, binary.BigEndian, &msgsize)
	if msgsize != 7 {
		t.Error("Incorrect message size")
	}
	msgcontent := make([]byte, 7)
	conn.writeBuf.Read(msgcontent)
	if !bytes.Equal(msgcontent, testMsg) {
		t.Error("Incorrect message contents")
	}
}

func Test_MsgToNodeChan(t *testing.T) {
	conn := new(testConn)
	r, _, nB := newTestRing()
	msgring := NewTCPMsgRing(r)
	msgring.conns[nB.Address(0)] = newRingConn(conn)
	msg := TestMsg{}
	retch := make(chan struct{})
	go msgring.msgToNodeChan(&msg, nB, retch)
	<-retch
	var msgtype uint64
	binary.Read(&conn.writeBuf, binary.BigEndian, &msgtype)
	if int(msgtype) != 1 {
		t.Error("Message type not written correctly")
	}
	var msgsize uint64
	binary.Read(&conn.writeBuf, binary.BigEndian, &msgsize)
	if msgsize != 7 {
		t.Error("Incorrect message size")
	}
	msgcontent := make([]byte, 7)
	conn.writeBuf.Read(msgcontent)
	if !bytes.Equal(msgcontent, testMsg) {
		t.Error("Incorrect message contents")
	}
}

func Test_MsgToOtherReplicas(t *testing.T) {
	conn := new(testConn)
	r, _, nB := newTestRing()
	msgring := NewTCPMsgRing(r)
	msgring.conns[nB.Address(0)] = newRingConn(conn)
	msg := TestMsg{}
	msgring.MsgToOtherReplicas(r.Version(), uint32(1), &msg)
	var msgtype uint64
	err := binary.Read(&conn.writeBuf, binary.BigEndian, &msgtype)
	if err != nil {
		t.Error(err)
	}
	if int(msgtype) != 1 {
		t.Errorf("Message type not written correctly was %d", msgtype)
	}
	var msgsize uint64
	binary.Read(&conn.writeBuf, binary.BigEndian, &msgsize)
	if msgsize != 7 {
		t.Error("Incorrect message size")
	}
	msgcontent := make([]byte, 7)
	conn.writeBuf.Read(msgcontent)
	if !bytes.Equal(msgcontent, testMsg) {
		t.Error("Incorrect message contents")
	}
}
<commit_msg>Oops. Failed at not sucking.<commit_after>package ring

import (
	"bytes"
	"encoding/binary"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net"
	"testing"
	"time"
)

func newRingConn(conn net.Conn) *ringConn {
	return &ringConn{
		state:  _STATE_CONNECTED,
		conn:   conn,
		reader: newTimeoutReader(conn, 16*1024, 2*time.Second),
		writer: newTimeoutWriter(conn, 16*1024, 2*time.Second),
	}
}

// Mock up a bunch of stuff

func newTestRing() (Ring, Node, Node) {
	b := NewBuilder()
	b.SetReplicaCount(3)
	nA := b.AddNode(true, 1, nil, []string{"127.0.0.1:9999"}, "", []byte("Conf"))
	nB := b.AddNode(true, 1, nil, []string{"127.0.0.1:8888"}, "", []byte("Conf"))
	r := b.Ring()
	r.SetLocalNode(nA.ID())
	return r, nA, nB
}

var testMsg = []byte("Testing")
var testStr = "Testing"

type TestMsg struct {
}

func (m *TestMsg) MsgType() uint64 {
	return 1
}

func (m *TestMsg) MsgLength() uint64 {
	return 7
}

func (m *TestMsg) WriteContent(writer io.Writer) (uint64, error) {
	count, err := writer.Write(testMsg)
	return uint64(count), err
}

func (m *TestMsg) Done() {
	return
}

// Following mock stuff borrowed from golang.org/src/net/http/serve_test.go
type dummyAddr string

func (a dummyAddr) Network() string {
	return string(a)
}

func (a dummyAddr) String() string {
	return string(a)
}

type noopConn struct{}

func (noopConn) LocalAddr() net.Addr                { return dummyAddr("local-addr") }
func (noopConn) RemoteAddr() net.Addr               { return dummyAddr("remote-addr") }
func (noopConn) SetDeadline(t time.Time) error      { return nil }
func (noopConn) SetReadDeadline(t time.Time) error  { return nil }
func (noopConn) SetWriteDeadline(t time.Time) error { return nil }

type testConn struct {
	readBuf  bytes.Buffer
	writeBuf bytes.Buffer
	noopConn
}

func (c *testConn) Read(b []byte) (int, error) {
	return c.readBuf.Read(b)
}

func (c *testConn) Write(b []byte) (int, error) {
	return c.writeBuf.Write(b)
}

func (c *testConn) Close() error {
	return nil
}

/***** Actual tests start here *****/

func TestTCPMsgRingIsMsgRing(t *testing.T) {
	r, _, _ := newTestRing()
	tmr := NewTCPMsgRing(r)
	func(mr MsgRing) {}(tmr)
}

func Test_NewTCPMsgRing(t *testing.T) {
	r, _, _ := newTestRing()
	msgring := NewTCPMsgRing(r)
	if msgring.Ring().LocalNode().Address(0) != "127.0.0.1:9999" {
		t.Error("Error initializing TCPMsgRing")
	}
}

func Test_TCPMsgRingSetRing(t *testing.T) {
	r, _, _ := newTestRing()
	msgring := NewTCPMsgRing(r)

	r2, _, _ := newTestRing()
	msgring.SetRing(r2)

	if msgring.Ring() != r2 {
		t.Error("Error setting TCPMsgRing Ring")
	}
}

func test_stringmarshaller(reader io.Reader, size uint64) (uint64, error) {
	buf := make([]byte, size)
	c, err := reader.Read(buf)
	if !bytes.Equal(buf, testMsg) {
		err = errors.New("Unmarshaller didn't read the correct value")
	}
	return uint64(c), err
}

func Test_handle(t *testing.T) {
	log.SetOutput(ioutil.Discard)
	conn := new(testConn)
	binary.Write(&conn.readBuf, binary.BigEndian, uint64(1))
	binary.Write(&conn.readBuf, binary.BigEndian, uint64(7))
	conn.readBuf.WriteString(testStr)
	r, _, _ := newTestRing()
	msgring := NewTCPMsgRing(r)
	msgring.SetMsgHandler(1, test_stringmarshaller)
	msgring.handleForever(newRingConn(conn))
}

func Test_MsgToNode(t *testing.T) {
	conn := new(testConn)
	r, _, nB := newTestRing()
	msgring := NewTCPMsgRing(r)
	msgring.conns[nB.Address(0)] = newRingConn(conn)
	msg := TestMsg{}
	msgring.MsgToNode(nB.ID(), &msg)
	var msgtype uint64
	binary.Read(&conn.writeBuf, binary.BigEndian, &msgtype)
	if int(msgtype) != 1 {
		t.Error("Message type not written correctly")
	}
	var msgsize uint64
	binary.Read(&conn.writeBuf, binary.BigEndian, &msgsize)
	if msgsize != 7 {
		t.Error("Incorrect message size")
	}
	msgcontent := make([]byte, 7)
	conn.writeBuf.Read(msgcontent)
	if !bytes.Equal(msgcontent, testMsg) {
		t.Error("Incorrect message contents")
	}
}

func Test_MsgToNodeChan(t *testing.T) {
	conn := new(testConn)
	r, _, nB := newTestRing()
	msgring := NewTCPMsgRing(r)
	msgring.conns[nB.Address(0)] = newRingConn(conn)
	msg := TestMsg{}
	retch := make(chan struct{})
	go msgring.msgToNodeChan(&msg, nB, retch)
	<-retch
	var msgtype uint64
	binary.Read(&conn.writeBuf, binary.BigEndian, &msgtype)
	if int(msgtype) != 1 {
		t.Error("Message type not written correctly")
	}
	var msgsize uint64
	binary.Read(&conn.writeBuf, binary.BigEndian, &msgsize)
	if msgsize != 7 {
		t.Error("Incorrect message size")
	}
	msgcontent := make([]byte, 7)
	conn.writeBuf.Read(msgcontent)
	if !bytes.Equal(msgcontent, testMsg) {
		t.Error("Incorrect message contents")
	}
}

func Test_MsgToOtherReplicas(t *testing.T) {
	conn := new(testConn)
	r, _, nB := newTestRing()
	msgring := NewTCPMsgRing(r)
	msgring.conns[nB.Address(0)] = newRingConn(conn)
	msg := TestMsg{}
	msgring.MsgToOtherReplicas(r.Version(), uint32(1), &msg)
	var msgtype uint64
	err := binary.Read(&conn.writeBuf, binary.BigEndian, &msgtype)
	if err != nil {
		t.Error(err)
	}
	if int(msgtype) != 1 {
		t.Errorf("Message type not written correctly was %d", msgtype)
	}
	var msgsize uint64
	binary.Read(&conn.writeBuf, binary.BigEndian, &msgsize)
	if msgsize != 7 {
		t.Error("Incorrect message size")
	}
	msgcontent := make([]byte, 7)
	conn.writeBuf.Read(msgcontent)
	if !bytes.Equal(msgcontent, testMsg) {
		t.Error("Incorrect message contents")
	}
}
<|endoftext|>


<commit_before>// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"strings"

	"github.com/olivere/elastic/v7/uritemplates"
)

// IndicesDeleteService allows to delete existing indices.
//
// See https://www.elastic.co/guide/en/elasticsearch/reference/7.0/indices-delete-index.html
// for details.
type IndicesDeleteService struct {
	client *Client

	pretty     *bool       // pretty format the returned JSON response
	human      *bool       // return human readable values for statistics
	errorTrace *bool       // include the stack trace of returned errors
	filterPath []string    // list of filters used to reduce the response
	headers    http.Header // custom request-level HTTP headers

	index         []string
	timeout       string
	masterTimeout string
}

// NewIndicesDeleteService creates and initializes a new IndicesDeleteService.
func NewIndicesDeleteService(client *Client) *IndicesDeleteService {
	return &IndicesDeleteService{
		client: client,
		index:  make([]string, 0),
	}
}

// Pretty tells Elasticsearch whether to return a formatted JSON response.
func (s *IndicesDeleteService) Pretty(pretty bool) *IndicesDeleteService {
	s.pretty = &pretty
	return s
}

// Human specifies whether human readable values should be returned in
// the JSON response, e.g. "7.5mb".
func (s *IndicesDeleteService) Human(human bool) *IndicesDeleteService {
	s.human = &human
	return s
}

// ErrorTrace specifies whether to include the stack trace of returned errors.
func (s *IndicesDeleteService) ErrorTrace(errorTrace bool) *IndicesDeleteService {
	s.errorTrace = &errorTrace
	return s
}

// FilterPath specifies a list of filters used to reduce the response.
func (s *IndicesDeleteService) FilterPath(filterPath ...string) *IndicesDeleteService {
	s.filterPath = filterPath
	return s
}

// Header adds a header to the request.
func (s *IndicesDeleteService) Header(name string, value string) *IndicesDeleteService {
	if s.headers == nil {
		s.headers = http.Header{}
	}
	s.headers.Add(name, value)
	return s
}

// Headers specifies the headers of the request.
func (s *IndicesDeleteService) Headers(headers http.Header) *IndicesDeleteService {
	s.headers = headers
	return s
}

// Index adds the list of indices to delete.
// Use `_all` or `*` string to delete all indices.
func (s *IndicesDeleteService) Index(index []string) *IndicesDeleteService {
	s.index = index
	return s
}

// Timeout is an explicit operation timeout.
func (s *IndicesDeleteService) Timeout(timeout string) *IndicesDeleteService {
	s.timeout = timeout
	return s
}

// MasterTimeout specifies the timeout for connection to master.
func (s *IndicesDeleteService) MasterTimeout(masterTimeout string) *IndicesDeleteService {
	s.masterTimeout = masterTimeout
	return s
}

// buildURL builds the URL for the operation.
func (s *IndicesDeleteService) buildURL() (string, url.Values, error) {
	// Build URL
	path, err := uritemplates.Expand("/{index}", map[string]string{
		"index": strings.Join(s.index, ","),
	})
	if err != nil {
		return "", url.Values{}, err
	}

	// Add query string parameters
	params := url.Values{}
	if v := s.pretty; v != nil {
		params.Set("pretty", fmt.Sprint(*v))
	}
	if v := s.human; v != nil {
		params.Set("human", fmt.Sprint(*v))
	}
	if v := s.errorTrace; v != nil {
		params.Set("error_trace", fmt.Sprint(*v))
	}
	if len(s.filterPath) > 0 {
		params.Set("filter_path", strings.Join(s.filterPath, ","))
	}
	if s.timeout != "" {
		params.Set("timeout", s.timeout)
	}
	if s.masterTimeout != "" {
		params.Set("master_timeout", s.masterTimeout)
	}
	return path, params, nil
}

// Validate checks if the operation is valid.
func (s *IndicesDeleteService) Validate() error {
	var invalid []string
	if len(s.index) == 0 {
		invalid = append(invalid, "Index")
	}
	if len(invalid) > 0 {
		return fmt.Errorf("missing required fields: %v", invalid)
	}
	return nil
}

// Do executes the operation.
func (s *IndicesDeleteService) Do(ctx context.Context) (*IndicesDeleteResponse, error) {
	// Check pre-conditions
	if err := s.Validate(); err != nil {
		return nil, err
	}

	// Get URL for request
	path, params, err := s.buildURL()
	if err != nil {
		return nil, err
	}

	// Get HTTP response
	res, err := s.client.PerformRequest(ctx, PerformRequestOptions{
		Method:  "DELETE",
		Path:    path,
		Params:  params,
		Headers: s.headers,
	})
	if err != nil {
		return nil, err
	}

	// Return operation response
	ret := new(IndicesDeleteResponse)
	if err := s.client.decoder.Decode(res.Body, ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// -- Result of a delete index request.

// IndicesDeleteResponse is the response of IndicesDeleteService.Do.
type IndicesDeleteResponse struct {
	Acknowledged bool `json:"acknowledged"`
}
<commit_msg>Add missing common parameters to Delete Indices API (#1487)<commit_after>// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"strings"

	"github.com/olivere/elastic/v7/uritemplates"
)

// IndicesDeleteService allows to delete existing indices.
//
// See https://www.elastic.co/guide/en/elasticsearch/reference/7.0/indices-delete-index.html
// for details.
type IndicesDeleteService struct {
	client *Client

	pretty     *bool       // pretty format the returned JSON response
	human      *bool       // return human readable values for statistics
	errorTrace *bool       // include the stack trace of returned errors
	filterPath []string    // list of filters used to reduce the response
	headers    http.Header // custom request-level HTTP headers

	index             []string
	timeout           string
	masterTimeout     string
	ignoreUnavailable *bool
	allowNoIndices    *bool
	expandWildcards   string
}

// NewIndicesDeleteService creates and initializes a new IndicesDeleteService.
func NewIndicesDeleteService(client *Client) *IndicesDeleteService {
	return &IndicesDeleteService{
		client: client,
		index:  make([]string, 0),
	}
}

// Pretty tells Elasticsearch whether to return a formatted JSON response.
func (s *IndicesDeleteService) Pretty(pretty bool) *IndicesDeleteService {
	s.pretty = &pretty
	return s
}

// Human specifies whether human readable values should be returned in
// the JSON response, e.g. "7.5mb".
func (s *IndicesDeleteService) Human(human bool) *IndicesDeleteService {
	s.human = &human
	return s
}

// ErrorTrace specifies whether to include the stack trace of returned errors.
func (s *IndicesDeleteService) ErrorTrace(errorTrace bool) *IndicesDeleteService {
	s.errorTrace = &errorTrace
	return s
}

// FilterPath specifies a list of filters used to reduce the response.
func (s *IndicesDeleteService) FilterPath(filterPath ...string) *IndicesDeleteService {
	s.filterPath = filterPath
	return s
}

// Header adds a header to the request.
func (s *IndicesDeleteService) Header(name string, value string) *IndicesDeleteService {
	if s.headers == nil {
		s.headers = http.Header{}
	}
	s.headers.Add(name, value)
	return s
}

// Headers specifies the headers of the request.
func (s *IndicesDeleteService) Headers(headers http.Header) *IndicesDeleteService {
	s.headers = headers
	return s
}

// Index adds the list of indices to delete.
// Use `_all` or `*` string to delete all indices.
func (s *IndicesDeleteService) Index(index []string) *IndicesDeleteService {
	s.index = index
	return s
}

// Timeout is an explicit operation timeout.
func (s *IndicesDeleteService) Timeout(timeout string) *IndicesDeleteService {
	s.timeout = timeout
	return s
}

// MasterTimeout specifies the timeout for connection to master.
func (s *IndicesDeleteService) MasterTimeout(masterTimeout string) *IndicesDeleteService {
	s.masterTimeout = masterTimeout
	return s
}

// IgnoreUnavailable indicates whether to ignore unavailable indexes (default: false).
func (s *IndicesDeleteService) IgnoreUnavailable(ignoreUnavailable bool) *IndicesDeleteService {
	s.ignoreUnavailable = &ignoreUnavailable
	return s
}

// AllowNoIndices indicates whether to ignore if a wildcard expression
// resolves to no concrete indices (default: false).
func (s *IndicesDeleteService) AllowNoIndices(allowNoIndices bool) *IndicesDeleteService {
	s.allowNoIndices = &allowNoIndices
	return s
}

// ExpandWildcards indicates whether wildcard expressions should get
// expanded to open or closed indices (default: open).
func (s *IndicesDeleteService) ExpandWildcards(expandWildcards string) *IndicesDeleteService {
	s.expandWildcards = expandWildcards
	return s
}

// buildURL builds the URL for the operation.
func (s *IndicesDeleteService) buildURL() (string, url.Values, error) {
	// Build URL
	path, err := uritemplates.Expand("/{index}", map[string]string{
		"index": strings.Join(s.index, ","),
	})
	if err != nil {
		return "", url.Values{}, err
	}

	// Add query string parameters
	params := url.Values{}
	if v := s.pretty; v != nil {
		params.Set("pretty", fmt.Sprint(*v))
	}
	if v := s.human; v != nil {
		params.Set("human", fmt.Sprint(*v))
	}
	if v := s.errorTrace; v != nil {
		params.Set("error_trace", fmt.Sprint(*v))
	}
	if len(s.filterPath) > 0 {
		params.Set("filter_path", strings.Join(s.filterPath, ","))
	}
	if s.timeout != "" {
		params.Set("timeout", s.timeout)
	}
	if s.masterTimeout != "" {
		params.Set("master_timeout", s.masterTimeout)
	}
	if s.ignoreUnavailable != nil {
		params.Set("ignore_unavailable", fmt.Sprintf("%v", *s.ignoreUnavailable))
	}
	if s.allowNoIndices != nil {
		params.Set("allow_no_indices", fmt.Sprintf("%v", *s.allowNoIndices))
	}
	if s.expandWildcards != "" {
		params.Set("expand_wildcards", s.expandWildcards)
	}
	return path, params, nil
}

// Validate checks if the operation is valid.
func (s *IndicesDeleteService) Validate() error {
	var invalid []string
	if len(s.index) == 0 {
		invalid = append(invalid, "Index")
	}
	if len(invalid) > 0 {
		return fmt.Errorf("missing required fields: %v", invalid)
	}
	return nil
}

// Do executes the operation.
func (s *IndicesDeleteService) Do(ctx context.Context) (*IndicesDeleteResponse, error) {
	// Check pre-conditions
	if err := s.Validate(); err != nil {
		return nil, err
	}

	// Get URL for request
	path, params, err := s.buildURL()
	if err != nil {
		return nil, err
	}

	// Get HTTP response
	res, err := s.client.PerformRequest(ctx, PerformRequestOptions{
		Method:  "DELETE",
		Path:    path,
		Params:  params,
		Headers: s.headers,
	})
	if err != nil {
		return nil, err
	}

	// Return operation response
	ret := new(IndicesDeleteResponse)
	if err := s.client.decoder.Decode(res.Body, ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// -- Result of a delete index request.

// IndicesDeleteResponse is the response of IndicesDeleteService.Do.
type IndicesDeleteResponse struct {
	Acknowledged bool `json:"acknowledged"`
}
<|endoftext|>


<commit_before>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package transform

import (
	"errors"
	"io/ioutil"
	"strconv"
	"strings"
	"testing"
)

type lowerCaseASCII struct{}

func (lowerCaseASCII) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	n := len(src)
	if n > len(dst) {
		n, err = len(dst), ErrShortDst
	}
	for i, c := range src[:n] {
		if 'A' <= c && c <= 'Z' {
			c += 'a' - 'A'
		}
		dst[i] = c
	}
	return n, n, err
}

var errYouMentionedX = errors.New("you mentioned X")

type dontMentionX struct{}

func (dontMentionX) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	n := len(src)
	if n > len(dst) {
		n, err = len(dst), ErrShortDst
	}
	for i, c := range src[:n] {
		if c == 'X' {
			return i, i, errYouMentionedX
		}
		dst[i] = c
	}
	return n, n, err
}

// rleDecode and rleEncode implement a toy run-length encoding: "aabbbbbbbbbb"
// is encoded as "2a10b". The decoding is assumed to not contain any numbers.

type rleDecode struct{}

func (rleDecode) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
loop:
	for len(src) > 0 {
		n := 0
		for i, c := range src {
			if '0' <= c && c <= '9' {
				n = 10*n + int(c-'0')
				continue
			}
			if i == 0 {
				return nDst, nSrc, errors.New("rleDecode: bad input")
			}
			if n > len(dst) {
				return nDst, nSrc, ErrShortDst
			}
			for j := 0; j < n; j++ {
				dst[j] = c
			}
			dst, src = dst[n:], src[i+1:]
			nDst, nSrc = nDst+n, nSrc+i+1
			continue loop
		}
		if atEOF {
			return nDst, nSrc, errors.New("rleDecode: bad input")
		}
		return nDst, nSrc, ErrShortSrc
	}
	return nDst, nSrc, nil
}

type rleEncode struct {
	// allowStutter means that "xxxxxxxx" can be encoded as "5x3x"
	// instead of always as "8x".
	allowStutter bool
}

func (e rleEncode) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	for len(src) > 0 {
		n, c0 := len(src), src[0]
		for i, c := range src[1:] {
			if c != c0 {
				n = i + 1
				break
			}
		}
		if n == len(src) && !atEOF && !e.allowStutter {
			return nDst, nSrc, ErrShortSrc
		}
		s := strconv.Itoa(n)
		if len(s) >= len(dst) {
			return nDst, nSrc, ErrShortDst
		}
		copy(dst, s)
		dst[len(s)] = c0
		dst, src = dst[len(s)+1:], src[n:]
		nDst, nSrc = nDst+len(s)+1, nSrc+n
	}
	return nDst, nSrc, nil
}

func TestReader(t *testing.T) {
	testCases := []struct {
		desc    string
		t       Transformer
		src     string
		dstSize int
		srcSize int
		wantStr string
		wantErr error
	}{
		{
			"lowerCaseASCII",
			lowerCaseASCII{},
			"Hello WORLD.",
			100,
			100,
			"hello world.",
			nil,
		},

		{
			"lowerCaseASCII; small dst",
			lowerCaseASCII{},
			"Hello WORLD.",
			3,
			100,
			"hello world.",
			nil,
		},

		{
			"lowerCaseASCII; small src",
			lowerCaseASCII{},
			"Hello WORLD.",
			100,
			4,
			"hello world.",
			nil,
		},

		{
			"lowerCaseASCII; small buffers",
			lowerCaseASCII{},
			"Hello WORLD.",
			3,
			4,
			"hello world.",
			nil,
		},

		{
			"lowerCaseASCII; very small buffers",
			lowerCaseASCII{},
			"Hello WORLD.",
			1,
			1,
			"hello world.",
			nil,
		},

		{
			"dontMentionX",
			dontMentionX{},
			"The First Rule of Transform Club: don't mention Mister X, ever.",
			100,
			100,
			"The First Rule of Transform Club: don't mention Mister ",
			errYouMentionedX,
		},

		{
			"dontMentionX; small buffers",
			dontMentionX{},
			"The First Rule of Transform Club: don't mention Mister X, ever.",
			10,
			10,
			"The First Rule of Transform Club: don't mention Mister ",
			errYouMentionedX,
		},

		{
			"dontMentionX; very small buffers",
			dontMentionX{},
			"The First Rule of Transform Club: don't mention Mister X, ever.",
			1,
			1,
			"The First Rule of Transform Club: don't mention Mister ",
			errYouMentionedX,
		},

		{
			"rleDecode",
			rleDecode{},
			"1a2b3c10d11e0f1g",
			100,
			100,
			"abbcccddddddddddeeeeeeeeeeeg",
			nil,
		},

		{
			"rleDecode; long",
			rleDecode{},
			"12a23b34c45d56e99z",
			100,
			100,
			strings.Repeat("a", 12) +
				strings.Repeat("b", 23) +
				strings.Repeat("c", 34) +
				strings.Repeat("d", 45) +
				strings.Repeat("e", 56) +
				strings.Repeat("z", 99),
			nil,
		},

		{
			"rleDecode; tight buffers",
			rleDecode{},
			"1a2b3c10d11e0f1g",
			11,
			3,
			"abbcccddddddddddeeeeeeeeeeeg",
			nil,
		},

		{
			"rleDecode; short dst",
			rleDecode{},
			"1a2b3c10d11e0f1g",
			10,
			3,
			"abbcccdddddddddd",
			ErrShortDst,
		},

		{
			"rleDecode; short src",
			rleDecode{},
			"1a2b3c10d11e0f1g",
			11,
			2,
			"abbccc",
			ErrShortSrc,
		},

		{
			"rleEncode",
			rleEncode{},
			"abbcccddddddddddeeeeeeeeeeeg",
			100,
			100,
			"1a2b3c10d11e1g",
			nil,
		},

		{
			"rleEncode; long",
			rleEncode{},
			strings.Repeat("a", 12) +
				strings.Repeat("b", 23) +
				strings.Repeat("c", 34) +
				strings.Repeat("d", 45) +
				strings.Repeat("e", 56) +
				strings.Repeat("z", 99),
			100,
			100,
			"12a23b34c45d56e99z",
			nil,
		},

		{
			"rleEncode; tight buffers",
			rleEncode{},
			"abbcccddddddddddeeeeeeeeeeeg",
			3,
			12,
			"1a2b3c10d11e1g",
			nil,
		},

		{
			"rleEncode; short dst",
			rleEncode{},
			"abbcccddddddddddeeeeeeeeeeeg",
			2,
			12,
			"1a2b3c",
			ErrShortDst,
		},

		{
			"rleEncode; short src",
			rleEncode{},
			"abbcccddddddddddeeeeeeeeeeeg",
			3,
			11,
			"1a2b3c10d",
			ErrShortSrc,
		},

		{
			"rleEncode; allowStutter = false",
			rleEncode{allowStutter: false},
			"aaaabbbbbbbbccccddddd",
			10,
			10,
			"4a8b4c5d",
			nil,
		},

		{
			"rleEncode; allowStutter = true",
			rleEncode{allowStutter: true},
			"aaaabbbbbbbbccccddddd",
			10,
			10,
			"4a6b2b4c4d1d",
			nil,
		},
	}

	for _, tc := range testCases {
		r := NewReader(strings.NewReader(tc.src), tc.t)
		// Differently sized dst and src buffers are not part of the
		// exported API. We override them manually.
		r.dst = make([]byte, tc.dstSize)
		r.src = make([]byte, tc.srcSize)
		got, err := ioutil.ReadAll(r)
		str := string(got)
		if str != tc.wantStr || err != tc.wantErr {
			t.Errorf("%s:\ngot  %q, %v\nwant %q, %v", tc.desc, str, err, tc.wantStr, tc.wantErr)
		}
	}
}
<commit_msg>go.text/transform: re-arrange TestReader's test cases so that they can be re-used by other tests.<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package transform

import (
	"errors"
	"fmt"
	"io/ioutil"
	"strconv"
	"strings"
	"testing"
)

type lowerCaseASCII struct{}

func (lowerCaseASCII) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	n := len(src)
	if n > len(dst) {
		n, err = len(dst), ErrShortDst
	}
	for i, c := range src[:n] {
		if 'A' <= c && c <= 'Z' {
			c += 'a' - 'A'
		}
		dst[i] = c
	}
	return n, n, err
}

var errYouMentionedX = errors.New("you mentioned X")

type dontMentionX struct{}

func (dontMentionX) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	n := len(src)
	if n > len(dst) {
		n, err = len(dst), ErrShortDst
	}
	for i, c := range src[:n] {
		if c == 'X' {
			return i, i, errYouMentionedX
		}
		dst[i] = c
	}
	return n, n, err
}

// rleDecode and rleEncode implement a toy run-length encoding: "aabbbbbbbbbb"
// is encoded as "2a10b". The decoding is assumed to not contain any numbers.

type rleDecode struct{}

func (rleDecode) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
loop:
	for len(src) > 0 {
		n := 0
		for i, c := range src {
			if '0' <= c && c <= '9' {
				n = 10*n + int(c-'0')
				continue
			}
			if i == 0 {
				return nDst, nSrc, errors.New("rleDecode: bad input")
			}
			if n > len(dst) {
				return nDst, nSrc, ErrShortDst
			}
			for j := 0; j < n; j++ {
				dst[j] = c
			}
			dst, src = dst[n:], src[i+1:]
			nDst, nSrc = nDst+n, nSrc+i+1
			continue loop
		}
		if atEOF {
			return nDst, nSrc, errors.New("rleDecode: bad input")
		}
		return nDst, nSrc, ErrShortSrc
	}
	return nDst, nSrc, nil
}

type rleEncode struct {
	// allowStutter means that "xxxxxxxx" can be encoded as "5x3x"
	// instead of always as "8x".
	allowStutter bool
}

func (e rleEncode) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	for len(src) > 0 {
		n, c0 := len(src), src[0]
		for i, c := range src[1:] {
			if c != c0 {
				n = i + 1
				break
			}
		}
		if n == len(src) && !atEOF && !e.allowStutter {
			return nDst, nSrc, ErrShortSrc
		}
		s := strconv.Itoa(n)
		if len(s) >= len(dst) {
			return nDst, nSrc, ErrShortDst
		}
		copy(dst, s)
		dst[len(s)] = c0
		dst, src = dst[len(s)+1:], src[n:]
		nDst, nSrc = nDst+len(s)+1, nSrc+n
	}
	return nDst, nSrc, nil
}

type testCase struct {
	desc    string
	t       Transformer
	src     string
	dstSize int
	srcSize int
	wantStr string
	wantErr error
}

func (t testCase) String() string {
	return tstr(t.t) + "; " + t.desc
}

func tstr(t Transformer) string {
	if stringer, ok := t.(fmt.Stringer); ok {
		return stringer.String()
	}
	s := fmt.Sprintf("%T", t)
	return s[1+strings.Index(s, "."):]
}

var testCases = []testCase{
	{
		"basic",
		lowerCaseASCII{},
		"Hello WORLD.",
		100,
		100,
		"hello world.",
		nil,
	},

	{
		"small dst",
		lowerCaseASCII{},
		"Hello WORLD.",
		3,
		100,
		"hello world.",
		nil,
	},

	{
		"small src",
		lowerCaseASCII{},
		"Hello WORLD.",
		100,
		4,
		"hello world.",
		nil,
	},

	{
		"small buffers",
		lowerCaseASCII{},
		"Hello WORLD.",
		3,
		4,
		"hello world.",
		nil,
	},

	{
		"very small buffers",
		lowerCaseASCII{},
		"Hello WORLD.",
		1,
		1,
		"hello world.",
		nil,
	},

	{
		"basic",
		dontMentionX{},
		"The First Rule of Transform Club: don't mention Mister X, ever.",
		100,
		100,
		"The First Rule of Transform Club: don't mention Mister ",
		errYouMentionedX,
	},

	{
		"small buffers",
		dontMentionX{},
		"The First Rule of Transform Club: don't mention Mister X, ever.",
		10,
		10,
		"The First Rule of Transform Club: don't mention Mister ",
		errYouMentionedX,
	},

	{
		"very small buffers",
		dontMentionX{},
		"The First Rule of Transform Club: don't mention Mister X, ever.",
		1,
		1,
		"The First Rule of Transform Club: don't mention Mister ",
		errYouMentionedX,
	},

	{
		"basic",
		rleDecode{},
		"1a2b3c10d11e0f1g",
		100,
		100,
		"abbcccddddddddddeeeeeeeeeeeg",
		nil,
	},

	{
		"long",
		rleDecode{},
		"12a23b34c45d56e99z",
		100,
		100,
		strings.Repeat("a", 12) +
			strings.Repeat("b", 23) +
			strings.Repeat("c", 34) +
			strings.Repeat("d", 45) +
			strings.Repeat("e", 56) +
			strings.Repeat("z", 99),
		nil,
	},

	{
		"tight buffers",
		rleDecode{},
		"1a2b3c10d11e0f1g",
		11,
		3,
		"abbcccddddddddddeeeeeeeeeeeg",
		nil,
	},

	{
		"short dst",
		rleDecode{},
		"1a2b3c10d11e0f1g",
		10,
		3,
		"abbcccdddddddddd",
		ErrShortDst,
	},

	{
		"short src",
		rleDecode{},
		"1a2b3c10d11e0f1g",
		11,
		2,
		"abbccc",
		ErrShortSrc,
	},

	{
		"basic",
		rleEncode{},
		"abbcccddddddddddeeeeeeeeeeeg",
		100,
		100,
		"1a2b3c10d11e1g",
		nil,
	},

	{
		"long",
		rleEncode{},
		strings.Repeat("a", 12) +
			strings.Repeat("b", 23) +
			strings.Repeat("c", 34) +
			strings.Repeat("d", 45) +
			strings.Repeat("e", 56) +
			strings.Repeat("z", 99),
		100,
		100,
		"12a23b34c45d56e99z",
		nil,
	},

	{
		"tight buffers",
		rleEncode{},
		"abbcccddddddddddeeeeeeeeeeeg",
		3,
		12,
		"1a2b3c10d11e1g",
		nil,
	},

	{
		"short dst",
		rleEncode{},
		"abbcccddddddddddeeeeeeeeeeeg",
		2,
		12,
		"1a2b3c",
		ErrShortDst,
	},

	{
		"short src",
		rleEncode{},
		"abbcccddddddddddeeeeeeeeeeeg",
		3,
		11,
		"1a2b3c10d",
		ErrShortSrc,
	},

	{
		"allowStutter = false",
		rleEncode{allowStutter: false},
		"aaaabbbbbbbbccccddddd",
		10,
		10,
		"4a8b4c5d",
		nil,
	},

	{
		"allowStutter = true",
		rleEncode{allowStutter: true},
		"aaaabbbbbbbbccccddddd",
		10,
		10,
		"4a6b2b4c4d1d",
		nil,
	},
}

func TestReader(t *testing.T) {
	for _, tc := range testCases {
		r := NewReader(strings.NewReader(tc.src), tc.t)
		// Differently sized dst and src buffers are not part of the
		// exported API. We override them manually.
		r.dst = make([]byte, tc.dstSize)
		r.src = make([]byte, tc.srcSize)
		got, err := ioutil.ReadAll(r)
		str := string(got)
		if str != tc.wantStr || err != tc.wantErr {
			t.Errorf("%s:\ngot  %q, %v\nwant %q, %v", tc, str, err, tc.wantStr, tc.wantErr)
		}
	}
}
<|endoftext|>


<commit_before>package outputelastic

import (
	"github.com/Sirupsen/logrus"
	"github.com/tsaikd/gogstash/config"
	"github.com/tsaikd/gogstash/config/logevent"
	"golang.org/x/net/context"
	elastic "gopkg.in/olivere/elastic.v5"
)

// ModuleName is the name used in config file
const ModuleName = "elastic"

// OutputConfig holds the configuration json fields and internal objects
type OutputConfig struct {
	config.OutputConfig
	URL          string `json:"url"`           // elastic API entrypoint
	Index        string `json:"index"`         // index name to log
	DocumentType string `json:"document_type"` // type name to log
	DocumentID   string `json:"document_id"`   // id to log, used if you want to control id format

	Sniff bool `json:"sniff"` // find all nodes of your cluster, https://github.com/olivere/elastic/wiki/Sniffing

	client *elastic.Client // elastic client instance
}

// DefaultOutputConfig returns an OutputConfig struct with default values
func DefaultOutputConfig() OutputConfig {
	return OutputConfig{
		OutputConfig: config.OutputConfig{
			CommonConfig: config.CommonConfig{
				Type: ModuleName,
			},
		},
	}
}

// InitHandler initialize the output plugin
func InitHandler(confraw *config.ConfigRaw, logger *logrus.Logger) (retconf config.TypeOutputConfig, err error) {
	conf := DefaultOutputConfig()
	if err = config.ReflectConfig(confraw, &conf); err != nil {
		return
	}

	if conf.client, err = elastic.NewClient(
		elastic.SetURL(conf.URL),
		elastic.SetSniff(conf.Sniff),
	); err != nil {
		return
	}

	retconf = &conf
	return
}

func (t *OutputConfig) Event(event logevent.LogEvent) (err error) {
	index := event.Format(t.Index)
	doctype := event.Format(t.DocumentType)
	id := event.Format(t.DocumentID)

	_, err = t.client.Index().
		Index(index).
		Type(doctype).
		Id(id).
		BodyJson(event).
		Do(context.TODO())
	return
}
<commit_msg>output/elastic: index name should be lowercase<commit_after>package outputelastic

import (
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/tsaikd/gogstash/config"
	"github.com/tsaikd/gogstash/config/logevent"
	"golang.org/x/net/context"
	elastic "gopkg.in/olivere/elastic.v5"
)

// ModuleName is the name used in config file
const ModuleName = "elastic"

// OutputConfig holds the configuration json fields and internal objects
type OutputConfig struct {
	config.OutputConfig
	URL          string `json:"url"`           // elastic API entrypoint
	Index        string `json:"index"`         // index name to log
	DocumentType string `json:"document_type"` // type name to log
	DocumentID   string `json:"document_id"`   // id to log, used if you want to control id format

	Sniff bool `json:"sniff"` // find all nodes of your cluster, https://github.com/olivere/elastic/wiki/Sniffing

	client *elastic.Client // elastic client instance
}

// DefaultOutputConfig returns an OutputConfig struct with default values
func DefaultOutputConfig() OutputConfig {
	return OutputConfig{
		OutputConfig: config.OutputConfig{
			CommonConfig: config.CommonConfig{
				Type: ModuleName,
			},
		},
	}
}

// InitHandler initialize the output plugin
func InitHandler(confraw *config.ConfigRaw, logger *logrus.Logger) (retconf config.TypeOutputConfig, err error) {
	conf := DefaultOutputConfig()
	if err = config.ReflectConfig(confraw, &conf); err != nil {
		return
	}

	if conf.client, err = elastic.NewClient(
		elastic.SetURL(conf.URL),
		elastic.SetSniff(conf.Sniff),
	); err != nil {
		return
	}

	retconf = &conf
	return
}

func (t *OutputConfig) Event(event logevent.LogEvent) (err error) {
	index := event.Format(t.Index)
	// elastic index name should be lowercase
	index = strings.ToLower(index)
	doctype := event.Format(t.DocumentType)
	id := event.Format(t.DocumentID)

	_, err = t.client.Index().
		Index(index).
		Type(doctype).
		Id(id).
		BodyJson(event).
		Do(context.TODO())
	return
}
<|endoftext|>