<commit_before>//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//

package test

import (
	"context"
	"testing"

	driver "github.com/arangodb/go-driver"
)

// TestCreateFullTextIndex creates a collection with a full text index.
func TestIndexes(t *testing.T) {
	c := createClientFromEnv(t, true)
	db := ensureDatabase(nil, c, "index_test", nil, t)
	col := ensureCollection(nil, db, "indexes_test", nil, t)

	// Create some indexes
	if _, _, err := col.EnsureFullTextIndex(nil, []string{"name"}, nil); err != nil {
		t.Fatalf("Failed to create new index: %s", describe(err))
	}
	if _, _, err := col.EnsureHashIndex(nil, []string{"age", "gender"}, nil); err != nil {
		t.Fatalf("Failed to create new index: %s", describe(err))
	}

	// Get list of indexes
	if idxs, err := col.Indexes(context.Background()); err != nil {
		t.Fatalf("Failed to get indexes: %s", describe(err))
	} else {
		if len(idxs) != 3 {
			// We made 2 indexes, 1 is always added by the system
			t.Errorf("Expected 3 indexes, got %d", len(idxs))
		}

		// Try opening the indexes 1 by 1
		for _, x := range idxs {
			if idx, err := col.Index(nil, x.Name()); err != nil {
				t.Errorf("Failed to open index '%s': %s", x.Name(), describe(err))
			} else if idx.Name() != x.Name() {
				t.Errorf("Got different index name. Expected '%s', got '%s'", x.Name(), idx.Name())
			}
		}
	}

	// Check index count
	if stats, err := col.Statistics(nil); err != nil {
		t.Fatalf("Statistics failed: %s", describe(err))
	} else if stats.Figures.Indexes.Count != 3 {
		// 3 because 1 system index + 2 created above
		t.Errorf("Expected 3 indexes, got %d", stats.Figures.Indexes.Count)
	}
}

// TestIndexesDeduplicateHash tests no-deduplicate on hash index.
func TestIndexesDeduplicateHash(t *testing.T) {
	c := createClientFromEnv(t, true)
	version, err := c.Version(nil)
	if err != nil {
		t.Fatalf("Version failed: %s", describe(err))
	}
	isv32p := version.Version.CompareTo("3.2") >= 0
	if !isv32p {
		t.Skip("Test requires 3.2")
	} else {
		db := ensureDatabase(nil, c, "index_test", nil, t)

		{
			// Create some indexes with de-duplication off
			col := ensureCollection(nil, db, "indexes_hash_deduplicate_false_test", nil, t)
			if _, _, err := col.EnsureHashIndex(nil, []string{"tags[*]"}, &driver.EnsureHashIndexOptions{
				Unique:        true,
				Sparse:        false,
				NoDeduplicate: true,
			}); err != nil {
				t.Fatalf("Failed to create new index: %s", describe(err))
			}

			doc := struct {
				Tags []string `json:"tags"`
			}{
				Tags: []string{"a", "a", "b"},
			}
			if _, err := col.CreateDocument(nil, doc); !driver.IsConflict(err) {
				t.Errorf("Expected Conflict error, got %s", describe(err))
			}
		}

		{
			// Create some indexes with de-duplication on
			col := ensureCollection(nil, db, "indexes_hash_deduplicate_true_test", nil, t)
			if _, _, err := col.EnsureHashIndex(nil, []string{"tags"}, &driver.EnsureHashIndexOptions{
				Unique:        true,
				Sparse:        false,
				NoDeduplicate: false,
			}); err != nil {
				t.Fatalf("Failed to create new index: %s", describe(err))
			}

			doc := struct {
				Tags []string `json:"tags"`
			}{
				Tags: []string{"a", "a", "b"},
			}
			if _, err := col.CreateDocument(nil, doc); err != nil {
				t.Errorf("Expected success, got %s", describe(err))
			}
		}
	}
}

// TestIndexesDeduplicateSkipList tests no-deduplicate on skiplist index.
func TestIndexesDeduplicateSkipList(t *testing.T) {
	c := createClientFromEnv(t, true)
	version, err := c.Version(nil)
	if err != nil {
		t.Fatalf("Version failed: %s", describe(err))
	}
	isv32p := version.Version.CompareTo("3.2") >= 0
	if !isv32p {
		t.Skip("Test requires 3.2")
	} else {
		db := ensureDatabase(nil, c, "index_test", nil, t)

		{
			// Create some indexes with de-duplication off
			col := ensureCollection(nil, db, "indexes_skiplist_deduplicate_false_test", nil, t)
			if _, _, err := col.EnsureSkipListIndex(nil, []string{"tags[*]"}, &driver.EnsureSkipListIndexOptions{
				Unique:        true,
				Sparse:        false,
				NoDeduplicate: true,
			}); err != nil {
				t.Fatalf("Failed to create new index: %s", describe(err))
			}

			doc := struct {
				Tags []string `json:"tags"`
			}{
				Tags: []string{"a", "a", "b"},
			}
			if _, err := col.CreateDocument(nil, doc); !driver.IsConflict(err) {
				t.Errorf("Expected Conflict error, got %s", describe(err))
			}
		}

		{
			// Create some indexes with de-duplication on
			col := ensureCollection(nil, db, "indexes_skiplist_deduplicate_true_test", nil, t)
			if _, _, err := col.EnsureSkipListIndex(nil, []string{"tags"}, &driver.EnsureSkipListIndexOptions{
				Unique:        true,
				Sparse:        false,
				NoDeduplicate: false,
			}); err != nil {
				t.Fatalf("Failed to create new index: %s", describe(err))
			}

			doc := struct {
				Tags []string `json:"tags"`
			}{
				Tags: []string{"a", "a", "b"},
			}
			if _, err := col.CreateDocument(nil, doc); err != nil {
				t.Errorf("Expected success, got %s", describe(err))
			}
		}
	}
}
<commit_msg>Added test for multiple fulltext indexes with same fields but different options<commit_after>//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//

package test

import (
	"context"
	"testing"

	driver "github.com/arangodb/go-driver"
)

// TestCreateFullTextIndex creates a collection with a full text index.
func TestIndexes(t *testing.T) {
	c := createClientFromEnv(t, true)
	db := ensureDatabase(nil, c, "index_test", nil, t)
	col := ensureCollection(nil, db, "indexes_test", nil, t)

	// Create some indexes
	if _, _, err := col.EnsureFullTextIndex(nil, []string{"name"}, nil); err != nil {
		t.Fatalf("Failed to create new index: %s", describe(err))
	}
	if _, _, err := col.EnsureHashIndex(nil, []string{"age", "gender"}, nil); err != nil {
		t.Fatalf("Failed to create new index: %s", describe(err))
	}

	// Get list of indexes
	if idxs, err := col.Indexes(context.Background()); err != nil {
		t.Fatalf("Failed to get indexes: %s", describe(err))
	} else {
		if len(idxs) != 3 {
			// We made 2 indexes, 1 is always added by the system
			t.Errorf("Expected 3 indexes, got %d", len(idxs))
		}

		// Try opening the indexes 1 by 1
		for _, x := range idxs {
			if idx, err := col.Index(nil, x.Name()); err != nil {
				t.Errorf("Failed to open index '%s': %s", x.Name(), describe(err))
			} else if idx.Name() != x.Name() {
				t.Errorf("Got different index name. Expected '%s', got '%s'", x.Name(), idx.Name())
			}
		}
	}

	// Check index count
	if stats, err := col.Statistics(nil); err != nil {
		t.Fatalf("Statistics failed: %s", describe(err))
	} else if stats.Figures.Indexes.Count != 3 {
		// 3 because 1 system index + 2 created above
		t.Errorf("Expected 3 indexes, got %d", stats.Figures.Indexes.Count)
	}
}

// TestMultipleIndexes creates a collection with a full text index.
func TestMultipleIndexes(t *testing.T) {
	c := createClientFromEnv(t, true)
	db := ensureDatabase(nil, c, "index_test", nil, t)
	col := ensureCollection(nil, db, "multiple_indexes_test", nil, t)

	// Create some indexes of same type & fields, but different options
	if _, _, err := col.EnsureFullTextIndex(nil, []string{"name"}, &driver.EnsureFullTextIndexOptions{MinLength: 2}); err != nil {
		t.Fatalf("Failed to create new index (1): %s", describe(err))
	}
	if _, _, err := col.EnsureFullTextIndex(nil, []string{"name"}, &driver.EnsureFullTextIndexOptions{MinLength: 7}); err != nil {
		t.Fatalf("Failed to create new index (2): %s", describe(err))
	}

	// Get list of indexes
	if idxs, err := col.Indexes(context.Background()); err != nil {
		t.Fatalf("Failed to get indexes: %s", describe(err))
	} else {
		if len(idxs) != 3 {
			// We made 2 indexes, 1 is always added by the system
			t.Errorf("Expected 3 indexes, got %d", len(idxs))
		}

		// Try opening the indexes 1 by 1
		for _, x := range idxs {
			if idx, err := col.Index(nil, x.Name()); err != nil {
				t.Errorf("Failed to open index '%s': %s", x.Name(), describe(err))
			} else if idx.Name() != x.Name() {
				t.Errorf("Got different index name. Expected '%s', got '%s'", x.Name(), idx.Name())
			}
		}
	}

	// Check index count
	if stats, err := col.Statistics(nil); err != nil {
		t.Fatalf("Statistics failed: %s", describe(err))
	} else if stats.Figures.Indexes.Count != 3 {
		// 3 because 1 system index + 2 created above
		t.Errorf("Expected 3 indexes, got %d", stats.Figures.Indexes.Count)
	}
}

// TestIndexesDeduplicateHash tests no-deduplicate on hash index.
func TestIndexesDeduplicateHash(t *testing.T) {
	c := createClientFromEnv(t, true)
	version, err := c.Version(nil)
	if err != nil {
		t.Fatalf("Version failed: %s", describe(err))
	}
	isv32p := version.Version.CompareTo("3.2") >= 0
	if !isv32p {
		t.Skip("Test requires 3.2")
	} else {
		db := ensureDatabase(nil, c, "index_test", nil, t)

		{
			// Create some indexes with de-duplication off
			col := ensureCollection(nil, db, "indexes_hash_deduplicate_false_test", nil, t)
			if _, _, err := col.EnsureHashIndex(nil, []string{"tags[*]"}, &driver.EnsureHashIndexOptions{
				Unique:        true,
				Sparse:        false,
				NoDeduplicate: true,
			}); err != nil {
				t.Fatalf("Failed to create new index: %s", describe(err))
			}

			doc := struct {
				Tags []string `json:"tags"`
			}{
				Tags: []string{"a", "a", "b"},
			}
			if _, err := col.CreateDocument(nil, doc); !driver.IsConflict(err) {
				t.Errorf("Expected Conflict error, got %s", describe(err))
			}
		}

		{
			// Create some indexes with de-duplication on
			col := ensureCollection(nil, db, "indexes_hash_deduplicate_true_test", nil, t)
			if _, _, err := col.EnsureHashIndex(nil, []string{"tags"}, &driver.EnsureHashIndexOptions{
				Unique:        true,
				Sparse:        false,
				NoDeduplicate: false,
			}); err != nil {
				t.Fatalf("Failed to create new index: %s", describe(err))
			}

			doc := struct {
				Tags []string `json:"tags"`
			}{
				Tags: []string{"a", "a", "b"},
			}
			if _, err := col.CreateDocument(nil, doc); err != nil {
				t.Errorf("Expected success, got %s", describe(err))
			}
		}
	}
}

// TestIndexesDeduplicateSkipList tests no-deduplicate on skiplist index.
func TestIndexesDeduplicateSkipList(t *testing.T) {
	c := createClientFromEnv(t, true)
	version, err := c.Version(nil)
	if err != nil {
		t.Fatalf("Version failed: %s", describe(err))
	}
	isv32p := version.Version.CompareTo("3.2") >= 0
	if !isv32p {
		t.Skip("Test requires 3.2")
	} else {
		db := ensureDatabase(nil, c, "index_test", nil, t)

		{
			// Create some indexes with de-duplication off
			col := ensureCollection(nil, db, "indexes_skiplist_deduplicate_false_test", nil, t)
			if _, _, err := col.EnsureSkipListIndex(nil, []string{"tags[*]"}, &driver.EnsureSkipListIndexOptions{
				Unique:        true,
				Sparse:        false,
				NoDeduplicate: true,
			}); err != nil {
				t.Fatalf("Failed to create new index: %s", describe(err))
			}

			doc := struct {
				Tags []string `json:"tags"`
			}{
				Tags: []string{"a", "a", "b"},
			}
			if _, err := col.CreateDocument(nil, doc); !driver.IsConflict(err) {
				t.Errorf("Expected Conflict error, got %s", describe(err))
			}
		}

		{
			// Create some indexes with de-duplication on
			col := ensureCollection(nil, db, "indexes_skiplist_deduplicate_true_test", nil, t)
			if _, _, err := col.EnsureSkipListIndex(nil, []string{"tags"}, &driver.EnsureSkipListIndexOptions{
				Unique:        true,
				Sparse:        false,
				NoDeduplicate: false,
			}); err != nil {
				t.Fatalf("Failed to create new index: %s", describe(err))
			}

			doc := struct {
				Tags []string `json:"tags"`
			}{
				Tags: []string{"a", "a", "b"},
			}
			if _, err := col.CreateDocument(nil, doc); err != nil {
				t.Errorf("Expected success, got %s", describe(err))
			}
		}
	}
}
<|endoftext|>


<commit_before>package gossl

/*
#include "openssl/ssl.h"
#include <pthread.h>

#cgo pkg-config: openssl

static pthread_mutex_t *lock_cs;
static long *lock_count;
unsigned long pthreads_thread_id(void)
	{
	unsigned long ret;

	ret=(unsigned long)pthread_self();
	return(ret);
	}

void pthreads_locking_callback(int mode, int type, char *file,
	     int line)
      {
	if (mode & CRYPTO_LOCK)
		{
		pthread_mutex_lock(&(lock_cs[type]));
		lock_count[type]++;
		}
	else
		{
		pthread_mutex_unlock(&(lock_cs[type]));
		}
	}
void thread_setup(void)
	{
	int i;

	lock_cs=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
	lock_count=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
	for (i=0; i<CRYPTO_num_locks(); i++)
		{
		lock_count[i]=0;
		pthread_mutex_init(&(lock_cs[i]),NULL);
		}

	CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);
	CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);
	}
int GoSSLInitializeThreads() {
 thread_setup();
 return 1;
}
*/
import "C"

var sslThreadsInitialized = C.GoSSLInitializeThreads()
<commit_msg>threads.go: wraps threads initialization in init()<commit_after>package gossl

/*
#include <openssl/ssl.h>
#include <pthread.h>
#cgo pkg-config: openssl

static pthread_mutex_t *lock_cs;
static long *lock_count;

unsigned long pthreads_thread_id(void)
{
	unsigned long ret;

	ret = (unsigned long)pthread_self();
	return ret;
}

void pthreads_locking_callback(int mode, int type, char *file,
int line)
{
	if (mode & CRYPTO_LOCK) {
		pthread_mutex_lock(&(lock_cs[type]));
		lock_count[type]++;
	} else {
		pthread_mutex_unlock(&(lock_cs[type]));
	}
}

void thread_setup(void)
{
	int i;

	lock_cs=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
	lock_count=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
	for (i=0; i<CRYPTO_num_locks(); i++)
	{
		lock_count[i]=0;
		pthread_mutex_init(&(lock_cs[i]),NULL);
	}

	CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);
	CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);
}

void GoSSLInitializeThreads()
{
	thread_setup();
}
*/
import "C"

func init() {
	C.GoSSLInitializeThreads()
}
<|endoftext|>


<commit_before>/*
Copyright 2017 WALLIX

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 aws

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

	awssdk "github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/wallix/awless/aws/config"
	"github.com/wallix/awless/cloud"
	"github.com/wallix/awless/logger"
	"github.com/wallix/awless/template/driver"
)

var (
	AccessService, InfraService, StorageService, NotificationService, QueueService, DnsService, LambdaService, MonitoringService, CdnService, CloudformationService cloud.Service
)

func InitServices(conf map[string]interface{}, log *logger.Logger) error {
	awsconf := config(conf)
	region := awsconf.region()
	if region == "" {
		return errors.New("empty AWS region. Set it with `awless config set aws.region`")
	}

	sess, err := initAWSSession(region, awsconf.profile())
	if err != nil {
		return err
	}

	AccessService = NewAccess(sess, awsconf, log)
	InfraService = NewInfra(sess, awsconf, log)
	StorageService = NewStorage(sess, awsconf, log)
	NotificationService = NewNotification(sess, awsconf, log)
	QueueService = NewQueue(sess, awsconf, log)
	DnsService = NewDns(sess, awsconf, log)
	LambdaService = NewLambda(sess, awsconf, log)
	MonitoringService = NewMonitoring(sess, awsconf, log)
	CdnService = NewCdn(sess, awsconf, log)
	CloudformationService = NewCloudformation(sess, awsconf, log)

	cloud.ServiceRegistry[InfraService.Name()] = InfraService
	cloud.ServiceRegistry[AccessService.Name()] = AccessService
	cloud.ServiceRegistry[StorageService.Name()] = StorageService
	cloud.ServiceRegistry[NotificationService.Name()] = NotificationService
	cloud.ServiceRegistry[QueueService.Name()] = QueueService
	cloud.ServiceRegistry[DnsService.Name()] = DnsService
	cloud.ServiceRegistry[LambdaService.Name()] = LambdaService
	cloud.ServiceRegistry[MonitoringService.Name()] = MonitoringService
	cloud.ServiceRegistry[CdnService.Name()] = CdnService
	cloud.ServiceRegistry[CloudformationService.Name()] = CloudformationService

	return nil
}

func NewDriver(region, profile string, log ...*logger.Logger) (driver.Driver, error) {
	if !awsconfig.IsValidRegion(region) {
		return nil, fmt.Errorf("invalid region '%s' provided", region)
	}

	sess, err := initAWSSession(region, profile)
	if err != nil {
		return nil, err
	}

	drivLog := logger.DiscardLogger
	if len(log) > 0 {
		drivLog = log[0]
	}

	awsconf := config(
		map[string]interface{}{"aws.region": region, "aws.profile": profile},
	)

	var drivers []driver.Driver
	drivers = append(drivers, NewAccess(sess, awsconf, drivLog).Drivers()...)
	drivers = append(drivers, NewInfra(sess, awsconf, drivLog).Drivers()...)
	drivers = append(drivers, NewStorage(sess, awsconf, drivLog).Drivers()...)
	drivers = append(drivers, NewNotification(sess, awsconf, drivLog).Drivers()...)
	drivers = append(drivers, NewQueue(sess, awsconf, drivLog).Drivers()...)
	drivers = append(drivers, NewDns(sess, awsconf, drivLog).Drivers()...)
	drivers = append(drivers, NewLambda(sess, awsconf, drivLog).Drivers()...)
	drivers = append(drivers, NewMonitoring(sess, awsconf, drivLog).Drivers()...)
	drivers = append(drivers, NewCdn(sess, awsconf, drivLog).Drivers()...)
	drivers = append(drivers, NewCloudformation(sess, awsconf, drivLog).Drivers()...)

	return driver.NewMultiDriver(drivers...), nil
}

func initAWSSession(region, profile string) (*session.Session, error) {
	session, err := session.NewSessionWithOptions(session.Options{
		Config:                  awssdk.Config{Region: awssdk.String(region), HTTPClient: &http.Client{Timeout: 2 * time.Second}},
		SharedConfigState:       session.SharedConfigEnable,
		AssumeRoleTokenProvider: stscreds.StdinTokenProvider,
		Profile:                 profile,
	})
	//session.Config = session.Config.WithLogLevel(awssdk.LogDebugWithHTTPBody)
	if err != nil {
		return nil, err
	}

	if _, err = session.Config.Credentials.Get(); err != nil {
		return nil, errors.New("Your AWS credentials seem undefined! AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY need to be exported in your CLI environment\nInstallation documentation is at https://github.com/wallix/awless/wiki/Installation")
	}
	session.Config.HTTPClient = http.DefaultClient

	return session, nil
}
<commit_msg>Removing suprinsigly unused method in init process<commit_after>/*
Copyright 2017 WALLIX

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 aws

import (
	"errors"
	"net/http"
	"time"

	awssdk "github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/wallix/awless/cloud"
	"github.com/wallix/awless/logger"
)

var (
	AccessService, InfraService, StorageService, NotificationService, QueueService, DnsService, LambdaService, MonitoringService, CdnService, CloudformationService cloud.Service
)

func InitServices(conf map[string]interface{}, log *logger.Logger) error {
	awsconf := config(conf)
	region := awsconf.region()
	if region == "" {
		return errors.New("empty AWS region. Set it with `awless config set aws.region`")
	}

	sess, err := initAWSSession(region, awsconf.profile())
	if err != nil {
		return err
	}

	AccessService = NewAccess(sess, awsconf, log)
	InfraService = NewInfra(sess, awsconf, log)
	StorageService = NewStorage(sess, awsconf, log)
	NotificationService = NewNotification(sess, awsconf, log)
	QueueService = NewQueue(sess, awsconf, log)
	DnsService = NewDns(sess, awsconf, log)
	LambdaService = NewLambda(sess, awsconf, log)
	MonitoringService = NewMonitoring(sess, awsconf, log)
	CdnService = NewCdn(sess, awsconf, log)
	CloudformationService = NewCloudformation(sess, awsconf, log)

	cloud.ServiceRegistry[InfraService.Name()] = InfraService
	cloud.ServiceRegistry[AccessService.Name()] = AccessService
	cloud.ServiceRegistry[StorageService.Name()] = StorageService
	cloud.ServiceRegistry[NotificationService.Name()] = NotificationService
	cloud.ServiceRegistry[QueueService.Name()] = QueueService
	cloud.ServiceRegistry[DnsService.Name()] = DnsService
	cloud.ServiceRegistry[LambdaService.Name()] = LambdaService
	cloud.ServiceRegistry[MonitoringService.Name()] = MonitoringService
	cloud.ServiceRegistry[CdnService.Name()] = CdnService
	cloud.ServiceRegistry[CloudformationService.Name()] = CloudformationService

	return nil
}

func initAWSSession(region, profile string) (*session.Session, error) {
	session, err := session.NewSessionWithOptions(session.Options{
		Config:                  awssdk.Config{Region: awssdk.String(region), HTTPClient: &http.Client{Timeout: 2 * time.Second}},
		SharedConfigState:       session.SharedConfigEnable,
		AssumeRoleTokenProvider: stscreds.StdinTokenProvider,
		Profile:                 profile,
	})
	//session.Config = session.Config.WithLogLevel(awssdk.LogDebugWithHTTPBody)
	if err != nil {
		return nil, err
	}

	if _, err = session.Config.Credentials.Get(); err != nil {
		return nil, errors.New("Your AWS credentials seem undefined! AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY need to be exported in your CLI environment\nInstallation documentation is at https://github.com/wallix/awless/wiki/Installation")
	}
	session.Config.HTTPClient = http.DefaultClient

	return session, nil
}
<|endoftext|>


<commit_before>// Brunobot notifies a Discord channel when Professional Dota 2 games are live.
// This should be run via cron every minute to ensure only one notification.
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"

	log "github.com/sirupsen/logrus"

	"github.com/jasonodonnell/BrunoBot/discord"
	"github.com/jasonodonnell/BrunoBot/dota"
)

type configuration struct {
	Teams     []string
	Webhook   string
	Whitelist bool
}

func usage() {
	log.Fatal("Usage: brunobot --config=/path/to/config.json")
}

// Webhook must be set in configuration
func parseConfiguration(path string) (config configuration, err error) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	defer file.Close()

	decoder := json.NewDecoder(file)
	err = decoder.Decode(&config)
	if err != nil {
		return
	}

	if config.Webhook == "" {
		err = fmt.Errorf("Webhook is not set")
		return
	}
	return
}

func main() {
	configFile := flag.String("config", "", "Configuration file")
	flag.Parse()
	if *configFile == "" {
		log.Error("Configuration file not found. Exiting..")
		usage()
	}

	configuration, err := parseConfiguration(*configFile)
	if err != nil {
		log.Error("Error reading configuration file: %s", err)
		usage()
	}

	httpClient := &http.Client{}
	client, err := dota.New(configuration.Teams, httpClient)
	if err != nil {
		log.Fatal(err)
	}

	matches, err := client.GetMatches()
	if err != nil {
		log.Fatal(err)
	}

	for _, match := range matches {
		format := "%s: %s vs %s :: Post Game Results - https://www.opendota.com/matches/%d"
		notification := fmt.Sprintf(format, match.League, match.Radiant, match.Dire, match.MatchID)
		if err := discord.Send(notification, configuration.Webhook); err != nil {
			log.Fatal(err)
		}
	}
}
<commit_msg>Fix log error<commit_after>// Brunobot notifies a Discord channel when Professional Dota 2 games are live.
// This should be run via cron every minute to ensure only one notification.
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"

	log "github.com/sirupsen/logrus"

	"github.com/jasonodonnell/BrunoBot/discord"
	"github.com/jasonodonnell/BrunoBot/dota"
)

type configuration struct {
	Teams     []string
	Webhook   string
	Whitelist bool
}

func usage() {
	log.Fatal("Usage: brunobot --config=/path/to/config.json")
}

// Webhook must be set in configuration
func parseConfiguration(path string) (config configuration, err error) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	defer file.Close()

	decoder := json.NewDecoder(file)
	err = decoder.Decode(&config)
	if err != nil {
		return
	}

	if config.Webhook == "" {
		err = fmt.Errorf("Webhook is not set")
		return
	}
	return
}

func main() {
	configFile := flag.String("config", "", "Configuration file")
	flag.Parse()
	if *configFile == "" {
		log.Error("Configuration file not found. Exiting..")
		usage()
	}

	configuration, err := parseConfiguration(*configFile)
	if err != nil {
		log.Errorf("Error reading configuration file: %s", err)
		usage()
	}

	httpClient := &http.Client{}
	client, err := dota.New(configuration.Teams, httpClient)
	if err != nil {
		log.Fatal(err)
	}

	matches, err := client.GetMatches()
	if err != nil {
		log.Fatal(err)
	}

	for _, match := range matches {
		format := "%s: %s vs %s :: Post Game Results - https://www.opendota.com/matches/%d"
		notification := fmt.Sprintf(format, match.League, match.Radiant, match.Dire, match.MatchID)
		if err := discord.Send(notification, configuration.Webhook); err != nil {
			log.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>package gnat

import (
	"bytes"
	"errors"
	"math"
	"math/big"
	"math/rand"
	"net"
	"sort"
	"strconv"
	"sync"
	"time"
)

const (
	iterateFindNode = iota
)

const (
	// a small number representing the degree of parallelism in network calls
	alpha = 3

	// the size in bits of the keys used to identify nodes and store and
	// retrieve data; this is 256, the length of a SHA256
	b = 256

	// the maximum number of contacts stored in a bucket
	k = 32
)

// hashTable represents the hashtable state
type hashTable struct {
	// The ID of the local node
	Self *NetworkNode

	// Routing table a list of all known nodes in the network
	// Nodes within buckets are sorted by least recently seen e.g.
	// [ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
	//  ^                                                           ^
	//  └ Least recently seen                    Most recently seen ┘
	RoutingTable [][]*node // 256x32

	mutex *sync.Mutex

	refreshMap [b]time.Time
}

func newHashTable(options *Options) (*hashTable, error) {
	ht := &hashTable{}

	rand.Seed(time.Now().UnixNano())

	ht.mutex = &sync.Mutex{}
	ht.Self = &NetworkNode{}

	if options.ID != nil {
		if len(options.ID) != b {
			return nil, errors.New("error: invalid key size " + string(len(options.ID)))
		}
		ht.Self.ID = options.ID
	} else {
		id, err := newID()
		if err != nil {
			return nil, err
		}
		ht.Self.ID = id
	}

	if options.IP == "" || options.Port == "" {
		return nil, errors.New("Port and IP required")
	}

	err := ht.setSelfAddr(options.IP, options.Port)
	if err != nil {
		return nil, err
	}

	for i := 0; i < b; i++ {
		ht.resetRefreshTimeForBucket(i)
	}

	for i := 0; i < b; i++ {
		ht.RoutingTable = append(ht.RoutingTable, []*node{})
	}

	return ht, nil
}

func (ht *hashTable) setSelfAddr(ip string, port string) error {
	ht.Self.IP = net.ParseIP(ip)
	p, err := strconv.Atoi(port)
	if err != nil {
		return err
	}
	ht.Self.Port = p
	return nil
}

func (ht *hashTable) resetRefreshTimeForBucket(bucket int) {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()
	ht.refreshMap[bucket] = time.Now()
}

func (ht *hashTable) getRefreshTimeForBucket(bucket int) time.Time {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()
	return ht.refreshMap[bucket]
}

func (ht *hashTable) markNodeAsSeen(node []byte) {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()
	index := getBucketIndexFromDifferingBit(ht.Self.ID, node)
	bucket := ht.RoutingTable[index]
	nodeIndex := -1
	for i, v := range bucket {
		if bytes.Compare(v.ID, node) == 0 {
			nodeIndex = i
			break
		}
	}
	if nodeIndex == -1 {
		panic(errors.New("Tried to mark nonexistent node as seen"))
	}

	n := bucket[nodeIndex]
	bucket = append(bucket[:nodeIndex], bucket[nodeIndex+1:]...)
	bucket = append(bucket, n)
	ht.RoutingTable[index] = bucket
}

func (ht *hashTable) doesNodeExistInBucket(bucket int, node []byte) bool {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()
	for _, v := range ht.RoutingTable[bucket] {
		if bytes.Compare(v.ID, node) == 0 {
			return true
		}
	}
	return false
}

func (ht *hashTable) getClosestContacts(num int, target []byte, ignoredNodes []*NetworkNode) *shortList {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()
	// First we need to build the list of adjacent indices to our target
	// in order
	index := getBucketIndexFromDifferingBit(ht.Self.ID, target)
	indexList := []int{index}
	i := index - 1
	j := index + 1
	for len(indexList) < b {
		if j < b {
			indexList = append(indexList, j)
		}
		if i >= 0 {
			indexList = append(indexList, i)
		}
		i--
		j++
	}

	sl := &shortList{}

	leftToAdd := num

	// Next we select alpha contacts and add them to the short list
	for leftToAdd > 0 && len(indexList) > 0 {
		index, indexList = indexList[0], indexList[1:]
		bucketContacts := len(ht.RoutingTable[index])
		for i := 0; i < bucketContacts; i++ {
			ignored := false
			for j := 0; j < len(ignoredNodes); j++ {
				if bytes.Compare(ht.RoutingTable[index][i].ID, ignoredNodes[j].ID) == 0 {
					ignored = true
				}
			}
			if !ignored {
				sl.AppendUnique([]*node{ht.RoutingTable[index][i]})
				leftToAdd--
				if leftToAdd == 0 {
					break
				}
			}
		}
	}

	sort.Sort(sl)

	return sl
}

func (ht *hashTable) removeNode(ID []byte) {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()

	index := getBucketIndexFromDifferingBit(ht.Self.ID, ID)
	bucket := ht.RoutingTable[index]

	for i, v := range bucket {
		if bytes.Compare(v.ID, ID) == 0 {
			bucket = append(bucket[:i], bucket[i+1:]...)
		}
	}

	ht.RoutingTable[index] = bucket
}

func (ht *hashTable) getAllNodesInBucketCloserThan(bucket int, id []byte) [][]byte {
	b := ht.RoutingTable[bucket]
	var nodes [][]byte
	for _, v := range b {
		d1 := ht.getDistance(id, ht.Self.ID)
		d2 := ht.getDistance(id, v.ID)

		result := big.NewInt(0)
		result.Sub(d1, d2)
		if result.Sign() > -1 {
			nodes = append(nodes, v.ID)
		}
	}

	return nodes
}

func (ht *hashTable) getCloserNode(node1 *NetworkNode, node2 *NetworkNode, id []byte) *NetworkNode {

	d1 := ht.getDistance(id, node1.ID)
	d2 := ht.getDistance(id, node2.ID)
	result := big.NewInt(0)
	result.Sub(d1, d2)
	if result.Sign() <= 0 {
		return node1
	}

	return node2
}

func (ht *hashTable) getTotalNodesInBucket(bucket int) int {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()
	return len(ht.RoutingTable[bucket])
}

func (ht *hashTable) getDistance(id1 []byte, id2 []byte) *big.Int {
	var dst [k]byte
	for i := 0; i < k; i++ {
		dst[i] = id1[i] ^ id2[i]
	}
	ret := big.NewInt(0)
	return ret.SetBytes(dst[:])
}

func (ht *hashTable) getRandomIDFromBucket(bucket int) []byte {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()

	// Set the new ID to to be equal in every byte up to
	// the byte of the first differing bit in the bucket

	byteIndex := bucket / 8
	var id []byte
	for i := 0; i < byteIndex; i++ {
		id = append(id, ht.Self.ID[i])
	}
	differingBitStart := bucket % 8

	var firstByte byte
	// check each bit from left to right in order
	for i := 0; i < 8; i++ {
		// Set the value of the bit to be the same as the ID
		// up to the differing bit. Then begin randomizing
		var bit bool
		if i < differingBitStart {
			bit = hasBit(ht.Self.ID[byteIndex], uint(i))
		} else {
			bit = rand.Intn(2) == 1
		}

		if bit {
			firstByte += byte(math.Pow(2, float64(7-i)))
		}
	}

	id = append(id, firstByte)

	// Randomize each remaining byte
	for i := byteIndex + 1; i < 32; i++ {
		randomByte := byte(rand.Intn(256))
		id = append(id, randomByte)
	}

	return id
}

func getBucketIndexFromDifferingBit(id1 []byte, id2 []byte) int {
	// Look at each byte from left to right
	for j := 0; j < len(id1); j++ {
		// xor the byte
		xor := id1[j] ^ id2[j]

		// check each bit on the xored result from left to right in order
		for i := 0; i < 8; i++ {
			if hasBit(xor, uint(i)) {
				byteIndex := j * 8
				bitIndex := i
				return b - (byteIndex + bitIndex) - 1
			}
		}
	}

	// the ids must be the same
	// this should only happen during bootstrapping
	return 0
}

func (ht *hashTable) totalNodes() int {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()
	var total int
	for _, v := range ht.RoutingTable {
		total += len(v)
	}
	return total
}

// newID generates a new random ID
func newID() ([]byte, error) {
	result := make([]byte, 32)
	_, err := rand.Read(result)
	return result, err
}

// Simple helper function to determine the value of a particular
// bit in a byte by index

// Example:
// number:  1
// bits:    00000001
// pos:     01234567
func hasBit(n byte, pos uint) bool {
	pos = 7 - pos
	val := n & (1 << pos)
	return (val > 0)
}
<commit_msg>rephrase<commit_after>package gnat

import (
	"bytes"
	"errors"
	"math"
	"math/big"
	"math/rand"
	"net"
	"sort"
	"strconv"
	"sync"
	"time"
)

const (
	iterateFindNode = iota
)

const (
	// a small number representing the degree of parallelism in network calls
	alpha = 3

	// the size in bits of the keys used to identify nodes and store and
	// retrieve data; this is 256, the length of a SHA256
	b = 256

	// the maximum number of contacts stored in a bucket
	k = 32
)

// hashTable represents the hashtable state
type hashTable struct {
	// The ID of the local node
	Self *NetworkNode

	// Routing table a list of all known nodes in the network
	// Nodes within buckets are sorted by least recently seen e.g.
	// [ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
	//  ^                                                           ^
	//  └ Least recently seen                    Most recently seen ┘
	RoutingTable [][]*node // 256x32

	mutex *sync.Mutex

	refreshMap [b]time.Time
}

func newHashTable(options *Options) (*hashTable, error) {
	ht := &hashTable{}

	rand.Seed(time.Now().UnixNano())

	ht.mutex = &sync.Mutex{}
	ht.Self = &NetworkNode{}

	if options.ID != nil {
		if len(options.ID) != b {
			return nil, errors.New("error: invalid node ID size " + string(len(options.ID)))
		}
		ht.Self.ID = options.ID
	} else {
		id, err := newID()
		if err != nil {
			return nil, err
		}
		ht.Self.ID = id
	}

	if options.IP == "" || options.Port == "" {
		return nil, errors.New("Port and IP required")
	}

	err := ht.setSelfAddr(options.IP, options.Port)
	if err != nil {
		return nil, err
	}

	for i := 0; i < b; i++ {
		ht.resetRefreshTimeForBucket(i)
	}

	for i := 0; i < b; i++ {
		ht.RoutingTable = append(ht.RoutingTable, []*node{})
	}

	return ht, nil
}

func (ht *hashTable) setSelfAddr(ip string, port string) error {
	ht.Self.IP = net.ParseIP(ip)
	p, err := strconv.Atoi(port)
	if err != nil {
		return err
	}
	ht.Self.Port = p
	return nil
}

func (ht *hashTable) resetRefreshTimeForBucket(bucket int) {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()
	ht.refreshMap[bucket] = time.Now()
}

func (ht *hashTable) getRefreshTimeForBucket(bucket int) time.Time {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()
	return ht.refreshMap[bucket]
}

func (ht *hashTable) markNodeAsSeen(node []byte) {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()
	index := getBucketIndexFromDifferingBit(ht.Self.ID, node)
	bucket := ht.RoutingTable[index]
	nodeIndex := -1
	for i, v := range bucket {
		if bytes.Compare(v.ID, node) == 0 {
			nodeIndex = i
			break
		}
	}
	if nodeIndex == -1 {
		panic(errors.New("Tried to mark nonexistent node as seen"))
	}

	n := bucket[nodeIndex]
	bucket = append(bucket[:nodeIndex], bucket[nodeIndex+1:]...)
	bucket = append(bucket, n)
	ht.RoutingTable[index] = bucket
}

func (ht *hashTable) doesNodeExistInBucket(bucket int, node []byte) bool {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()
	for _, v := range ht.RoutingTable[bucket] {
		if bytes.Compare(v.ID, node) == 0 {
			return true
		}
	}
	return false
}

func (ht *hashTable) getClosestContacts(num int, target []byte, ignoredNodes []*NetworkNode) *shortList {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()
	// First we need to build the list of adjacent indices to our target
	// in order
	index := getBucketIndexFromDifferingBit(ht.Self.ID, target)
	indexList := []int{index}
	i := index - 1
	j := index + 1
	for len(indexList) < b {
		if j < b {
			indexList = append(indexList, j)
		}
		if i >= 0 {
			indexList = append(indexList, i)
		}
		i--
		j++
	}

	sl := &shortList{}

	leftToAdd := num

	// Next we select alpha contacts and add them to the short list
	for leftToAdd > 0 && len(indexList) > 0 {
		index, indexList = indexList[0], indexList[1:]
		bucketContacts := len(ht.RoutingTable[index])
		for i := 0; i < bucketContacts; i++ {
			ignored := false
			for j := 0; j < len(ignoredNodes); j++ {
				if bytes.Compare(ht.RoutingTable[index][i].ID, ignoredNodes[j].ID) == 0 {
					ignored = true
				}
			}
			if !ignored {
				sl.AppendUnique([]*node{ht.RoutingTable[index][i]})
				leftToAdd--
				if leftToAdd == 0 {
					break
				}
			}
		}
	}

	sort.Sort(sl)

	return sl
}

func (ht *hashTable) removeNode(ID []byte) {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()

	index := getBucketIndexFromDifferingBit(ht.Self.ID, ID)
	bucket := ht.RoutingTable[index]

	for i, v := range bucket {
		if bytes.Compare(v.ID, ID) == 0 {
			bucket = append(bucket[:i], bucket[i+1:]...)
		}
	}

	ht.RoutingTable[index] = bucket
}

func (ht *hashTable) getAllNodesInBucketCloserThan(bucket int, id []byte) [][]byte {
	b := ht.RoutingTable[bucket]
	var nodes [][]byte
	for _, v := range b {
		d1 := ht.getDistance(id, ht.Self.ID)
		d2 := ht.getDistance(id, v.ID)

		result := big.NewInt(0)
		result.Sub(d1, d2)
		if result.Sign() > -1 {
			nodes = append(nodes, v.ID)
		}
	}

	return nodes
}

func (ht *hashTable) getCloserNode(node1 *NetworkNode, node2 *NetworkNode, id []byte) *NetworkNode {

	d1 := ht.getDistance(id, node1.ID)
	d2 := ht.getDistance(id, node2.ID)
	result := big.NewInt(0)
	result.Sub(d1, d2)
	if result.Sign() <= 0 {
		return node1
	}

	return node2
}

func (ht *hashTable) getTotalNodesInBucket(bucket int) int {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()
	return len(ht.RoutingTable[bucket])
}

func (ht *hashTable) getDistance(id1 []byte, id2 []byte) *big.Int {
	var dst [k]byte
	for i := 0; i < k; i++ {
		dst[i] = id1[i] ^ id2[i]
	}
	ret := big.NewInt(0)
	return ret.SetBytes(dst[:])
}

func (ht *hashTable) getRandomIDFromBucket(bucket int) []byte {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()

	// Set the new ID to to be equal in every byte up to
	// the byte of the first differing bit in the bucket

	byteIndex := bucket / 8
	var id []byte
	for i := 0; i < byteIndex; i++ {
		id = append(id, ht.Self.ID[i])
	}
	differingBitStart := bucket % 8

	var firstByte byte
	// check each bit from left to right in order
	for i := 0; i < 8; i++ {
		// Set the value of the bit to be the same as the ID
		// up to the differing bit. Then begin randomizing
		var bit bool
		if i < differingBitStart {
			bit = hasBit(ht.Self.ID[byteIndex], uint(i))
		} else {
			bit = rand.Intn(2) == 1
		}

		if bit {
			firstByte += byte(math.Pow(2, float64(7-i)))
		}
	}

	id = append(id, firstByte)

	// Randomize each remaining byte
	for i := byteIndex + 1; i < 32; i++ {
		randomByte := byte(rand.Intn(256))
		id = append(id, randomByte)
	}

	return id
}

func getBucketIndexFromDifferingBit(id1 []byte, id2 []byte) int {
	// Look at each byte from left to right
	for j := 0; j < len(id1); j++ {
		// xor the byte
		xor := id1[j] ^ id2[j]

		// check each bit on the xored result from left to right in order
		for i := 0; i < 8; i++ {
			if hasBit(xor, uint(i)) {
				byteIndex := j * 8
				bitIndex := i
				return b - (byteIndex + bitIndex) - 1
			}
		}
	}

	// the ids must be the same
	// this should only happen during bootstrapping
	return 0
}

func (ht *hashTable) totalNodes() int {
	ht.mutex.Lock()
	defer ht.mutex.Unlock()
	var total int
	for _, v := range ht.RoutingTable {
		total += len(v)
	}
	return total
}

// newID generates a new random ID
func newID() ([]byte, error) {
	result := make([]byte, 32)
	_, err := rand.Read(result)
	return result, err
}

// Simple helper function to determine the value of a particular
// bit in a byte by index

// Example:
// number:  1
// bits:    00000001
// pos:     01234567
func hasBit(n byte, pos uint) bool {
	pos = 7 - pos
	val := n & (1 << pos)
	return (val > 0)
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httptest"
	_ "net/http/httputil"
	"sync"
	"testing"
	"time"
)

func startHTTP(cb func(http.ResponseWriter, *http.Request)) net.Listener {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		cb(w, r)
	})

	listener, _ := net.Listen("tcp", ":0")

	go http.Serve(listener, handler)

	return listener
}

func TestHTTPOutput(t *testing.T) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	input := NewTestInput()

	listener := startHTTP(func(w http.ResponseWriter, req *http.Request) {
		if req.Header.Get("User-Agent") != "Gor" {
			t.Error("Wrong header")
		}

		if req.Method == "OPTIONS" {
			t.Error("Wrong method")
		}

		if req.Method == "POST" {
			defer req.Body.Close()
			body, _ := ioutil.ReadAll(req.Body)

			if string(body) != "a=1&b=2" {
				t.Error("Wrong POST body:", string(body))
			}
		}

		wg.Done()
	})

	headers := HTTPHeaders{HTTPHeader{"User-Agent", "Gor"}}
	methods := HTTPMethods{[]byte("GET"), []byte("PUT"), []byte("POST")}
	Settings.modifierConfig = HTTPModifierConfig{headers: headers, methods: methods}

	output := NewHTTPOutput(listener.Addr().String(), &HTTPOutputConfig{})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{output}

	go Start(quit)

	for i := 0; i < 100; i++ {
		wg.Add(2) // OPTIONS should be ignored
		input.EmitPOST()
		input.EmitOPTIONS()
		input.EmitGET()
	}

	wg.Wait()

	close(quit)

	Settings.modifierConfig = HTTPModifierConfig{}
}

func TestHTTPOutputKeepOriginalHost(t *testing.T) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	input := NewTestInput()

	listener := startHTTP(func(req *http.Request) {
		if req.Host != "custom-host.com" {
			t.Error("Wrong header", req.Host)
		}

		wg.Done()
	})

	headers := HTTPHeaders{HTTPHeader{"Host", "custom-host.com"}}
	Settings.modifierConfig = HTTPModifierConfig{headers: headers}

	output := NewHTTPOutput(listener.Addr().String(), &HTTPOutputConfig{Debug: false, OriginalHost: true})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{output}

	go Start(quit)

	wg.Add(1)
	input.EmitGET()

	wg.Wait()

	close(quit)

	Settings.modifierConfig = HTTPModifierConfig{}
}

func TestOutputHTTPSSL(t *testing.T) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	// Origing and Replay server initialization
	server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		wg.Done()
	}))

	input := NewTestInput()
	output := NewHTTPOutput(server.URL, &HTTPOutputConfig{})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{output}

	go Start(quit)

	wg.Add(2)

	input.EmitPOST()
	input.EmitGET()

	wg.Wait()
	close(quit)
}

func BenchmarkHTTPOutput(b *testing.B) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	listener := startHTTP(func(w http.ResponseWriter, req *http.Request) {
		time.Sleep(50 * time.Millisecond)
		wg.Done()
	})

	input := NewTestInput()
	output := NewHTTPOutput(listener.Addr().String(), &HTTPOutputConfig{})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{output}

	go Start(quit)

	for i := 0; i < b.N; i++ {
		wg.Add(1)
		input.EmitPOST()
	}

	wg.Wait()

	close(quit)
}
<commit_msg>Fix tests<commit_after>package main

import (
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httptest"
	_ "net/http/httputil"
	"sync"
	"testing"
	"time"
)

func startHTTP(cb func(http.ResponseWriter, *http.Request)) net.Listener {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		cb(w, r)
	})

	listener, _ := net.Listen("tcp", ":0")

	go http.Serve(listener, handler)

	return listener
}

func TestHTTPOutput(t *testing.T) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	input := NewTestInput()

	listener := startHTTP(func(w http.ResponseWriter, req *http.Request) {
		if req.Header.Get("User-Agent") != "Gor" {
			t.Error("Wrong header")
		}

		if req.Method == "OPTIONS" {
			t.Error("Wrong method")
		}

		if req.Method == "POST" {
			defer req.Body.Close()
			body, _ := ioutil.ReadAll(req.Body)

			if string(body) != "a=1&b=2" {
				t.Error("Wrong POST body:", string(body))
			}
		}

		wg.Done()
	})

	headers := HTTPHeaders{HTTPHeader{"User-Agent", "Gor"}}
	methods := HTTPMethods{[]byte("GET"), []byte("PUT"), []byte("POST")}
	Settings.modifierConfig = HTTPModifierConfig{headers: headers, methods: methods}

	output := NewHTTPOutput(listener.Addr().String(), &HTTPOutputConfig{})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{output}

	go Start(quit)

	for i := 0; i < 100; i++ {
		wg.Add(2) // OPTIONS should be ignored
		input.EmitPOST()
		input.EmitOPTIONS()
		input.EmitGET()
	}

	wg.Wait()

	close(quit)

	Settings.modifierConfig = HTTPModifierConfig{}
}

func TestHTTPOutputKeepOriginalHost(t *testing.T) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	input := NewTestInput()

	listener := startHTTP(func(w http.ResponseWriter, req *http.Request) {
		if req.Host != "custom-host.com" {
			t.Error("Wrong header", req.Host)
		}

		wg.Done()
	})

	headers := HTTPHeaders{HTTPHeader{"Host", "custom-host.com"}}
	Settings.modifierConfig = HTTPModifierConfig{headers: headers}

	output := NewHTTPOutput(listener.Addr().String(), &HTTPOutputConfig{Debug: false, OriginalHost: true})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{output}

	go Start(quit)

	wg.Add(1)
	input.EmitGET()

	wg.Wait()

	close(quit)

	Settings.modifierConfig = HTTPModifierConfig{}
}

func TestOutputHTTPSSL(t *testing.T) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	// Origing and Replay server initialization
	server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		wg.Done()
	}))

	input := NewTestInput()
	output := NewHTTPOutput(server.URL, &HTTPOutputConfig{})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{output}

	go Start(quit)

	wg.Add(2)

	input.EmitPOST()
	input.EmitGET()

	wg.Wait()
	close(quit)
}

func BenchmarkHTTPOutput(b *testing.B) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	listener := startHTTP(func(w http.ResponseWriter, req *http.Request) {
		time.Sleep(50 * time.Millisecond)
		wg.Done()
	})

	input := NewTestInput()
	output := NewHTTPOutput(listener.Addr().String(), &HTTPOutputConfig{})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{output}

	go Start(quit)

	for i := 0; i < b.N; i++ {
		wg.Add(1)
		input.EmitPOST()
	}

	wg.Wait()

	close(quit)
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/gin-gonic/gin"
	"github.com/pilu/fresh/runner/runnerutils"
)

var (
	g *Environment = environment()
)

type Environment struct {
	devMode bool
}

func environment() *Environment {
	return &Environment{
		devMode: true,
	}
}

func (g *Environment) IsDevMode() bool {
	return g.devMode
}

func errPanic(err error, message string) {
	if err != nil {
		if message == "" {
			message = err.Error()
		}
		log.Printf(message)
		if g.IsDevMode() {
			panic(err.Error())
		}
	}
}

func checkErr(err error) {
	errPanic(err, "")
}

func runnerMiddleware(c *gin.Context) {
	if runnerutils.HasErrors() {
		runnerutils.RenderError(c.Writer)
		c.Abort(500)
	}
}

func main() {
	r := gin.Default()

	// IMPORTANT PART STARTS HERE(=
	//
	if g.IsDevMode() {
		r.Use(runnerMiddleware)
		gopath := os.Getenv("GOPATH")
		if gopath != "" {
			r.ServeFiles("/gopath/*filepath", http.Dir(gopath))
		}

		goroot := os.Getenv("GOROOT")
		if goroot != "" {
			r.ServeFiles("/goroot/*filepath", http.Dir(goroot))
		}
	}

	// This serves static files in the "public" directory
	r.ServeFiles("/public/*filepath", http.Dir("../public"))

	// Subpaths of /todo/ are client urls, should NOT be protected
	// Just serve the index.html for every subpaths actually, nothing else
	web := r.Group("/todo/", func(c *gin.Context) {
		f, err := os.Open("../public/index.html")
		checkErr(err)
		conts, err := ioutil.ReadAll(f)
		checkErr(err)
		c.Data(200, conts)
	})
	web.GET("*path", func(c *gin.Context) {})

	// Redirect the home page to /todo/
	r.GET("/", func(c *gin.Context) {
		http.Redirect(c.Writer, c.Req, "/todo/", http.StatusFound)
	})

	//
	// =)IMPORTANT PART ENDS HERE

	r.Run(":3000")
}
<commit_msg>TodoMVC - gin api changes<commit_after>package main

import (
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/gin-gonic/gin"
	"github.com/pilu/fresh/runner/runnerutils"
)

var (
	g *Environment = environment()
)

type Environment struct {
	devMode bool
}

func environment() *Environment {
	return &Environment{
		devMode: true,
	}
}

func (g *Environment) IsDevMode() bool {
	return g.devMode
}

func errPanic(err error, message string) {
	if err != nil {
		if message == "" {
			message = err.Error()
		}
		log.Printf(message)
		if g.IsDevMode() {
			panic(err.Error())
		}
	}
}

func checkErr(err error) {
	errPanic(err, "")
}

func runnerMiddleware(c *gin.Context) {
	if runnerutils.HasErrors() {
		runnerutils.RenderError(c.Writer)
		c.Abort(500)
	}
}

func main() {
	r := gin.Default()

	// IMPORTANT PART STARTS HERE(=
	//
	if g.IsDevMode() {
		r.Use(runnerMiddleware)
		gopath := os.Getenv("GOPATH")
		if gopath != "" {
			r.ServeFiles("/gopath/*filepath", http.Dir(gopath))
		}

		goroot := os.Getenv("GOROOT")
		if goroot != "" {
			r.ServeFiles("/goroot/*filepath", http.Dir(goroot))
		}
	}

	// This serves static files in the "public" directory
	r.ServeFiles("/public/*filepath", http.Dir("../public"))

	// Subpaths of /todo/ are client urls, should NOT be protected
	// Just serve the index.html for every subpaths actually, nothing else
	web := r.Group("/todo/", func(c *gin.Context) {
		f, err := os.Open("../public/index.html")
		checkErr(err)
		conts, err := ioutil.ReadAll(f)
		checkErr(err)
		c.Data(200, "text/html;charset=utf-8", conts)
	})
	web.GET("*path", func(c *gin.Context) {})

	// Redirect the home page to /todo/
	r.GET("/", func(c *gin.Context) {
		http.Redirect(c.Writer, c.Request, "/todo/", http.StatusFound)
	})

	//
	// =)IMPORTANT PART ENDS HERE

	r.Run(":3000")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"math"
	"strconv"
	"time"
)

type Burndown struct {
	LengthOfSprint      int `json:"length"`
	BeginOfSprint       time.Time
	BeginOfSprintString string `json:"begin"`
	TotalStoryPoints    int
	IdealRemaining      []float64
	ActualRemaining     []int
	IdealSpeed          float64
	ActualSpeed         float64
	Metric              map[string]int `json:"metric"`
	trello              *Trello
}

func NewBurndown(vars []byte, trello *Trello) *Burndown {
	var burndown Burndown
	burndown.trello = trello
	burndown.configFrom(vars)
	return &burndown
}

func (burndown *Burndown) setBeginOfSprint(beginOfSprintString string) {
	burndown.BeginOfSprintString = beginOfSprintString
	beginOfSprint := fmt.Sprintf("%sT00:00:00Z", beginOfSprintString)
	burndown.BeginOfSprint, _ = time.Parse(time.RFC3339, beginOfSprint)
}

func (burndown *Burndown) configFrom(data []byte) {
	json.Unmarshal(data, &burndown)
	burndown.setBeginOfSprint(burndown.BeginOfSprintString)
}

func (burndown *Burndown) setParametersFromRequest(vars map[string]string) {
	if boardId, ok := vars["boardId"]; ok {
		burndown.trello.BoardId = boardId
		fmt.Printf("burndown.trello.BoardId: %v\n", burndown.trello.BoardId)
	}
	if beginOfSprint, ok := vars["begin"]; ok {
		burndown.setBeginOfSprint(beginOfSprint)
	}
	if lengthOfSprint, ok := vars["length"]; ok {
		lengthOfSprintInt, _ := strconv.Atoi(lengthOfSprint)
		burndown.LengthOfSprint = lengthOfSprintInt
	}
}

func (burndown *Burndown) calculate() {
	burndown.TotalStoryPoints = burndown.calculateTotalStoryPoints()
	burndown.IdealSpeed = burndown.calculateIdealSpeed()
	burndown.ActualSpeed = burndown.calculateActualSpeed()
	burndown.IdealRemaining = burndown.calculateIdealRemaining()
	burndown.ActualRemaining = burndown.calculateActualRemaining()
}

func (burndown Burndown) getDayOfWork(time time.Time) (dayOfWork int) {
	deltaHours := math.Ceil((time.Sub(burndown.BeginOfSprint).Hours()))
	dayOfWork = int(deltaHours) / 24
	if math.Mod(deltaHours, 24) > 0 {
		dayOfWork = dayOfWork + 1
	}
	weeks := dayOfWork / 7
	dayOfWork = dayOfWork - weeks*2

	return
}

func (burndown Burndown) getCurrentDayOfWork() int {
	return burndown.getDayOfWork(time.Now())
}

func (burndown Burndown) calculateIdealSpeed() float64 {
	return float64(burndown.TotalStoryPoints) / float64(burndown.LengthOfSprint)
}

func (burndown Burndown) calculateActualSpeed() (actualSpeed float64) {
	donePoints := float64(burndown.evaluateList(burndown.trello.DoneCards))
	actualSpeed = float64(donePoints) / float64(burndown.getCurrentDayOfWork())
	return
}

func (burndown Burndown) calculateIdealRemaining() (idealRemaining []float64) {
	lengthOfSprint := int(burndown.LengthOfSprint)
	for day := 1; day <= lengthOfSprint; day++ {
		idealRemaining = append(idealRemaining, (float64(burndown.TotalStoryPoints) - float64(day)*burndown.IdealSpeed))
	}
	return
}

func (burndown Burndown) calculateActualRemaining() (actualRemaining []int) {
	for idx := 0; idx < burndown.LengthOfSprint; idx++ {
		actualRemaining = append(actualRemaining, int(burndown.TotalStoryPoints))
	}
	for _, card := range burndown.trello.DoneCards {
		storyPoints := burndown.evaluateCard(card)
		doneAction, _ := burndown.trello.getLatestDoneAction(card)
		dayOfWork := burndown.getDayOfWork(doneAction.Time)
		for idx := dayOfWork; idx < len(actualRemaining); idx++ {
			actualRemaining[idx] -= storyPoints
		}
	}
	return
}

func (burndown Burndown) calculateTotalStoryPoints() (totalStoryPoints int) {
	doneStoryPoints := burndown.evaluateList(burndown.trello.DoneCards)
	openStoryPoints := burndown.evaluateList(burndown.trello.OpenCards)
	doingStoryPoints := burndown.evaluateList(burndown.trello.DoingCards)
	fmt.Printf("doneStoryPoints: %v\n", doneStoryPoints)
	fmt.Printf("openStoryPoints: %v\n", openStoryPoints)
	fmt.Printf("doingStoryPoints: %v\n", doingStoryPoints)
	totalStoryPoints = doneStoryPoints + openStoryPoints + doingStoryPoints
	return
}

func (burndown Burndown) evaluateCard(card Card) (storyPoints int) {
	for _, label := range card.Labels {
		if val, ok := burndown.Metric[label.Name]; ok {
			storyPoints = storyPoints + val
		}
	}
	return
}

func (burndown Burndown) evaluateList(cardList []Card) (storyPoints int) {
	for _, card := range cardList {
		storyPoints = storyPoints + burndown.evaluateCard(card)
	}
	return
}
<commit_msg>clean up<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"math"
	"time"
)

type Burndown struct {
	LengthOfSprint      int `json:"length"`
	BeginOfSprint       time.Time
	BeginOfSprintString string `json:"begin"`
	TotalStoryPoints    int
	IdealRemaining      []float64
	ActualRemaining     []int
	IdealSpeed          float64
	ActualSpeed         float64
	Metric              map[string]int `json:"metric"`
	trello              *Trello
}

func NewBurndown(vars []byte, trello *Trello) *Burndown {
	var burndown Burndown
	burndown.trello = trello
	burndown.configFrom(vars)
	return &burndown
}

func (burndown *Burndown) setBeginOfSprint(beginOfSprintString string) {
	burndown.BeginOfSprintString = beginOfSprintString
	beginOfSprint := fmt.Sprintf("%sT00:00:00Z", beginOfSprintString)
	burndown.BeginOfSprint, _ = time.Parse(time.RFC3339, beginOfSprint)
}

func (burndown *Burndown) configFrom(data []byte) {
	json.Unmarshal(data, &burndown)
	burndown.setBeginOfSprint(burndown.BeginOfSprintString)
}

func (burndown *Burndown) calculate() {
	burndown.TotalStoryPoints = burndown.calculateTotalStoryPoints()
	burndown.IdealSpeed = burndown.calculateIdealSpeed()
	burndown.ActualSpeed = burndown.calculateActualSpeed()
	burndown.IdealRemaining = burndown.calculateIdealRemaining()
	burndown.ActualRemaining = burndown.calculateActualRemaining()
}

func (burndown Burndown) getDayOfWork(time time.Time) (dayOfWork int) {
	deltaHours := math.Ceil((time.Sub(burndown.BeginOfSprint).Hours()))
	dayOfWork = int(deltaHours) / 24
	if math.Mod(deltaHours, 24) > 0 {
		dayOfWork = dayOfWork + 1
	}
	weeks := dayOfWork / 7
	dayOfWork = dayOfWork - weeks*2

	return
}

func (burndown Burndown) getCurrentDayOfWork() int {
	return burndown.getDayOfWork(time.Now())
}

func (burndown Burndown) calculateIdealSpeed() float64 {
	return float64(burndown.TotalStoryPoints) / float64(burndown.LengthOfSprint)
}

func (burndown Burndown) calculateActualSpeed() (actualSpeed float64) {
	donePoints := float64(burndown.evaluateList(burndown.trello.DoneCards))
	actualSpeed = float64(donePoints) / float64(burndown.getCurrentDayOfWork())
	return
}

func (burndown Burndown) calculateIdealRemaining() (idealRemaining []float64) {
	lengthOfSprint := int(burndown.LengthOfSprint)
	for day := 1; day <= lengthOfSprint; day++ {
		idealRemaining = append(idealRemaining, (float64(burndown.TotalStoryPoints) - float64(day)*burndown.IdealSpeed))
	}
	return
}

func (burndown Burndown) calculateActualRemaining() (actualRemaining []int) {
	for idx := 0; idx < burndown.LengthOfSprint; idx++ {
		actualRemaining = append(actualRemaining, int(burndown.TotalStoryPoints))
	}
	for _, card := range burndown.trello.DoneCards {
		storyPoints := burndown.evaluateCard(card)
		doneAction, _ := burndown.trello.getLatestDoneAction(card)
		dayOfWork := burndown.getDayOfWork(doneAction.Time)
		for idx := dayOfWork; idx < len(actualRemaining); idx++ {
			actualRemaining[idx] -= storyPoints
		}
	}
	return
}

func (burndown Burndown) calculateTotalStoryPoints() (totalStoryPoints int) {
	doneStoryPoints := burndown.evaluateList(burndown.trello.DoneCards)
	openStoryPoints := burndown.evaluateList(burndown.trello.OpenCards)
	doingStoryPoints := burndown.evaluateList(burndown.trello.DoingCards)
	totalStoryPoints = doneStoryPoints + openStoryPoints + doingStoryPoints
	return
}

func (burndown Burndown) evaluateCard(card Card) (storyPoints int) {
	for _, label := range card.Labels {
		if val, ok := burndown.Metric[label.Name]; ok {
			storyPoints = storyPoints + val
		}
	}
	return
}

func (burndown Burndown) evaluateList(cardList []Card) (storyPoints int) {
	for _, card := range cardList {
		storyPoints = storyPoints + burndown.evaluateCard(card)
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"math"
	"time"
)

type Burndown struct {
	LengthOfSprint      int `json:"length"`
	BeginOfSprint       time.Time
	BeginOfSprintString string `json:"begin"`
	TotalStoryPoints    int
	IdealRemaining      []float64
	ActualRemaining     []int
	IdealSpeed          float64
	ActualSpeed         float64
	Metric              map[string]int `json:"metric"`
	trello              *Trello
}

func NewBurndown(trello *Trello, vars []byte) *Burndown {
	var burndown Burndown
	burndown.trello = trello
	burndown.configFrom(vars)
	return &burndown
}

func (burndown *Burndown) setBeginOfSprint(beginOfSprintString string) {
	burndown.BeginOfSprintString = beginOfSprintString
	beginOfSprint := fmt.Sprintf("%sT00:00:00Z", beginOfSprintString)
	burndown.BeginOfSprint, _ = time.Parse(time.RFC3339, beginOfSprint)
}

func (burndown *Burndown) configFrom(data []byte) {
	json.Unmarshal(data, &burndown)
	burndown.setBeginOfSprint(burndown.BeginOfSprintString)
}

func (burndown *Burndown) calculate() {
	burndown.TotalStoryPoints = burndown.calculateTotalStoryPoints()
	burndown.IdealSpeed = burndown.calculateIdealSpeed()
	burndown.ActualSpeed = burndown.calculateActualSpeed()
	burndown.IdealRemaining = burndown.calculateIdealRemaining()
	burndown.ActualRemaining = burndown.calculateActualRemaining()
}

func (burndown Burndown) getDayOfWork(time time.Time) (dayOfWork int) {
	deltaHours := math.Ceil((time.Sub(burndown.BeginOfSprint).Hours()))
	dayOfWork = int(deltaHours) / 24
	if math.Mod(deltaHours, 24) > 0 {
		dayOfWork = dayOfWork + 1
	}
	weeks := dayOfWork / 7
	dayOfWork = dayOfWork - weeks*2

	return
}

func (burndown Burndown) getCurrentDayOfWork() int {
	return burndown.getDayOfWork(time.Now())
}

func (burndown Burndown) calculateIdealSpeed() float64 {
	return float64(burndown.TotalStoryPoints) / float64(burndown.LengthOfSprint)
}

func (burndown Burndown) calculateActualSpeed() (actualSpeed float64) {
	donePoints := float64(burndown.evaluateList(burndown.trello.DoneCards))
	actualSpeed = float64(donePoints) / float64(burndown.getCurrentDayOfWork())
	return
}

func (burndown Burndown) calculateIdealRemaining() (idealRemaining []float64) {
	lengthOfSprint := int(burndown.LengthOfSprint)
	for day := 1; day <= lengthOfSprint; day++ {
		idealRemaining = append(idealRemaining, (float64(burndown.TotalStoryPoints) - float64(day)*burndown.IdealSpeed))
	}
	return
}

func (burndown Burndown) calculateActualRemaining() (actualRemaining []int) {
	for idx := 0; idx < burndown.LengthOfSprint; idx++ {
		actualRemaining = append(actualRemaining, int(burndown.TotalStoryPoints))
	}
	for _, card := range burndown.trello.DoneCards {
		storyPoints := burndown.evaluateCard(card)
		doneAction, _ := burndown.trello.getLatestDoneAction(card)
		dayOfWork := burndown.getDayOfWork(doneAction.Time)
		for idx := dayOfWork; idx < len(actualRemaining); idx++ {
			actualRemaining[idx] -= storyPoints
		}
	}
	return
}

func (burndown Burndown) calculateTotalStoryPoints() (totalStoryPoints int) {
	doneStoryPoints := burndown.evaluateList(burndown.trello.DoneCards)
	openStoryPoints := burndown.evaluateList(burndown.trello.OpenCards)
	doingStoryPoints := burndown.evaluateList(burndown.trello.DoingCards)
	totalStoryPoints = doneStoryPoints + openStoryPoints + doingStoryPoints
	return
}

func (burndown Burndown) evaluateCard(card Card) (storyPoints int) {
	for _, label := range card.Labels {
		if val, ok := burndown.Metric[label.Name]; ok {
			storyPoints = storyPoints + val
		}
	}
	return
}

func (burndown Burndown) evaluateList(cardList []Card) (storyPoints int) {
	for _, card := range cardList {
		storyPoints = storyPoints + burndown.evaluateCard(card)
	}
	return
}
<commit_msg>show actual only up to current day of work<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"math"
	"time"
)

type Burndown struct {
	LengthOfSprint      int `json:"length"`
	BeginOfSprint       time.Time
	BeginOfSprintString string `json:"begin"`
	TotalStoryPoints    int
	IdealRemaining      []float64
	ActualRemaining     []int
	IdealSpeed          float64
	ActualSpeed         float64
	Metric              map[string]int `json:"metric"`
	trello              *Trello
}

func NewBurndown(trello *Trello, vars []byte) *Burndown {
	var burndown Burndown
	burndown.trello = trello
	burndown.configFrom(vars)
	return &burndown
}

func (burndown *Burndown) setBeginOfSprint(beginOfSprintString string) {
	burndown.BeginOfSprintString = beginOfSprintString
	beginOfSprint := fmt.Sprintf("%sT00:00:00Z", beginOfSprintString)
	burndown.BeginOfSprint, _ = time.Parse(time.RFC3339, beginOfSprint)
}

func (burndown *Burndown) configFrom(data []byte) {
	json.Unmarshal(data, &burndown)
	burndown.setBeginOfSprint(burndown.BeginOfSprintString)
}

func (burndown *Burndown) calculate() {
	burndown.TotalStoryPoints = burndown.calculateTotalStoryPoints()
	burndown.IdealSpeed = burndown.calculateIdealSpeed()
	burndown.ActualSpeed = burndown.calculateActualSpeed()
	burndown.IdealRemaining = burndown.calculateIdealRemaining()
	burndown.ActualRemaining = burndown.calculateActualRemaining()
}

func (burndown Burndown) getDayOfWork(time time.Time) (dayOfWork int) {
	deltaHours := math.Ceil((time.Sub(burndown.BeginOfSprint).Hours()))
	dayOfWork = int(deltaHours) / 24
	if math.Mod(deltaHours, 24) > 0 {
		dayOfWork = dayOfWork + 1
	}
	weeks := dayOfWork / 7
	dayOfWork = dayOfWork - weeks*2

	return
}

func (burndown Burndown) getCurrentDayOfWork() int {
	return burndown.getDayOfWork(time.Now())
}

func (burndown Burndown) calculateIdealSpeed() float64 {
	return float64(burndown.TotalStoryPoints) / float64(burndown.LengthOfSprint)
}

func (burndown Burndown) calculateActualSpeed() (actualSpeed float64) {
	donePoints := float64(burndown.evaluateList(burndown.trello.DoneCards))
	actualSpeed = float64(donePoints) / float64(burndown.getCurrentDayOfWork())
	return
}

func (burndown Burndown) calculateIdealRemaining() (idealRemaining []float64) {
	lengthOfSprint := int(burndown.LengthOfSprint)
	for day := 1; day <= lengthOfSprint; day++ {
		idealRemaining = append(idealRemaining, (float64(burndown.TotalStoryPoints) - float64(day)*burndown.IdealSpeed))
	}
	return
}

func (burndown Burndown) calculateActualRemaining() (actualRemaining []int) {
	for idx := 0; idx < burndown.getCurrentDayOfWork(); idx++ {
		actualRemaining = append(actualRemaining, int(burndown.TotalStoryPoints))
	}
	for _, card := range burndown.trello.DoneCards {
		storyPoints := burndown.evaluateCard(card)
		doneAction, _ := burndown.trello.getLatestDoneAction(card)
		dayOfWork := burndown.getDayOfWork(doneAction.Time)
		for idx := dayOfWork; idx < len(actualRemaining); idx++ {
			actualRemaining[idx] -= storyPoints
		}
	}
	return
}

func (burndown Burndown) calculateTotalStoryPoints() (totalStoryPoints int) {
	doneStoryPoints := burndown.evaluateList(burndown.trello.DoneCards)
	openStoryPoints := burndown.evaluateList(burndown.trello.OpenCards)
	doingStoryPoints := burndown.evaluateList(burndown.trello.DoingCards)
	totalStoryPoints = doneStoryPoints + openStoryPoints + doingStoryPoints
	return
}

func (burndown Burndown) evaluateCard(card Card) (storyPoints int) {
	for _, label := range card.Labels {
		if val, ok := burndown.Metric[label.Name]; ok {
			storyPoints = storyPoints + val
		}
	}
	return
}

func (burndown Burndown) evaluateList(cardList []Card) (storyPoints int) {
	for _, card := range cardList {
		storyPoints = storyPoints + burndown.evaluateCard(card)
	}
	return
}
<|endoftext|>


<commit_before>package proc

import (
	"fmt"

	sys "golang.org/x/sys/unix"
)

// Not actually used, but necessary
// to be defined.
type OSSpecificDetails struct {
	registers sys.PtraceRegs
}

func (t *Thread) Halt() error {
	if stopped(t.Id) {
		return nil
	}
	err := sys.Tgkill(t.dbp.Pid, t.Id, sys.SIGSTOP)
	if err != nil {
		return fmt.Errorf("halt err %s on thread %d", err, t.Id)
	}
	_, _, err = wait(t.Id, t.dbp.Pid, 0)
	if err != nil {
		return fmt.Errorf("wait err %s on thread %d", err, t.Id)
	}
	t.running = false
	return nil
}

func (t *Thread) resume() (err error) {
	t.running = true
	t.dbp.execPtraceFunc(func() { err = PtraceCont(t.Id, 0) })
	return
}

func (t *Thread) singleStep() (err error) {
	t.dbp.execPtraceFunc(func() { err = sys.PtraceSingleStep(t.Id) })
	if err != nil {
		return err
	}
	_, _, err = wait(t.Id, t.dbp.Pid, 0)
	return err
}

func (t *Thread) blocked() bool {
	// TODO(dp) cache the func pc to remove this lookup
	pc, _ := t.PC()
	fn := t.dbp.goSymTable.PCToFunc(pc)
	if fn != nil && ((fn.Name == "runtime.futex") || (fn.Name == "runtime.usleep") || (fn.Name == "runtime.clone")) {
		return true
	}
	return false
}

func (thread *Thread) saveRegisters() (Registers, error) {
	var err error
	thread.dbp.execPtraceFunc(func() { err = sys.PtraceGetRegs(thread.Id, &thread.os.registers) })
	if err != nil {
		return nil, fmt.Errorf("could not save register contents")
	}
	return &Regs{&thread.os.registers}, nil
}

func (thread *Thread) restoreRegisters() (err error) {
	thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.Id, &thread.os.registers) })
	return
}

func (thread *Thread) writeMemory(addr uintptr, data []byte) (written int, err error) {
	if len(data) == 0 {
		return
	}
	thread.dbp.execPtraceFunc(func() { written, err = sys.PtracePokeData(thread.Id, addr, data) })
	return
}

func (thread *Thread) readMemory(addr uintptr, size int) (data []byte, err error) {
	if size == 0 {
		return nil, nil
	}
	data = make([]byte, size)
	thread.dbp.execPtraceFunc(func() { read, err = sys.PtracePeekData(thread.Id, addr, data) })
	return
}
<commit_msg>Fix Linux compilation error<commit_after>package proc

import (
	"fmt"

	sys "golang.org/x/sys/unix"
)

// Not actually used, but necessary
// to be defined.
type OSSpecificDetails struct {
	registers sys.PtraceRegs
}

func (t *Thread) Halt() error {
	if stopped(t.Id) {
		return nil
	}
	err := sys.Tgkill(t.dbp.Pid, t.Id, sys.SIGSTOP)
	if err != nil {
		return fmt.Errorf("halt err %s on thread %d", err, t.Id)
	}
	_, _, err = wait(t.Id, t.dbp.Pid, 0)
	if err != nil {
		return fmt.Errorf("wait err %s on thread %d", err, t.Id)
	}
	t.running = false
	return nil
}

func (t *Thread) resume() (err error) {
	t.running = true
	t.dbp.execPtraceFunc(func() { err = PtraceCont(t.Id, 0) })
	return
}

func (t *Thread) singleStep() (err error) {
	t.dbp.execPtraceFunc(func() { err = sys.PtraceSingleStep(t.Id) })
	if err != nil {
		return err
	}
	_, _, err = wait(t.Id, t.dbp.Pid, 0)
	return err
}

func (t *Thread) blocked() bool {
	// TODO(dp) cache the func pc to remove this lookup
	pc, _ := t.PC()
	fn := t.dbp.goSymTable.PCToFunc(pc)
	if fn != nil && ((fn.Name == "runtime.futex") || (fn.Name == "runtime.usleep") || (fn.Name == "runtime.clone")) {
		return true
	}
	return false
}

func (thread *Thread) saveRegisters() (Registers, error) {
	var err error
	thread.dbp.execPtraceFunc(func() { err = sys.PtraceGetRegs(thread.Id, &thread.os.registers) })
	if err != nil {
		return nil, fmt.Errorf("could not save register contents")
	}
	return &Regs{&thread.os.registers}, nil
}

func (thread *Thread) restoreRegisters() (err error) {
	thread.dbp.execPtraceFunc(func() { err = sys.PtraceSetRegs(thread.Id, &thread.os.registers) })
	return
}

func (thread *Thread) writeMemory(addr uintptr, data []byte) (written int, err error) {
	if len(data) == 0 {
		return
	}
	thread.dbp.execPtraceFunc(func() { written, err = sys.PtracePokeData(thread.Id, addr, data) })
	return
}

func (thread *Thread) readMemory(addr uintptr, size int) (data []byte, err error) {
	if size == 0 {
		return nil, nil
	}
	data = make([]byte, size)
	thread.dbp.execPtraceFunc(func() { _, err = sys.PtracePeekData(thread.Id, addr, data) })
	return
}
<|endoftext|>


<commit_before>package timeout

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"strconv"
	"syscall"
	"time"
)

type Timeout struct {
	PreserveStatus bool
	Duration       uint64
	KillAfter      uint64
	Signal         os.Signal
	Cmd            *exec.Cmd
}

var defaultSignal = func() os.Signal {
	if runtime.GOOS == "windows" {
		return os.Interrupt
	}
	return syscall.SIGTERM
}()

type exitCode int

// exit statuses are same with GNU timeout
const (
	exitNormal            exitCode = 0
	exitTimedOut                   = 124
	exitUnknownErr                 = 125
	exitCommandNotInvoked          = 126
	exitCommandNotFound            = 127
	exitKilled                     = 137
)

type tmError struct {
	ExitCode exitCode
	message  string
}

func (err *tmError) Error() string {
	return err.message
}

type exit struct {
	Code exitCode
	Type exitType
}

func (ex exit) String() string {
	return fmt.Sprintf("exitCode: %d, type: %s", ex.Code, ex.Type)
}

func (ex exit) isTimedOut() bool {
	return ex.Type == exitTypeTimedOut
}

func (ex exit) isKilled() bool {
	return ex.Type == exitTypeKilled
}

type exitType int

const (
	exitTypeNormal exitType = iota + 1
	exitTypeTimedOut
	exitTypeKilled
)

func (eTyp exitType) String() string {
	switch eTyp {
	case exitTypeNormal:
		return "normal"
	case exitTypeTimedOut:
		return "timeout"
	case exitTypeKilled:
		return "killed"
	default:
		return "unknown"
	}
}

func (tio *Timeout) signal() os.Signal {
	if tio.Signal == nil {
		return defaultSignal
	}
	return tio.Signal
}

func (tio *Timeout) Run() int {
	ch, stdoutPipe, stderrPipe, err := tio.RunCommand()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return int(err.ExitCode)
	}
	defer func() {
		stdoutPipe.Close()
		stderrPipe.Close()
	}()

	go readAndOut(stdoutPipe, os.Stdout)
	go readAndOut(stderrPipe, os.Stderr)

	exitSt := <-ch
	return int(exitSt.Code)
}

func (tio *Timeout) RunCommand() (exitChan chan exit, stdoutPipe, stderrPipe io.ReadCloser, tmerr *tmError) {
	cmd := tio.Cmd

	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		tmerr = &tmError{
			ExitCode: exitUnknownErr,
			message:  fmt.Sprintf("unknown error: %s", err),
		}
		return
	}
	stderrPipe, err = cmd.StderrPipe()
	if err != nil {
		tmerr = &tmError{
			ExitCode: exitUnknownErr,
			message:  fmt.Sprintf("unknown error: %s", err),
		}
		return
	}
	if err = cmd.Start(); err != nil {
		switch {
		case os.IsNotExist(err):
			tmerr = &tmError{
				ExitCode: exitCommandNotFound,
				message:  err.Error(),
			}
		case os.IsPermission(err):
			tmerr = &tmError{
				ExitCode: exitCommandNotInvoked,
				message:  err.Error(),
			}
		default:
			tmerr = &tmError{
				ExitCode: exitUnknownErr,
				message:  fmt.Sprintf("unknown error: %s", err),
			}
		}
		return
	}

	exitChan = make(chan exit)
	go func() {
		exitChan <- tio.handleTimeout()
	}()

	return
}

func (tio *Timeout) handleTimeout() exit {
	var ex exit
	cmd := tio.Cmd
	exitChan := getExitChan(cmd)
	if tio.Duration > 0 {
		select {
		case exitCode := <-exitChan:
			ex.Code = exitCode
			ex.Type = exitTypeNormal
		case <-time.After(time.Duration(tio.Duration) * time.Second):
			cmd.Process.Signal(tio.signal())
			ex.Code = exitTimedOut
			ex.Type = exitTypeTimedOut
		}
	} else {
		exitCode := <-exitChan
		return exit{
			Code: exitCode,
			Type: exitTypeNormal,
		}
	}

	if ex.isTimedOut() {
		tmpExit := exitNormal
		if tio.KillAfter > 0 {
			select {
			case tmpExit = <-exitChan:
			case <-time.After(time.Duration(tio.KillAfter) * time.Second):
				cmd.Process.Kill()
				ex.Code = exitKilled
				ex.Type = exitTypeKilled
			}
		} else {
			tmpExit = <-exitChan
		}
		if tio.PreserveStatus && !ex.isKilled() {
			ex.Code = tmpExit
		}
	}

	return ex
}

func getExitChan(cmd *exec.Cmd) chan exitCode {
	ch := make(chan exitCode)
	go func() {
		err := cmd.Wait()
		ch <- resolveCode(err)
	}()
	return ch
}

func resolveCode(err error) exitCode {
	if err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				return exitCode(status.ExitStatus())
			}
		}
		// XXX The exit codes in some platforms aren't integer. e.g. plan9.
		return exitCode(-1)
	}
	return exitNormal
}

func readAndOut(r io.Reader, f *os.File) {
	s := bufio.NewScanner(r)
	for s.Scan() {
		fmt.Fprintln(f, s.Text())
	}
}

var durRe = regexp.MustCompile(`^([0-9]+)([smhd])?$`)

func parseDuration(durStr string) (uint64, error) {
	matches := durRe.FindStringSubmatch(durStr)
	if len(matches) == 0 {
		return 0, fmt.Errorf("duration format invalid: %s", durStr)
	}

	base, _ := strconv.ParseUint(matches[1], 10, 64)
	switch matches[2] {
	case "", "s":
		return base, nil
	case "m":
		return base * 60, nil
	case "h":
		return base * 60 * 60, nil
	case "d":
		return base * 60 * 60 * 24, nil
	default:
		return 0, fmt.Errorf("something went wrong")
	}
}
<commit_msg>remove type exitCode<commit_after>package timeout

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"strconv"
	"syscall"
	"time"
)

type Timeout struct {
	PreserveStatus bool
	Duration       uint64
	KillAfter      uint64
	Signal         os.Signal
	Cmd            *exec.Cmd
}

var defaultSignal = func() os.Signal {
	if runtime.GOOS == "windows" {
		return os.Interrupt
	}
	return syscall.SIGTERM
}()

// exit statuses are same with GNU timeout
const (
	exitNormal            = 0
	exitTimedOut          = 124
	exitUnknownErr        = 125
	exitCommandNotInvoked = 126
	exitCommandNotFound   = 127
	exitKilled            = 137
)

type tmError struct {
	ExitCode int
	message  string
}

func (err *tmError) Error() string {
	return err.message
}

type exit struct {
	Code int
	Type exitType
}

func (ex exit) String() string {
	return fmt.Sprintf("exitCode: %d, type: %s", ex.Code, ex.Type)
}

func (ex exit) isTimedOut() bool {
	return ex.Type == exitTypeTimedOut
}

func (ex exit) isKilled() bool {
	return ex.Type == exitTypeKilled
}

type exitType int

const (
	exitTypeNormal exitType = iota + 1
	exitTypeTimedOut
	exitTypeKilled
)

func (eTyp exitType) String() string {
	switch eTyp {
	case exitTypeNormal:
		return "normal"
	case exitTypeTimedOut:
		return "timeout"
	case exitTypeKilled:
		return "killed"
	default:
		return "unknown"
	}
}

func (tio *Timeout) signal() os.Signal {
	if tio.Signal == nil {
		return defaultSignal
	}
	return tio.Signal
}

func (tio *Timeout) Run() int {
	ch, stdoutPipe, stderrPipe, err := tio.RunCommand()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return int(err.ExitCode)
	}
	defer func() {
		stdoutPipe.Close()
		stderrPipe.Close()
	}()

	go readAndOut(stdoutPipe, os.Stdout)
	go readAndOut(stderrPipe, os.Stderr)

	exitSt := <-ch
	return int(exitSt.Code)
}

func (tio *Timeout) RunCommand() (exitChan chan exit, stdoutPipe, stderrPipe io.ReadCloser, tmerr *tmError) {
	cmd := tio.Cmd

	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		tmerr = &tmError{
			ExitCode: exitUnknownErr,
			message:  fmt.Sprintf("unknown error: %s", err),
		}
		return
	}
	stderrPipe, err = cmd.StderrPipe()
	if err != nil {
		tmerr = &tmError{
			ExitCode: exitUnknownErr,
			message:  fmt.Sprintf("unknown error: %s", err),
		}
		return
	}
	if err = cmd.Start(); err != nil {
		switch {
		case os.IsNotExist(err):
			tmerr = &tmError{
				ExitCode: exitCommandNotFound,
				message:  err.Error(),
			}
		case os.IsPermission(err):
			tmerr = &tmError{
				ExitCode: exitCommandNotInvoked,
				message:  err.Error(),
			}
		default:
			tmerr = &tmError{
				ExitCode: exitUnknownErr,
				message:  fmt.Sprintf("unknown error: %s", err),
			}
		}
		return
	}

	exitChan = make(chan exit)
	go func() {
		exitChan <- tio.handleTimeout()
	}()

	return
}

func (tio *Timeout) handleTimeout() exit {
	var ex exit
	cmd := tio.Cmd
	exitChan := getExitChan(cmd)
	if tio.Duration > 0 {
		select {
		case exitCode := <-exitChan:
			ex.Code = exitCode
			ex.Type = exitTypeNormal
		case <-time.After(time.Duration(tio.Duration) * time.Second):
			cmd.Process.Signal(tio.signal())
			ex.Code = exitTimedOut
			ex.Type = exitTypeTimedOut
		}
	} else {
		exitCode := <-exitChan
		return exit{
			Code: exitCode,
			Type: exitTypeNormal,
		}
	}

	if ex.isTimedOut() {
		tmpExit := exitNormal
		if tio.KillAfter > 0 {
			select {
			case tmpExit = <-exitChan:
			case <-time.After(time.Duration(tio.KillAfter) * time.Second):
				cmd.Process.Kill()
				ex.Code = exitKilled
				ex.Type = exitTypeKilled
			}
		} else {
			tmpExit = <-exitChan
		}
		if tio.PreserveStatus && !ex.isKilled() {
			ex.Code = tmpExit
		}
	}

	return ex
}

func getExitChan(cmd *exec.Cmd) chan int {
	ch := make(chan int)
	go func() {
		err := cmd.Wait()
		ch <- resolveCode(err)
	}()
	return ch
}

func resolveCode(err error) int {
	if err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				return status.ExitStatus()
			}
		}
		// XXX The exit codes in some platforms aren't integer. e.g. plan9.
		return -1
	}
	return exitNormal
}

func readAndOut(r io.Reader, f *os.File) {
	s := bufio.NewScanner(r)
	for s.Scan() {
		fmt.Fprintln(f, s.Text())
	}
}

var durRe = regexp.MustCompile(`^([0-9]+)([smhd])?$`)

func parseDuration(durStr string) (uint64, error) {
	matches := durRe.FindStringSubmatch(durStr)
	if len(matches) == 0 {
		return 0, fmt.Errorf("duration format invalid: %s", durStr)
	}

	base, _ := strconv.ParseUint(matches[1], 10, 64)
	switch matches[2] {
	case "", "s":
		return base, nil
	case "m":
		return base * 60, nil
	case "h":
		return base * 60 * 60, nil
	case "d":
		return base * 60 * 60 * 24, nil
	default:
		return 0, fmt.Errorf("something went wrong")
	}
}
<|endoftext|>


<commit_before>package mpb_test

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"strings"
	"sync/atomic"
	"testing"
	"time"
	"unicode/utf8"

	"github.com/vbauerster/mpb/v7"
	"github.com/vbauerster/mpb/v7/decor"
)

func TestBarCompleted(t *testing.T) {
	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(ioutil.Discard))
	total := 80
	bar := p.AddBar(int64(total))

	if bar.Completed() {
		t.Fail()
	}

	bar.IncrBy(total)

	if !bar.Completed() {
		t.Error("bar isn't completed after increment")
	}

	p.Wait()
}

func TestBarAborted(t *testing.T) {
	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(ioutil.Discard))
	total := 80
	bar := p.AddBar(int64(total))

	if bar.Aborted() {
		t.Fail()
	}

	bar.Abort(false)

	if !bar.Aborted() {
		t.Error("bar isn't aborted after abort call")
	}

	p.Wait()
}

func TestBarID(t *testing.T) {
	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(ioutil.Discard))
	total := 100
	wantID := 11
	bar := p.AddBar(int64(total), mpb.BarID(wantID))

	gotID := bar.ID()
	if gotID != wantID {
		t.Errorf("Expected bar id: %d, got %d\n", wantID, gotID)
	}

	bar.IncrBy(total)

	p.Wait()
}

func TestBarSetRefill(t *testing.T) {
	var buf bytes.Buffer

	p := mpb.New(mpb.WithOutput(&buf), mpb.WithWidth(100))

	total := 100
	till := 30
	refiller := "+"

	bar := p.New(int64(total), mpb.BarStyle().Refiller(refiller), mpb.BarFillerTrim())

	bar.SetRefill(int64(till))
	bar.IncrBy(till)
	bar.IncrBy(total - till)

	p.Wait()

	wantBar := fmt.Sprintf("[%s%s]",
		strings.Repeat(refiller, till-1),
		strings.Repeat("=", total-till-1),
	)

	got := string(bytes.Split(buf.Bytes(), []byte("\n"))[0])

	if !strings.Contains(got, wantBar) {
		t.Errorf("Want bar: %q, got bar: %q\n", wantBar, got)
	}
}

func TestBarHas100PercentWithBarRemoveOnComplete(t *testing.T) {
	var buf bytes.Buffer

	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(&buf))

	total := 50

	bar := p.AddBar(int64(total),
		mpb.BarRemoveOnComplete(),
		mpb.AppendDecorators(decor.Percentage()),
	)

	bar.IncrBy(total)

	p.Wait()

	hundred := "100 %"
	if !bytes.Contains(buf.Bytes(), []byte(hundred)) {
		t.Errorf("Bar's buffer does not contain: %q\n", hundred)
	}
}

func TestBarStyle(t *testing.T) {
	var buf bytes.Buffer
	customFormat := "╢▌▌░╟"
	runes := []rune(customFormat)
	total := 80
	p := mpb.New(mpb.WithWidth(total), mpb.WithOutput(&buf))
	bs := mpb.BarStyle()
	bs.Lbound(string(runes[0]))
	bs.Filler(string(runes[1]))
	bs.Tip(string(runes[2]))
	bs.Padding(string(runes[3]))
	bs.Rbound(string(runes[4]))
	bar := p.New(int64(total), bs, mpb.BarFillerTrim())

	bar.IncrBy(total)

	p.Wait()

	wantBar := fmt.Sprintf("%s%s%s%s",
		string(runes[0]),
		strings.Repeat(string(runes[1]), total-3),
		string(runes[2]),
		string(runes[4]),
	)
	got := string(bytes.Split(buf.Bytes(), []byte("\n"))[0])

	if !strings.Contains(got, wantBar) {
		t.Errorf("Want bar: %q:%d, got bar: %q:%d\n", wantBar, utf8.RuneCountInString(wantBar), got, utf8.RuneCountInString(got))
	}
}

func TestBarPanicBeforeComplete(t *testing.T) {
	var buf bytes.Buffer
	p := mpb.New(
		mpb.WithWidth(80),
		mpb.WithDebugOutput(&buf),
		mpb.WithOutput(ioutil.Discard),
	)

	total := 100
	panicMsg := "Upps!!!"
	var pCount uint32
	bar := p.AddBar(int64(total),
		mpb.PrependDecorators(panicDecorator(panicMsg,
			func(st decor.Statistics) bool {
				if st.Current >= 42 {
					atomic.AddUint32(&pCount, 1)
					return true
				}
				return false
			},
		)),
	)

	bar.IncrBy(total)

	p.Wait()

	if pCount != 1 {
		t.Errorf("Decorator called after panic %d times, expected 1\n", pCount)
	}

	barStr := buf.String()
	if !strings.Contains(barStr, panicMsg) {
		t.Errorf("%q doesn't contain %q\n", barStr, panicMsg)
	}
}

func TestBarPanicAfterComplete(t *testing.T) {
	var buf bytes.Buffer
	p := mpb.New(
		mpb.WithWidth(80),
		mpb.WithDebugOutput(&buf),
		mpb.WithOutput(ioutil.Discard),
	)

	total := 100
	panicMsg := "Upps!!!"
	var pCount uint32
	bar := p.AddBar(int64(total),
		mpb.PrependDecorators(panicDecorator(panicMsg,
			func(st decor.Statistics) bool {
				if st.Completed {
					atomic.AddUint32(&pCount, 1)
					return true
				}
				return false
			},
		)),
	)

	bar.IncrBy(total)

	p.Wait()

	if pCount != 1 {
		t.Errorf("Decorator called after panic %d times, expected 1\n", pCount)
	}

	barStr := buf.String()
	if !strings.Contains(barStr, panicMsg) {
		t.Errorf("%q doesn't contain %q\n", barStr, panicMsg)
	}
}

func TestDecorStatisticsAvailableWidth(t *testing.T) {
	total := 100
	down := make(chan struct{})
	checkDone := make(chan struct{})
	td1 := func(s decor.Statistics) string {
		if s.AvailableWidth != 80 {
			t.Errorf("expected AvailableWidth %d got %d\n", 80, s.AvailableWidth)
		}
		return fmt.Sprintf("\x1b[31;1;4m%s\x1b[0m", strings.Repeat("0", 20))
	}
	td2 := func(s decor.Statistics) string {
		defer func() {
			select {
			case checkDone <- struct{}{}:
			default:
			}
		}()
		if s.AvailableWidth != 40 {
			t.Errorf("expected AvailableWidth %d got %d\n", 40, s.AvailableWidth)
		}
		return ""
	}
	p := mpb.New(
		mpb.WithWidth(100),
		mpb.WithShutdownNotifier(down),
		mpb.WithOutput(ioutil.Discard),
	)
	bar := p.AddBar(int64(total),
		mpb.BarFillerTrim(),
		mpb.PrependDecorators(
			decor.Name(strings.Repeat("0", 20)),
			decor.Any(td1),
		),
		mpb.AppendDecorators(
			decor.Name(strings.Repeat("0", 20)),
			decor.Any(td2),
		),
	)
	go func() {
		for {
			select {
			case <-checkDone:
				bar.Abort(true)
			case <-down:
				return
			}
		}
	}()
	for !bar.Completed() {
		bar.Increment()
	}
	p.Wait()
}

func panicDecorator(panicMsg string, cond func(decor.Statistics) bool) decor.Decorator {
	return decor.Any(func(st decor.Statistics) string {
		if cond(st) {
			panic(panicMsg)
		}
		return ""
	})
}
<commit_msg>refactor TestDecorStatisticsAvailableWidth<commit_after>package mpb_test

import (
	"bytes"
	"context"
	"fmt"
	"io/ioutil"
	"strings"
	"sync/atomic"
	"testing"
	"time"
	"unicode/utf8"

	"github.com/vbauerster/mpb/v7"
	"github.com/vbauerster/mpb/v7/decor"
)

func TestBarCompleted(t *testing.T) {
	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(ioutil.Discard))
	total := 80
	bar := p.AddBar(int64(total))

	if bar.Completed() {
		t.Fail()
	}

	bar.IncrBy(total)

	if !bar.Completed() {
		t.Error("bar isn't completed after increment")
	}

	p.Wait()
}

func TestBarAborted(t *testing.T) {
	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(ioutil.Discard))
	total := 80
	bar := p.AddBar(int64(total))

	if bar.Aborted() {
		t.Fail()
	}

	bar.Abort(false)

	if !bar.Aborted() {
		t.Error("bar isn't aborted after abort call")
	}

	p.Wait()
}

func TestBarID(t *testing.T) {
	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(ioutil.Discard))
	total := 100
	wantID := 11
	bar := p.AddBar(int64(total), mpb.BarID(wantID))

	gotID := bar.ID()
	if gotID != wantID {
		t.Errorf("Expected bar id: %d, got %d\n", wantID, gotID)
	}

	bar.IncrBy(total)

	p.Wait()
}

func TestBarSetRefill(t *testing.T) {
	var buf bytes.Buffer

	p := mpb.New(mpb.WithOutput(&buf), mpb.WithWidth(100))

	total := 100
	till := 30
	refiller := "+"

	bar := p.New(int64(total), mpb.BarStyle().Refiller(refiller), mpb.BarFillerTrim())

	bar.SetRefill(int64(till))
	bar.IncrBy(till)
	bar.IncrBy(total - till)

	p.Wait()

	wantBar := fmt.Sprintf("[%s%s]",
		strings.Repeat(refiller, till-1),
		strings.Repeat("=", total-till-1),
	)

	got := string(bytes.Split(buf.Bytes(), []byte("\n"))[0])

	if !strings.Contains(got, wantBar) {
		t.Errorf("Want bar: %q, got bar: %q\n", wantBar, got)
	}
}

func TestBarHas100PercentWithBarRemoveOnComplete(t *testing.T) {
	var buf bytes.Buffer

	p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(&buf))

	total := 50

	bar := p.AddBar(int64(total),
		mpb.BarRemoveOnComplete(),
		mpb.AppendDecorators(decor.Percentage()),
	)

	bar.IncrBy(total)

	p.Wait()

	hundred := "100 %"
	if !bytes.Contains(buf.Bytes(), []byte(hundred)) {
		t.Errorf("Bar's buffer does not contain: %q\n", hundred)
	}
}

func TestBarStyle(t *testing.T) {
	var buf bytes.Buffer
	customFormat := "╢▌▌░╟"
	runes := []rune(customFormat)
	total := 80
	p := mpb.New(mpb.WithWidth(total), mpb.WithOutput(&buf))
	bs := mpb.BarStyle()
	bs.Lbound(string(runes[0]))
	bs.Filler(string(runes[1]))
	bs.Tip(string(runes[2]))
	bs.Padding(string(runes[3]))
	bs.Rbound(string(runes[4]))
	bar := p.New(int64(total), bs, mpb.BarFillerTrim())

	bar.IncrBy(total)

	p.Wait()

	wantBar := fmt.Sprintf("%s%s%s%s",
		string(runes[0]),
		strings.Repeat(string(runes[1]), total-3),
		string(runes[2]),
		string(runes[4]),
	)
	got := string(bytes.Split(buf.Bytes(), []byte("\n"))[0])

	if !strings.Contains(got, wantBar) {
		t.Errorf("Want bar: %q:%d, got bar: %q:%d\n", wantBar, utf8.RuneCountInString(wantBar), got, utf8.RuneCountInString(got))
	}
}

func TestBarPanicBeforeComplete(t *testing.T) {
	var buf bytes.Buffer
	p := mpb.New(
		mpb.WithWidth(80),
		mpb.WithDebugOutput(&buf),
		mpb.WithOutput(ioutil.Discard),
	)

	total := 100
	panicMsg := "Upps!!!"
	var pCount uint32
	bar := p.AddBar(int64(total),
		mpb.PrependDecorators(panicDecorator(panicMsg,
			func(st decor.Statistics) bool {
				if st.Current >= 42 {
					atomic.AddUint32(&pCount, 1)
					return true
				}
				return false
			},
		)),
	)

	bar.IncrBy(total)

	p.Wait()

	if pCount != 1 {
		t.Errorf("Decorator called after panic %d times, expected 1\n", pCount)
	}

	barStr := buf.String()
	if !strings.Contains(barStr, panicMsg) {
		t.Errorf("%q doesn't contain %q\n", barStr, panicMsg)
	}
}

func TestBarPanicAfterComplete(t *testing.T) {
	var buf bytes.Buffer
	p := mpb.New(
		mpb.WithWidth(80),
		mpb.WithDebugOutput(&buf),
		mpb.WithOutput(ioutil.Discard),
	)

	total := 100
	panicMsg := "Upps!!!"
	var pCount uint32
	bar := p.AddBar(int64(total),
		mpb.PrependDecorators(panicDecorator(panicMsg,
			func(st decor.Statistics) bool {
				if st.Completed {
					atomic.AddUint32(&pCount, 1)
					return true
				}
				return false
			},
		)),
	)

	bar.IncrBy(total)

	p.Wait()

	if pCount != 1 {
		t.Errorf("Decorator called after panic %d times, expected 1\n", pCount)
	}

	barStr := buf.String()
	if !strings.Contains(barStr, panicMsg) {
		t.Errorf("%q doesn't contain %q\n", barStr, panicMsg)
	}
}

func TestDecorStatisticsAvailableWidth(t *testing.T) {
	var called [2]bool
	td1 := func(s decor.Statistics) string {
		if s.AvailableWidth != 80 {
			t.Errorf("expected AvailableWidth %d got %d\n", 80, s.AvailableWidth)
		}
		called[0] = true
		return fmt.Sprintf("\x1b[31;1;4m%s\x1b[0m", strings.Repeat("0", 20))
	}
	td2 := func(s decor.Statistics) string {
		if s.AvailableWidth != 40 {
			t.Errorf("expected AvailableWidth %d got %d\n", 40, s.AvailableWidth)
		}
		called[1] = true
		return ""
	}
	ctx, cancel := context.WithCancel(context.Background())
	refresh := make(chan interface{})
	p := mpb.NewWithContext(ctx, mpb.WithWidth(100),
		mpb.WithManualRefresh(refresh),
		mpb.WithOutput(ioutil.Discard),
	)
	_ = p.AddBar(0,
		mpb.BarFillerTrim(),
		mpb.PrependDecorators(
			decor.Name(strings.Repeat("0", 20)),
			decor.Any(td1),
		),
		mpb.AppendDecorators(
			decor.Name(strings.Repeat("0", 20)),
			decor.Any(td2),
		),
	)
	refresh <- time.Now()
	cancel()
	p.Wait()
	for i, ok := range called {
		if !ok {
			t.Errorf("Decorator %d isn't called", i+1)
		}
	}
}

func panicDecorator(panicMsg string, cond func(decor.Statistics) bool) decor.Decorator {
	return decor.Any(func(st decor.Statistics) string {
		if cond(st) {
			panic(panicMsg)
		}
		return ""
	})
}
<|endoftext|>