<commit_before>package locking

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"os"
	"testing"
	"time"

	"github.com/git-lfs/git-lfs/api"
	"github.com/git-lfs/git-lfs/config"
	"github.com/stretchr/testify/assert"
)

func TestLockCache(t *testing.T) {
	var err error

	oldStore := config.LocalGitStorageDir
	config.LocalGitStorageDir, err = ioutil.TempDir("", "testCacheLock")
	assert.Nil(t, err)
	defer func() {
		os.RemoveAll(config.LocalGitStorageDir)
		config.LocalGitStorageDir = oldStore
	}()

	client, err := NewClient(config.NewFrom(config.Values{}))
	assert.Nil(t, err)

	testLocks := []Lock{
		Lock{Path: "folder/test1.dat", Id: "101"},
		Lock{Path: "folder/test2.dat", Id: "102"},
		Lock{Path: "root.dat", Id: "103"},
	}

	for _, l := range testLocks {
		err = client.cacheLock(l)
		assert.Nil(t, err)
	}

	locks := client.cachedLocks()
	for _, l := range testLocks {
		assert.Contains(t, locks, l)
	}
	assert.Equal(t, len(testLocks), len(locks))

	err = client.cacheUnlockByPath("folder/test2.dat")
	assert.Nil(t, err)

	locks = client.cachedLocks()
	// delete item 1 from test locls
	testLocks = append(testLocks[:1], testLocks[2:]...)
	for _, l := range testLocks {
		assert.Contains(t, locks, l)
	}
	assert.Equal(t, len(testLocks), len(locks))

	err = client.cacheUnlockById("101")
	assert.Nil(t, err)

	locks = client.cachedLocks()
	testLocks = testLocks[1:]
	for _, l := range testLocks {
		assert.Contains(t, locks, l)
	}
	assert.Equal(t, len(testLocks), len(locks))
}

type TestLifecycle struct {
}

func (l *TestLifecycle) Build(schema *api.RequestSchema) (*http.Request, error) {
	return http.NewRequest("GET", "http://dummy", nil)
}

func (l *TestLifecycle) Execute(req *http.Request, into interface{}) (api.Response, error) {
	// Return test data including other users
	locks := api.LockList{Locks: []api.Lock{
		api.Lock{Id: "99", Path: "folder/test3.dat", Committer: api.Committer{Name: "Alice", Email: "alice@wonderland.com"}},
		api.Lock{Id: "101", Path: "folder/test1.dat", Committer: api.Committer{Name: "Fred", Email: "fred@bloggs.com"}},
		api.Lock{Id: "102", Path: "folder/test2.dat", Committer: api.Committer{Name: "Fred", Email: "fred@bloggs.com"}},
		api.Lock{Id: "103", Path: "root.dat", Committer: api.Committer{Name: "Fred", Email: "fred@bloggs.com"}},
		api.Lock{Id: "199", Path: "other/test1.dat", Committer: api.Committer{Name: "Charles", Email: "charles@incharge.com"}},
	}}
	locksJson, _ := json.Marshal(locks)
	r := &http.Response{
		Status:     "200 OK",
		StatusCode: 200,
		Proto:      "HTTP/1.0",
		Body:       ioutil.NopCloser(bytes.NewReader(locksJson)),
	}
	if into != nil {
		decoder := json.NewDecoder(r.Body)
		if err := decoder.Decode(into); err != nil {
			return nil, err
		}
	}
	return api.WrapHttpResponse(r), nil
}
func (l *TestLifecycle) Cleanup(resp api.Response) error {
	return resp.Body().Close()
}

func TestRefreshCache(t *testing.T) {
	var err error
	oldStore := config.LocalGitStorageDir
	config.LocalGitStorageDir, err = ioutil.TempDir("", "testCacheLock")
	assert.Nil(t, err)
	defer func() {
		os.RemoveAll(config.LocalGitStorageDir)
		config.LocalGitStorageDir = oldStore
	}()

	cfg := config.NewFrom(config.Values{
		Git: map[string]string{"user.name": "Fred", "user.email": "fred@bloggs.com"}})
	client, err := NewClient(cfg)
	assert.Nil(t, err)
	// Override api client for testing
	client.apiClient = api.NewClient(&TestLifecycle{})

	// Should start with no cached items
	locks := client.cachedLocks()
	assert.Empty(t, locks)

	// Should load from test data, just Fred's
	err = client.fetchLocksToCache()
	assert.Nil(t, err)

	locks = client.cachedLocks()
	// Need to include zero time in structure for equal to work
	zeroTime := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)
	assert.Equal(t, []Lock{
		Lock{Path: "folder/test1.dat", Id: "101", Name: "Fred", Email: "fred@bloggs.com", LockedAt: zeroTime, UnlockedAt: zeroTime},
		Lock{Path: "folder/test2.dat", Id: "102", Name: "Fred", Email: "fred@bloggs.com", LockedAt: zeroTime, UnlockedAt: zeroTime},
		Lock{Path: "root.dat", Id: "103", Name: "Fred", Email: "fred@bloggs.com", LockedAt: zeroTime, UnlockedAt: zeroTime},
	}, locks)

}
<commit_msg>Fix tests referencing old fields<commit_after>package locking

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"os"
	"testing"
	"time"

	"github.com/git-lfs/git-lfs/api"
	"github.com/git-lfs/git-lfs/config"
	"github.com/stretchr/testify/assert"
)

func TestLockCache(t *testing.T) {
	var err error

	oldStore := config.LocalGitStorageDir
	config.LocalGitStorageDir, err = ioutil.TempDir("", "testCacheLock")
	assert.Nil(t, err)
	defer func() {
		os.RemoveAll(config.LocalGitStorageDir)
		config.LocalGitStorageDir = oldStore
	}()

	client, err := NewClient(config.NewFrom(config.Values{}))
	assert.Nil(t, err)

	testLocks := []Lock{
		Lock{Path: "folder/test1.dat", Id: "101"},
		Lock{Path: "folder/test2.dat", Id: "102"},
		Lock{Path: "root.dat", Id: "103"},
	}

	for _, l := range testLocks {
		err = client.cacheLock(l)
		assert.Nil(t, err)
	}

	locks := client.cachedLocks()
	for _, l := range testLocks {
		assert.Contains(t, locks, l)
	}
	assert.Equal(t, len(testLocks), len(locks))

	err = client.cacheUnlockByPath("folder/test2.dat")
	assert.Nil(t, err)

	locks = client.cachedLocks()
	// delete item 1 from test locls
	testLocks = append(testLocks[:1], testLocks[2:]...)
	for _, l := range testLocks {
		assert.Contains(t, locks, l)
	}
	assert.Equal(t, len(testLocks), len(locks))

	err = client.cacheUnlockById("101")
	assert.Nil(t, err)

	locks = client.cachedLocks()
	testLocks = testLocks[1:]
	for _, l := range testLocks {
		assert.Contains(t, locks, l)
	}
	assert.Equal(t, len(testLocks), len(locks))
}

type TestLifecycle struct {
}

func (l *TestLifecycle) Build(schema *api.RequestSchema) (*http.Request, error) {
	return http.NewRequest("GET", "http://dummy", nil)
}

func (l *TestLifecycle) Execute(req *http.Request, into interface{}) (api.Response, error) {
	// Return test data including other users
	locks := api.LockList{Locks: []api.Lock{
		api.Lock{Id: "99", Path: "folder/test3.dat", Committer: api.Committer{Name: "Alice", Email: "alice@wonderland.com"}},
		api.Lock{Id: "101", Path: "folder/test1.dat", Committer: api.Committer{Name: "Fred", Email: "fred@bloggs.com"}},
		api.Lock{Id: "102", Path: "folder/test2.dat", Committer: api.Committer{Name: "Fred", Email: "fred@bloggs.com"}},
		api.Lock{Id: "103", Path: "root.dat", Committer: api.Committer{Name: "Fred", Email: "fred@bloggs.com"}},
		api.Lock{Id: "199", Path: "other/test1.dat", Committer: api.Committer{Name: "Charles", Email: "charles@incharge.com"}},
	}}
	locksJson, _ := json.Marshal(locks)
	r := &http.Response{
		Status:     "200 OK",
		StatusCode: 200,
		Proto:      "HTTP/1.0",
		Body:       ioutil.NopCloser(bytes.NewReader(locksJson)),
	}
	if into != nil {
		decoder := json.NewDecoder(r.Body)
		if err := decoder.Decode(into); err != nil {
			return nil, err
		}
	}
	return api.WrapHttpResponse(r), nil
}
func (l *TestLifecycle) Cleanup(resp api.Response) error {
	return resp.Body().Close()
}

func TestRefreshCache(t *testing.T) {
	var err error
	oldStore := config.LocalGitStorageDir
	config.LocalGitStorageDir, err = ioutil.TempDir("", "testCacheLock")
	assert.Nil(t, err)
	defer func() {
		os.RemoveAll(config.LocalGitStorageDir)
		config.LocalGitStorageDir = oldStore
	}()

	cfg := config.NewFrom(config.Values{
		Git: map[string]string{"user.name": "Fred", "user.email": "fred@bloggs.com"}})
	client, err := NewClient(cfg)
	assert.Nil(t, err)
	// Override api client for testing
	client.apiClient = api.NewClient(&TestLifecycle{})

	// Should start with no cached items
	locks := client.cachedLocks()
	assert.Empty(t, locks)

	// Should load from test data, just Fred's
	err = client.fetchLocksToCache()
	assert.Nil(t, err)

	locks = client.cachedLocks()
	// Need to include zero time in structure for equal to work
	zeroTime := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)
	assert.Equal(t, []Lock{
		Lock{Path: "folder/test1.dat", Id: "101", Name: "Fred", Email: "fred@bloggs.com", LockedAt: zeroTime},
		Lock{Path: "folder/test2.dat", Id: "102", Name: "Fred", Email: "fred@bloggs.com", LockedAt: zeroTime},
		Lock{Path: "root.dat", Id: "103", Name: "Fred", Email: "fred@bloggs.com", LockedAt: zeroTime},
	}, locks)

}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/codeartifact"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func resourceAwsCodeArtifactDomain() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsCodeArtifactDomainCreate,
		Read:   resourceAwsCodeArtifactDomainRead,
		Delete: resourceAwsCodeArtifactDomainDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"domain": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"encryption_key": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"owner": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"created_time": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"asset_size_bytes": {
				Type:     schema.TypeInt,
				Computed: true,
			},
			"repository_count": {
				Type:     schema.TypeInt,
				Computed: true,
			},
		},
	}
}

func resourceAwsCodeArtifactDomainCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).codeartifactconn
	log.Print("[DEBUG] Creating CodeArtifact Domain")

	params := &codeartifact.CreateDomainInput{
		Domain:        aws.String(d.Get("domain").(string)),
		EncryptionKey: aws.String(d.Get("encryption_key").(string)),
	}

	domain, err := conn.CreateDomain(params)
	if err != nil {
		return fmt.Errorf("error creating CodeArtifact Domain: %s", err)
	}

	d.SetId(aws.StringValue(domain.Domain.Name))

	return resourceAwsCodeArtifactDomainRead(d, meta)
}

func resourceAwsCodeArtifactDomainRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).codeartifactconn

	log.Printf("[DEBUG] Reading CodeArtifact Domain: %s", d.Id())

	sm, err := conn.DescribeDomain(&codeartifact.DescribeDomainInput{
		Domain: aws.String(d.Id()),
	})
	if err != nil {
		if isAWSErr(err, codeartifact.ErrCodeResourceNotFoundException, "") {
			log.Printf("[WARN] CodeArtifact Domain %q not found, removing from state", d.Id())
			d.SetId("")
			return nil
		}
		return err
	}

	d.Set("domain", sm.Domain.Name)
	d.Set("arn", sm.Domain.Arn)
	d.Set("encryption_key", sm.Domain.EncryptionKey)
	d.Set("owner", sm.Domain.Owner)
	d.Set("asset_size_bytes", sm.Domain.AssetSizeBytes)
	d.Set("repository_count", sm.Domain.RepositoryCount)

	if err := d.Set("created_time", sm.Domain.CreatedTime.Format(time.RFC3339)); err != nil {
		return fmt.Errorf("[DEBUG] Error setting created_time: %s", err)
	}

	return nil
}

func resourceAwsCodeArtifactDomainDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).codeartifactconn
	log.Printf("[DEBUG] Deleting CodeArtifact Domain: %s", d.Id())

	input := &codeartifact.DeleteDomainInput{
		Domain: aws.String(d.Id()),
	}

	_, err := conn.DeleteDomain(input)

	if err != nil {
		return fmt.Errorf("error deleting CodeArtifact Domain: %s", err)
	}

	return nil
}
<commit_msg>no need to get when setting string<commit_after>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/codeartifact"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func resourceAwsCodeArtifactDomain() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsCodeArtifactDomainCreate,
		Read:   resourceAwsCodeArtifactDomainRead,
		Delete: resourceAwsCodeArtifactDomainDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"domain": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"encryption_key": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"owner": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"created_time": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"asset_size_bytes": {
				Type:     schema.TypeInt,
				Computed: true,
			},
			"repository_count": {
				Type:     schema.TypeInt,
				Computed: true,
			},
		},
	}
}

func resourceAwsCodeArtifactDomainCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).codeartifactconn
	log.Print("[DEBUG] Creating CodeArtifact Domain")

	params := &codeartifact.CreateDomainInput{
		Domain:        aws.String(d.Get("domain").(string)),
		EncryptionKey: aws.String(d.Get("encryption_key").(string)),
	}

	domain, err := conn.CreateDomain(params)
	if err != nil {
		return fmt.Errorf("error creating CodeArtifact Domain: %s", err)
	}

	d.SetId(aws.StringValue(domain.Domain.Name))

	return resourceAwsCodeArtifactDomainRead(d, meta)
}

func resourceAwsCodeArtifactDomainRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).codeartifactconn

	log.Printf("[DEBUG] Reading CodeArtifact Domain: %s", d.Id())

	sm, err := conn.DescribeDomain(&codeartifact.DescribeDomainInput{
		Domain: aws.String(d.Id()),
	})
	if err != nil {
		if isAWSErr(err, codeartifact.ErrCodeResourceNotFoundException, "") {
			log.Printf("[WARN] CodeArtifact Domain %q not found, removing from state", d.Id())
			d.SetId("")
			return nil
		}
		return err
	}

	d.Set("domain", sm.Domain.Name)
	d.Set("arn", sm.Domain.Arn)
	d.Set("encryption_key", sm.Domain.EncryptionKey)
	d.Set("owner", sm.Domain.Owner)
	d.Set("asset_size_bytes", sm.Domain.AssetSizeBytes)
	d.Set("repository_count", sm.Domain.RepositoryCount)
	d.Set("created_time", sm.Domain.CreatedTime.Format(time.RFC3339))

	return nil
}

func resourceAwsCodeArtifactDomainDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).codeartifactconn
	log.Printf("[DEBUG] Deleting CodeArtifact Domain: %s", d.Id())

	input := &codeartifact.DeleteDomainInput{
		Domain: aws.String(d.Id()),
	}

	_, err := conn.DeleteDomain(input)

	if err != nil {
		return fmt.Errorf("error deleting CodeArtifact Domain: %s", err)
	}

	return nil
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"reflect"
	"testing"

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

func TestAccAWSGluePartition_basic(t *testing.T) {
	rName := acctest.RandomWithPrefix("tf-acc-test")
	parValue := acctest.RandString(10)
	resourceName := "aws_glue_partition.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckGluePartitionDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccGluePartitionConfig(rName, parValue),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGluePartitionExists(resourceName),
					resource.TestCheckResourceAttr(resourceName, "database_name", rName),
					resource.TestCheckResourceAttr(resourceName, "partition_values.#", "1"),
					resource.TestCheckResourceAttrSet(resourceName, "creation_time"),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func TestAccAWSGluePartition_disappears(t *testing.T) {
	rName := acctest.RandomWithPrefix("tf-acc-test")
	parValue := acctest.RandString(10)
	resourceName := "aws_glue_partition.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckGluePartitionDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccGluePartitionConfig(rName, parValue),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGluePartitionExists(resourceName),
					testAccCheckResourceDisappears(testAccProvider, resourceAwsGluePartition(), resourceName),
				),
				ExpectNonEmptyPlan: true,
			},
		},
	})
}

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

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

		catalogID, dbName, tableName, values, err := readAwsGluePartitionID(rs.Primary.ID)
		if err != nil {
			return err
		}

		input := &glue.GetPartitionInput{
			DatabaseName:    aws.String(dbName),
			CatalogId:       aws.String(catalogID),
			TableName:       aws.String(tableName),
			PartitionValues: aws.StringSlice(values),
		}
		if _, err := conn.GetPartition(input); err != nil {
			if isAWSErr(err, glue.ErrCodeEntityNotFoundException, "") {
				continue
			}

			return err
		}
		return fmt.Errorf("still exists")
	}
	return nil
}

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

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

		catalogID, dbName, tableName, values, err := readAwsGluePartitionID(rs.Primary.ID)
		if err != nil {
			return err
		}

		conn := testAccProvider.Meta().(*AWSClient).glueconn
		out, err := conn.GetPartition(&glue.GetPartitionInput{
			DatabaseName:    aws.String(dbName),
			CatalogId:       aws.String(catalogID),
			TableName:       aws.String(tableName),
			PartitionValues: aws.StringSlice(values),
		})

		if err != nil {
			return err
		}

		if out.Partition == nil {
			return fmt.Errorf("No Glue Partition Found")
		}

		if !reflect.DeepEqual(aws.StringValueSlice(out.Partition.Values), values) {
			return fmt.Errorf("Glue Partition Mismatch")
		}

		return nil
	}
}

func testAccGluePartitionConfigBase(rName string) string {
	return fmt.Sprintf(`
resource "aws_glue_catalog_database" "test" {
  name = %[1]q
}

resource "aws_glue_catalog_table" "test" {
  name          = %[1]q
  database_name = "${aws_glue_catalog_database.test.name}"

  storage_descriptor {
    bucket_columns            = ["bucket_column_1"]
    compressed                = false
    input_format              = "SequenceFileInputFormat"
    location                  = "my_location"
    number_of_buckets         = 1
    output_format             = "SequenceFileInputFormat"
    stored_as_sub_directories = false

    parameters = {
      param1 = "param1_val"
    }

    columns {
      name    = "my_column_1"
      type    = "int"
      comment = "my_column1_comment"
    }

    columns {
      name    = "my_column_2"
      type    = "string"
      comment = "my_column2_comment"
    }

    ser_de_info {
      name = "ser_de_name"

      parameters = {
        param1 = "param_val_1"
      }

      serialization_library = "org.apache.hadoop.hive.serde2.columnar.ColumnarSerDe"
    }

    sort_columns {
      column     = "my_column_1"
      sort_order = 1
    }

    skewed_info {
      skewed_column_names = [
        "my_column_1",
      ]

      skewed_column_value_location_maps = {
        my_column_1 = "my_column_1_val_loc_map"
      }

      skewed_column_values = [
        "skewed_val_1",
      ]
    }
  }

  partition_keys {
    name    = "my_column_12"
    type    = "date"
    comment = "my_column_1_comment2"
  }
}
`, rName)
}

func testAccGluePartitionConfig(rName string, parValue string) string {
	return testAccGluePartitionConfigBase(rName) +
		fmt.Sprintf(`
resource "aws_glue_partition" "test" {
  database_name = "${aws_glue_catalog_database.test.name}"
  table_name    = "${aws_glue_catalog_table.test.name}"
  partition_values        =  ["%[1]s"]
}
`, parValue)
}
<commit_msg>tf 12 syntax for tests<commit_after>package aws

import (
	"fmt"
	"reflect"
	"testing"

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

func TestAccAWSGluePartition_basic(t *testing.T) {
	rName := acctest.RandomWithPrefix("tf-acc-test")
	parValue := acctest.RandString(10)
	resourceName := "aws_glue_partition.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckGluePartitionDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccGluePartitionConfig(rName, parValue),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGluePartitionExists(resourceName),
					resource.TestCheckResourceAttr(resourceName, "database_name", rName),
					resource.TestCheckResourceAttr(resourceName, "partition_values.#", "1"),
					resource.TestCheckResourceAttrSet(resourceName, "creation_time"),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func TestAccAWSGluePartition_disappears(t *testing.T) {
	rName := acctest.RandomWithPrefix("tf-acc-test")
	parValue := acctest.RandString(10)
	resourceName := "aws_glue_partition.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckGluePartitionDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccGluePartitionConfig(rName, parValue),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGluePartitionExists(resourceName),
					testAccCheckResourceDisappears(testAccProvider, resourceAwsGluePartition(), resourceName),
				),
				ExpectNonEmptyPlan: true,
			},
		},
	})
}

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

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

		catalogID, dbName, tableName, values, err := readAwsGluePartitionID(rs.Primary.ID)
		if err != nil {
			return err
		}

		input := &glue.GetPartitionInput{
			DatabaseName:    aws.String(dbName),
			CatalogId:       aws.String(catalogID),
			TableName:       aws.String(tableName),
			PartitionValues: aws.StringSlice(values),
		}
		if _, err := conn.GetPartition(input); err != nil {
			if isAWSErr(err, glue.ErrCodeEntityNotFoundException, "") {
				continue
			}

			return err
		}
		return fmt.Errorf("still exists")
	}
	return nil
}

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

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

		catalogID, dbName, tableName, values, err := readAwsGluePartitionID(rs.Primary.ID)
		if err != nil {
			return err
		}

		conn := testAccProvider.Meta().(*AWSClient).glueconn
		out, err := conn.GetPartition(&glue.GetPartitionInput{
			DatabaseName:    aws.String(dbName),
			CatalogId:       aws.String(catalogID),
			TableName:       aws.String(tableName),
			PartitionValues: aws.StringSlice(values),
		})

		if err != nil {
			return err
		}

		if out.Partition == nil {
			return fmt.Errorf("No Glue Partition Found")
		}

		if !reflect.DeepEqual(aws.StringValueSlice(out.Partition.Values), values) {
			return fmt.Errorf("Glue Partition Mismatch")
		}

		return nil
	}
}

func testAccGluePartitionConfigBase(rName string) string {
	return fmt.Sprintf(`
resource "aws_glue_catalog_database" "test" {
  name = %[1]q
}

resource "aws_glue_catalog_table" "test" {
  name          = %[1]q
  database_name = aws_glue_catalog_database.test.name

  storage_descriptor {
    bucket_columns            = ["bucket_column_1"]
    compressed                = false
    input_format              = "SequenceFileInputFormat"
    location                  = "my_location"
    number_of_buckets         = 1
    output_format             = "SequenceFileInputFormat"
    stored_as_sub_directories = false

    parameters = {
      param1 = "param1_val"
    }

    columns {
      name    = "my_column_1"
      type    = "int"
      comment = "my_column1_comment"
    }

    columns {
      name    = "my_column_2"
      type    = "string"
      comment = "my_column2_comment"
    }

    ser_de_info {
      name = "ser_de_name"

      parameters = {
        param1 = "param_val_1"
      }

      serialization_library = "org.apache.hadoop.hive.serde2.columnar.ColumnarSerDe"
    }

    sort_columns {
      column     = "my_column_1"
      sort_order = 1
    }

    skewed_info {
      skewed_column_names = [
        "my_column_1",
      ]

      skewed_column_value_location_maps = {
        my_column_1 = "my_column_1_val_loc_map"
      }

      skewed_column_values = [
        "skewed_val_1",
      ]
    }
  }

  partition_keys {
    name    = "my_column_12"
    type    = "date"
    comment = "my_column_1_comment2"
  }
}
`, rName)
}

func testAccGluePartitionConfig(rName string, parValue string) string {
	return testAccGluePartitionConfigBase(rName) +
		fmt.Sprintf(`
resource "aws_glue_partition" "test" {
  database_name    = aws_glue_catalog_database.test.name
  table_name       = aws_glue_catalog_table.test.name
  partition_values =  ["%[1]s"]
}
`, parValue)
}
<|endoftext|>


<commit_before>package midware

import (
	"github.com/ardanlabs/kit/cfg"
	"github.com/ardanlabs/kit/db"
	"github.com/ardanlabs/kit/log"
	"github.com/ardanlabs/kit/web/app"
)

// cfgDB config environmental variables.
const cfgMongoDB = "MONGO_DB"

// Mongo handles session management.
func Mongo(h app.Handler) app.Handler {

	// Check if mongodb is configured.
	dbName, err := cfg.String(cfgMongoDB)
	if err != nil {
		return func(c *app.Context) error {
			log.Dev(c.SessionID, "Mongo", "******> Mongo Not Configured")
			return h(c)
		}
	}

	// Wrap the handlers inside a session copy/close.
	return func(c *app.Context) error {
		mgoDB, err := db.NewMGO("Mongo", dbName)
		if err != nil {
			log.Error(c.SessionID, "Mongo", err, "Method[%s] URL[%s] RADDR[%s]", c.Request.Method, c.Request.URL.Path, c.Request.RemoteAddr)
			return app.ErrDBNotConfigured
		}

		log.Dev(c.SessionID, "Mongo", "******> Capture Mongo Session")
		c.DB = mgoDB
		defer func() {
			log.Dev(c.SessionID, "Mongo", "******> Release Mongo Session")
			mgoDB.CloseMGO("Mongo")
		}()

		return h(c)
	}
}
<commit_msg>Bad comment fixed<commit_after>package midware

import (
	"github.com/ardanlabs/kit/cfg"
	"github.com/ardanlabs/kit/db"
	"github.com/ardanlabs/kit/log"
	"github.com/ardanlabs/kit/web/app"
)

// cfgMongoDB config environmental variables.
const cfgMongoDB = "MONGO_DB"

// Mongo handles session management.
func Mongo(h app.Handler) app.Handler {

	// Check if mongodb is configured.
	dbName, err := cfg.String(cfgMongoDB)
	if err != nil {
		return func(c *app.Context) error {
			log.Dev(c.SessionID, "Mongo", "******> Mongo Not Configured")
			return h(c)
		}
	}

	// Wrap the handlers inside a session copy/close.
	return func(c *app.Context) error {
		mgoDB, err := db.NewMGO("Mongo", dbName)
		if err != nil {
			log.Error(c.SessionID, "Mongo", err, "Method[%s] URL[%s] RADDR[%s]", c.Request.Method, c.Request.URL.Path, c.Request.RemoteAddr)
			return app.ErrDBNotConfigured
		}

		log.Dev(c.SessionID, "Mongo", "******> Capture Mongo Session")
		c.DB = mgoDB
		defer func() {
			log.Dev(c.SessionID, "Mongo", "******> Release Mongo Session")
			mgoDB.CloseMGO("Mongo")
		}()

		return h(c)
	}
}
<|endoftext|>


<commit_before>package chalmers_chop

import (
	"errors"
	"github.com/mmcdole/gofeed"
	"strconv"
	"strings"
	"time"
)

// Defines the mapping between  sources and allergens
var allergenImages map[string]Allergen = map[string]Allergen{
	"gluten-white.png": Gluten,
	"gluten-black.png": Gluten,
	"egg-white.png":    Egg,
	"egg-black.png":    Egg,
	"lactose-white":    Lactose,
	"lactose-black":    Lactose,
	"FISH_black.png":   Fish,
	"FISH_white.png":   Fish,
}

func ParseDailyMenu(feed *gofeed.Feed) *Menu {
	var menu Menu

	menu.Title = feed.Title
	menu.Date = getMenuDate(feed)

	for _, item := range feed.Items {
		menu.AddDish(parseDish(item))
	}

	return &menu
}

func getMenuDate(feed *gofeed.Feed) string {
	/*
		We could assume that all "daily menus" should have today's date and generate it ourselves,
		however, to avoid trouble with timezones and other types of clock skew we prefer fetching
		it from the feed, if possible.
	*/
	d, err := parseMenuDate(feed)

	// Default to today's date
	if err != nil {
		return time.Now().Format("2006-01-02")
	}

	return d
}

/*
The menu date is retrieved by parsing the <guid> and fetching the last 10 runes, which
will always be a date on the format YYYY-mm-dd
*/
func parseMenuDate(feed *gofeed.Feed) (string, error) {
	if len(feed.Items) == 0 {
		return "", errors.New("Could not find menu date")
	}

	t := feed.Items[0].GUID

	return string(t[len(t)-10:]), nil
}

/*
Parses a dish from an item

The dish contents, price, and allergy information is contained in a CDATA tag inside the <description> tag. For example:

<description>
	<![CDATA[Beef, wheat bread, french fries@80
   >

]]>
		 ^                               ^                                                                                ^
		 contents                        price                                                                             allergen
 </description>

*/
func parseDish(item *gofeed.Item) Dish {
	var dish Dish

	dish.Name = item.Title

	desc := trimCDATA(item.Description)

	dish.Contents = parseContents(desc)
	dish.Price = parsePrice(desc)
	dish.Allergens = parseAllergens(desc)

	return dish
}

// The dish contents is all text content of the <description> tag leading up to the @ sign
func parseContents(desc string) string {
	return strings.Split(desc, "@")[0]
}

// The dish price is all text content of the <description> tag following the first @ sign, up until the first space sign
func parsePrice(desc string) int {
	afterAtSign := strings.Split(desc, "@")[1]
	priceText := beforeSpace(afterAtSign)

	p, err := strconv.Atoi(priceText)

	if err != nil {
		return 0
	}

	return p
}

/*
The dish allergens can be determined by searching the <description> tag for
the filenames found in allergenImages.

For example, the following dish contains the allergen Gluten ("gluten-white.png"):

<description>
	<![CDATA[Hamburger of the Day@80
   >

]]>
                                                                                ^^^^^^^^^^^^^^^^
</description>
*/
func parseAllergens(desc string) []Allergen {
	var al []Allergen

	for k, a := range allergenImages {
		if strings.Contains(desc, k) {
			al = append(al, a)
		}
	}

	return al
}

func trimCDATA(text string) string {
	if !strings.HasPrefix(text, "<![CDATA") || !strings.HasSuffix(text, "]]>") {
		return text
	}

	return strings.TrimSuffix(strings.TrimPrefix(text, "<![CDATA"), "]]>")
}

func beforeSpace(str string) string {
	indexFunc := func(r rune) bool {
		return r == ' '
	}

	value := strings.IndexFunc(str, indexFunc)

	if value >= 0 && value <= len(str) {
		return str[:value]
	}

	return str
}
<commit_msg>Improve getMenuDate documentation<commit_after>package chalmers_chop

import (
	"errors"
	"github.com/mmcdole/gofeed"
	"strconv"
	"strings"
	"time"
)

// Defines the mapping between  sources and allergens
var allergenImages map[string]Allergen = map[string]Allergen{
	"gluten-white.png": Gluten,
	"gluten-black.png": Gluten,
	"egg-white.png":    Egg,
	"egg-black.png":    Egg,
	"lactose-white":    Lactose,
	"lactose-black":    Lactose,
	"FISH_black.png":   Fish,
	"FISH_white.png":   Fish,
}

func ParseDailyMenu(feed *gofeed.Feed) *Menu {
	var menu Menu

	menu.Title = feed.Title
	menu.Date = getMenuDate(feed)

	for _, item := range feed.Items {
		menu.AddDish(parseDish(item))
	}

	return &menu
}

func getMenuDate(feed *gofeed.Feed) string {
	d, err := parseMenuDate(feed)

	if err != nil {
		// Default to today's date
		return time.Now().Format("2006-01-02")
	}

	return d
}

/*
The menu date is retrieved by parsing the <guid> and fetching the last 10 runes, which
will always be a date on the format YYYY-mm-dd
*/
func parseMenuDate(feed *gofeed.Feed) (string, error) {
	if len(feed.Items) == 0 {
		return "", errors.New("Could not find menu date")
	}

	t := feed.Items[0].GUID

	return string(t[len(t)-10:]), nil
}

/*
Parses a dish from an item

The dish contents, price, and allergy information is contained in a CDATA tag inside the <description> tag. For example:

<description>
	<![CDATA[Beef, wheat bread, french fries@80
   >

]]>
		 ^                               ^                                                                                ^
		 contents                        price                                                                             allergen
 </description>

*/
func parseDish(item *gofeed.Item) Dish {
	var dish Dish

	dish.Name = item.Title

	desc := trimCDATA(item.Description)

	dish.Contents = parseContents(desc)
	dish.Price = parsePrice(desc)
	dish.Allergens = parseAllergens(desc)

	return dish
}

// The dish contents is all text content of the <description> tag leading up to the @ sign
func parseContents(desc string) string {
	return strings.Split(desc, "@")[0]
}

// The dish price is all text content of the <description> tag following the first @ sign, up until the first space sign
func parsePrice(desc string) int {
	afterAtSign := strings.Split(desc, "@")[1]
	priceText := beforeSpace(afterAtSign)

	p, err := strconv.Atoi(priceText)

	if err != nil {
		return 0
	}

	return p
}

/*
The dish allergens can be determined by searching the <description> tag for
the filenames found in allergenImages.

For example, the following dish contains the allergen Gluten ("gluten-white.png"):

<description>
	<![CDATA[Hamburger of the Day@80
   >

]]>
                                                                                ^^^^^^^^^^^^^^^^
</description>
*/
func parseAllergens(desc string) []Allergen {
	var al []Allergen

	for k, a := range allergenImages {
		if strings.Contains(desc, k) {
			al = append(al, a)
		}
	}

	return al
}

func trimCDATA(text string) string {
	if !strings.HasPrefix(text, "<![CDATA") || !strings.HasSuffix(text, "]]>") {
		return text
	}

	return strings.TrimSuffix(strings.TrimPrefix(text, "<![CDATA"), "]]>")
}

func beforeSpace(str string) string {
	indexFunc := func(r rune) bool {
		return r == ' '
	}

	value := strings.IndexFunc(str, indexFunc)

	if value >= 0 && value <= len(str) {
		return str[:value]
	}

	return str
}
<|endoftext|>


<commit_before>package logger

import (
	"bytes"
	"fmt"
	"os"
	"strings"
	"syscall"
	"testing"

	"github.com/stripe/unilog/json"
)

var shakespeare = []string{
	"To be, or not to be, that is the question-",
	"Whether 'tis Nobler in the mind to suffer",
	"The Slings and Arrows of outrageous Fortune,",
	"Or to take Arms against a Sea of troubles,",
	"And by opposing end them?",
}

func TestReadlines(t *testing.T) {
	r := strings.NewReader(strings.Join(shakespeare, "\n"))
	ch := make(chan struct{})
	defer close(ch)
	lc, _ := readlines(r, 1, ch)
	var i int
	for line := range lc {
		if line != shakespeare[i] {
			t.Errorf("Line %d should have been %q, but got %q", i,
				shakespeare[i], line)
		}
		i++
	}
	if i != len(shakespeare) {
		t.Errorf("Did not get enough lines of shakespeare")
	}
}

var big = strings.Repeat("Unique New York", 9000)

func TestReadlinesWithLongLines(t *testing.T) {
	r := strings.NewReader(big)
	ch := make(chan struct{})
	defer close(ch)

	lc, _ := readlines(r, 1, ch)
	line := <-lc
	if line != big {
		t.Errorf("Lines do not match! Got %d bytes; expected %d",
			len(line), len(big))
	}
	if <-lc != "" {
		t.Error("Did not reach EOF")
	}
}

// double the first two instances of the character "e"
type doubleEFilter struct{}

func (ee *doubleEFilter) FilterLine(line string) string {
	return strings.Replace(line, "e", "ee", 2)
}

func (ee *doubleEFilter) FilterJSON(line *json.LogLine) {
	msg := (*line)["message"].(string)
	(*line)["message"] = strings.Replace(msg, "e", "ee", 2)
}

type isToAintFilter struct{}

func (ee *isToAintFilter) FilterLine(line string) string {
	return strings.Replace(line, "is", "ain't", -1)
}

func (ee *isToAintFilter) FilterJSON(line *json.LogLine) {
	msg := (*line)["message"].(string)
	(*line)["message"] = strings.Replace(msg, "is", "ain't", -1)
}

func TestFilterFunction(t *testing.T) {
	var input = shakespeare[0]
	const expected = "To bee, or not to bee, that ain't the question-\n"

	u := &Unilog{}

	u.Filters = []Filter{
		Filter(&doubleEFilter{}),
		Filter(&isToAintFilter{}),
	}

	result := u.format(input)
	if result != expected {
		t.Errorf("expected %q, found %q", expected, result)
	}
}

func TestTwoStateExit(t *testing.T) {
	u := &Unilog{}
	exitCode := -1

	term := make(chan os.Signal, 2)
	quit := make(chan os.Signal, 2)
	exit := make(chan int, 2)

	u.sigTerm = term
	u.sigQuit = quit
	u.exit = func(code int) {
		exitCode = code
		exit <- 1
	}
	u.shutdown = make(chan struct{})

	go u.run()

	term <- syscall.SIGTERM
	<-u.shutdown
	quit <- syscall.SIGQUIT

	<-exit
	if exitCode != 1 {
		t.Error("Did not call exit.")
	}
}

func TestSigTermNoExit(t *testing.T) {
	u := &Unilog{}

	term := make(chan os.Signal, 1)
	quit := make(chan os.Signal, 1)

	u.sigTerm = term
	u.sigQuit = quit
	u.exit = func(code int) {
		t.Error("Called exit.")
	}
	u.shutdown = make(chan struct{})

	term <- syscall.SIGTERM
	if !u.tick() {
		t.Error("Tick returned false.")
	}
}

func TestSigQuitNoOp(t *testing.T) {
	u := &Unilog{}

	term := make(chan os.Signal, 1)
	quit := make(chan os.Signal, 1)

	u.sigTerm = term
	u.sigQuit = quit
	u.exit = func(code int) {
		t.Error("Called exit.")
	}
	u.shutdown = make(chan struct{})

	quit <- syscall.SIGQUIT
	if !u.tick() {
		t.Error("Tick returned false.")
	}
}

type MockClient struct {
	Counts map[string]int64
}

func (mc *MockClient) Count(name string, value int64, tags []string, rate float64) error {
	var buffer bytes.Buffer
	for _, tag := range tags {
		buffer.WriteString("[")
		buffer.WriteString(tag)
		buffer.WriteString("]")
	}
	buffer.WriteString(name)
	mc.Counts[buffer.String()] += value
	return nil
}

func TestNoTags(t *testing.T) {
	client := &MockClient{Counts: make(map[string]int64)}
	for i := 0; i < 100; i++ {
		IndependentCount(client, "metric", 10, nil, 1)
	}
	if client.Counts["metric"] != 1000 {
		t.Errorf("Count was %d, not %d", client.Counts["metric"], 1000)
	}
}

func TestWithGlobalTags(t *testing.T) {
	client := &MockClient{Counts: make(map[string]int64)}
	for i := 0; i < 100; i++ {
		IndependentCount(client, "metric", 10, []string{"foo:bar"}, 1)
		IndependentCount(client, "metric", 5, []string{"baz:qaz", "veneurglobalonly:true"}, 1)
	}
	var tests = map[string]int64{
		"[foo:bar]metric":                        1000,
		"[baz:qaz][veneurglobalonly:true]metric": 500,
	}
	for key, value := range tests {
		if client.Counts[key] != value {
			t.Errorf("Count for %s was %d, not %d", key, client.Counts[key], value)
		}
	}
}

func TestWithIndependentTags(t *testing.T) {
	// Save and set tagState
	tmp := tagState
	tagState = newIndependentTags([]string{"veneurglobalonly:true", "owner:observability"})

	client := &MockClient{Counts: make(map[string]int64)}
	for i := 0; i < 100; i++ {
		IndependentCount(client, "metric", 10, nil, 1)
		IndependentCount(client, "metric", 5, []string{"baz:qaz"}, 1)
	}
	var tests = map[string]int64{
		"metric": 1000,
		"[veneurglobalonly:true]metric.veneurglobalonly":          1000,
		"[owner:observability]metric.owner":                       1000,
		"[baz:qaz]metric":                                         500,
		"[baz:qaz][veneurglobalonly:true]metric.veneurglobalonly": 500,
		"[baz:qaz][owner:observability]metric.owner":              500,
	}
	for key, value := range tests {
		if client.Counts[key] != value {
			t.Errorf("Count for %s was %d, not %d", key, client.Counts[key], value)
		}
	}
	// Restore tagState
	tagState = tmp
}

func TestSentryPanic(t *testing.T) {
	defer func() {
		r := recover()
		if r == nil {
			t.Errorf("Expected panic, but got none")
		} else if !strings.HasPrefix(fmt.Sprintf("%v", r), "Invalid DSN:") {
			t.Errorf("Expected `Invalid DSN: ...`, but got: %s", r)
		}
	}()

	u := &Unilog{SentryDSN: "foo"}
	u.setupSentry()
}

func TestSentrySuccess(t *testing.T) {
	defer func() {
		r := recover()
		if r != nil {
			t.Errorf("Expected no panic, but got: %s", r)
		}
	}()

	u := &Unilog{SentryDSN: "https://123:456@foo/789"}
	u.setupSentry()
}
<commit_msg>Test low-level logLine and logJSON functions. Catches the bug with the missing return.<commit_after>package logger

import (
	"bytes"
	encjson "encoding/json"
	"fmt"
	"os"
	"strings"
	"syscall"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stripe/unilog/filters"
	"github.com/stripe/unilog/json"
)

var shakespeare = []string{
	"To be, or not to be, that is the question-",
	"Whether 'tis Nobler in the mind to suffer",
	"The Slings and Arrows of outrageous Fortune,",
	"Or to take Arms against a Sea of troubles,",
	"And by opposing end them?",
}

func TestReadlines(t *testing.T) {
	r := strings.NewReader(strings.Join(shakespeare, "\n"))
	ch := make(chan struct{})
	defer close(ch)
	lc, _ := readlines(r, 1, ch)
	var i int
	for line := range lc {
		if line != shakespeare[i] {
			t.Errorf("Line %d should have been %q, but got %q", i,
				shakespeare[i], line)
		}
		i++
	}
	if i != len(shakespeare) {
		t.Errorf("Did not get enough lines of shakespeare")
	}
}

var big = strings.Repeat("Unique New York", 9000)

func TestReadlinesWithLongLines(t *testing.T) {
	r := strings.NewReader(big)
	ch := make(chan struct{})
	defer close(ch)

	lc, _ := readlines(r, 1, ch)
	line := <-lc
	if line != big {
		t.Errorf("Lines do not match! Got %d bytes; expected %d",
			len(line), len(big))
	}
	if <-lc != "" {
		t.Error("Did not reach EOF")
	}
}

// double the first two instances of the character "e"
type doubleEFilter struct{}

func (ee *doubleEFilter) FilterLine(line string) string {
	return strings.Replace(line, "e", "ee", 2)
}

func (ee *doubleEFilter) FilterJSON(line *json.LogLine) {
	msg := (*line)["message"].(string)
	(*line)["message"] = strings.Replace(msg, "e", "ee", 2)
}

type isToAintFilter struct{}

func (ee *isToAintFilter) FilterLine(line string) string {
	return strings.Replace(line, "is", "ain't", -1)
}

func (ee *isToAintFilter) FilterJSON(line *json.LogLine) {
	msg := (*line)["message"].(string)
	(*line)["message"] = strings.Replace(msg, "is", "ain't", -1)
}

func TestFilterFunction(t *testing.T) {
	var input = shakespeare[0]
	const expected = "To bee, or not to bee, that ain't the question-\n"

	u := &Unilog{}

	u.Filters = []Filter{
		Filter(&doubleEFilter{}),
		Filter(&isToAintFilter{}),
	}

	result := u.format(input)
	if result != expected {
		t.Errorf("expected %q, found %q", expected, result)
	}
}

func TestTwoStateExit(t *testing.T) {
	u := &Unilog{}
	exitCode := -1

	term := make(chan os.Signal, 2)
	quit := make(chan os.Signal, 2)
	exit := make(chan int, 2)

	u.sigTerm = term
	u.sigQuit = quit
	u.exit = func(code int) {
		exitCode = code
		exit <- 1
	}
	u.shutdown = make(chan struct{})

	go u.run()

	term <- syscall.SIGTERM
	<-u.shutdown
	quit <- syscall.SIGQUIT

	<-exit
	if exitCode != 1 {
		t.Error("Did not call exit.")
	}
}

func TestSigTermNoExit(t *testing.T) {
	u := &Unilog{}

	term := make(chan os.Signal, 1)
	quit := make(chan os.Signal, 1)

	u.sigTerm = term
	u.sigQuit = quit
	u.exit = func(code int) {
		t.Error("Called exit.")
	}
	u.shutdown = make(chan struct{})

	term <- syscall.SIGTERM
	if !u.tick() {
		t.Error("Tick returned false.")
	}
}

func TestSigQuitNoOp(t *testing.T) {
	u := &Unilog{}

	term := make(chan os.Signal, 1)
	quit := make(chan os.Signal, 1)

	u.sigTerm = term
	u.sigQuit = quit
	u.exit = func(code int) {
		t.Error("Called exit.")
	}
	u.shutdown = make(chan struct{})

	quit <- syscall.SIGQUIT
	if !u.tick() {
		t.Error("Tick returned false.")
	}
}

type MockClient struct {
	Counts map[string]int64
}

func (mc *MockClient) Count(name string, value int64, tags []string, rate float64) error {
	var buffer bytes.Buffer
	for _, tag := range tags {
		buffer.WriteString("[")
		buffer.WriteString(tag)
		buffer.WriteString("]")
	}
	buffer.WriteString(name)
	mc.Counts[buffer.String()] += value
	return nil
}

func TestNoTags(t *testing.T) {
	client := &MockClient{Counts: make(map[string]int64)}
	for i := 0; i < 100; i++ {
		IndependentCount(client, "metric", 10, nil, 1)
	}
	if client.Counts["metric"] != 1000 {
		t.Errorf("Count was %d, not %d", client.Counts["metric"], 1000)
	}
}

func TestWithGlobalTags(t *testing.T) {
	client := &MockClient{Counts: make(map[string]int64)}
	for i := 0; i < 100; i++ {
		IndependentCount(client, "metric", 10, []string{"foo:bar"}, 1)
		IndependentCount(client, "metric", 5, []string{"baz:qaz", "veneurglobalonly:true"}, 1)
	}
	var tests = map[string]int64{
		"[foo:bar]metric":                        1000,
		"[baz:qaz][veneurglobalonly:true]metric": 500,
	}
	for key, value := range tests {
		if client.Counts[key] != value {
			t.Errorf("Count for %s was %d, not %d", key, client.Counts[key], value)
		}
	}
}

func TestWithIndependentTags(t *testing.T) {
	// Save and set tagState
	tmp := tagState
	tagState = newIndependentTags([]string{"veneurglobalonly:true", "owner:observability"})

	client := &MockClient{Counts: make(map[string]int64)}
	for i := 0; i < 100; i++ {
		IndependentCount(client, "metric", 10, nil, 1)
		IndependentCount(client, "metric", 5, []string{"baz:qaz"}, 1)
	}
	var tests = map[string]int64{
		"metric": 1000,
		"[veneurglobalonly:true]metric.veneurglobalonly":          1000,
		"[owner:observability]metric.owner":                       1000,
		"[baz:qaz]metric":                                         500,
		"[baz:qaz][veneurglobalonly:true]metric.veneurglobalonly": 500,
		"[baz:qaz][owner:observability]metric.owner":              500,
	}
	for key, value := range tests {
		if client.Counts[key] != value {
			t.Errorf("Count for %s was %d, not %d", key, client.Counts[key], value)
		}
	}
	// Restore tagState
	tagState = tmp
}

func TestSentryPanic(t *testing.T) {
	defer func() {
		r := recover()
		if r == nil {
			t.Errorf("Expected panic, but got none")
		} else if !strings.HasPrefix(fmt.Sprintf("%v", r), "Invalid DSN:") {
			t.Errorf("Expected `Invalid DSN: ...`, but got: %s", r)
		}
	}()

	u := &Unilog{SentryDSN: "foo"}
	u.setupSentry()
}

func TestSentrySuccess(t *testing.T) {
	defer func() {
		r := recover()
		if r != nil {
			t.Errorf("Expected no panic, but got: %s", r)
		}
	}()

	u := &Unilog{SentryDSN: "https://123:456@foo/789"}
	u.setupSentry()
}

type mockFile struct {
	buf *bytes.Buffer
}

func (m mockFile) Write(p []byte) (int, error) {
	return m.buf.Write(p)
}
func (mockFile) Close() error {
	return nil
}

func getLogLine(u *Unilog, line string) string {
	var buf bytes.Buffer
	u.file = mockFile{buf: &buf}

	u.logLine(line)
	return buf.String()
}

func getLogJSON(u *Unilog, line string) string {
	var buf bytes.Buffer
	u.file = mockFile{buf: &buf}
	u.jsonEncoder = encjson.NewEncoder(u.file)

	u.logJSON(line)
	return buf.String()
}

func TestLogLine(t *testing.T) {
	out := getLogLine(&Unilog{}, "hi")
	assert.Equal(t, "hi\n", out)

	out = getLogLine(&Unilog{
		Filters: []Filter{
			filters.TimePrefixFilter{Format: "foo"},
		},
	}, "hi")
	assert.Equal(t, "[foo] hi\n", out)
}

func TestLogJSON(t *testing.T) {
	out := getLogJSON(&Unilog{}, "hi")
	assert.Equal(t, "hi\n", out)

	out = getLogJSON(&Unilog{}, `{"message":"hi"}`)
	assert.Regexp(t, `\{"timestamp":[\d\.]+,"message":"hi"}\n`, out)
}
<|endoftext|>


<commit_before>package lrucache

// Concurrent duplicate calls (same arg) are unified into one call. The result
// is returned to all callers by the wrapper.
//
// Call with the empty string to terminate. Running operations will complete
// but it is an error to invoke this function after that.
func NoConcurrentDupes(f func(string) Cacheable) func(string) Cacheable {
	type req struct {
		key        string
		resultChan chan Cacheable
	}
	opchan := make(chan req)
	go func() {
		// Push result of call to wrapped function down this channel
		waiting := map[string]chan Cacheable{}
		for r := range opchan {
			if r.key == "" {
				close(opchan)
				break
			}
			reschan, inprogress := waiting[r.key]
			if !inprogress {
				reschan = make(chan Cacheable)
				waiting[r.key] = reschan
			}
			// Explicit argument to deal with Go closure semantics
			go func(r req) {
				var result Cacheable
				if inprogress {
					// Already waiting for a call to complete, subscribe to result
					result = <-reschan
					// Pass the result to the waiting call to wrapper
					r.resultChan <- result
					close(r.resultChan)
				} else {
					// Get result from wrapped function directly
					result = f(r.key)
				}
				reschan <- result
			}(r)
		}
	}()
	return func(key string) Cacheable {
		res := make(chan Cacheable)
		opchan <- req{key, res}
		return <-res
	}
}
<commit_msg>Reorganize nocondupes code (legibility)<commit_after>package lrucache

// Process operations concurrently except for those with an identical key.
func nocondupesMainloop(f func(string) Cacheable, opchan chan reqGet) {
	// Push result of call to wrapped function down this channel
	waiting := map[string]chan Cacheable{}
	for r := range opchan {
		reschan, inprogress := waiting[r.id]
		if !inprogress {
			reschan = make(chan Cacheable)
			waiting[r.id] = reschan
		}
		// Explicit argument to deal with Go closure semantics
		go func(r reqGet) {
			var result Cacheable
			if inprogress {
				// Already waiting for a call to complete, subscribe to result
				result = <-reschan
				// Pass the result to the waiting call to wrapper
				r.reply <- result
				close(r.reply)
			} else {
				// Get result from wrapped function directly
				result = f(r.id)
			}
			reschan <- result
		}(r)
	}
}

// Concurrent duplicate calls (same arg) are unified into one call. The result
// is returned to all callers by the wrapper.
//
// Call with the empty string to terminate. Running operations will complete
// but it is an error to invoke this function after that.
func NoConcurrentDupes(f func(string) Cacheable) func(string) Cacheable {
	opchan := make(chan reqGet)
	go nocondupesMainloop(f, opchan)
	return func(key string) Cacheable {
		res := make(chan Cacheable)
		if key == "" {
			close(opchan)
			return nil
		}
		opchan <- reqGet{key, res}
		return <-res
	}
}
<|endoftext|>


<commit_before>package flying_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"
	"time"

	"github.com/mgutz/ansi"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

var _ = Describe("Flying", func() {
	var tmpdir string
	var fixture string

	BeforeEach(func() {
		var err error

		tmpdir, err = ioutil.TempDir("", "fly-test")
		Ω(err).ShouldNot(HaveOccurred())

		fixture = filepath.Join(tmpdir, "fixture")

		err = os.MkdirAll(fixture, 0755)
		Ω(err).ShouldNot(HaveOccurred())

		err = ioutil.WriteFile(
			filepath.Join(fixture, "run"),
			[]byte(`#!/bin/sh
echo some output
echo FOO is $FOO
echo ARGS are "$@"
exit 0
`),
			0755,
		)
		Ω(err).ShouldNot(HaveOccurred())

		err = ioutil.WriteFile(
			filepath.Join(fixture, "build.yml"),
			[]byte(`---
platform: linux

image: /var/vcap/packages/busybox

inputs:
  - name: fixture

params:
  FOO: 1

run:
  path: fixture/run
`),
			0644,
		)
		Ω(err).ShouldNot(HaveOccurred())
	})

	AfterEach(func() {
		os.RemoveAll(tmpdir)
	})

	start := func(cmd *exec.Cmd) *gexec.Session {
		session, err := gexec.Start(
			cmd,
			gexec.NewPrefixedWriter(
				fmt.Sprintf("%s%s ", ansi.Color("[o]", "green"), ansi.Color("[fly]", "blue")),
				GinkgoWriter,
			),
			gexec.NewPrefixedWriter(
				fmt.Sprintf("%s%s ", ansi.Color("[e]", "red+bright"), ansi.Color("[fly]", "blue")),
				GinkgoWriter,
			),
		)
		Ω(err).ShouldNot(HaveOccurred())

		return session
	}

	It("works", func() {
		fly := exec.Command(flyBin, "--", "SOME", "ARGS")
		fly.Dir = fixture

		session := start(fly)

		Eventually(session, 30*time.Second).Should(gexec.Exit(0))

		Ω(session).Should(gbytes.Say("some output"))
		Ω(session).Should(gbytes.Say("FOO is 1"))
		Ω(session).Should(gbytes.Say("ARGS are SOME ARGS"))
	})

	Describe("hijacking", func() {
		It("executes an interactive command in a running task's container", func() {
			err := ioutil.WriteFile(
				filepath.Join(fixture, "run"),
				[]byte(`#!/bin/sh
mkfifo /tmp/fifo
echo waiting
cat < /tmp/fifo
`),
				0755,
			)
			Ω(err).ShouldNot(HaveOccurred())

			fly := exec.Command(flyBin)
			fly.Dir = fixture

			flyS := start(fly)

			Eventually(flyS, 30*time.Second).Should(gbytes.Say("waiting"))

			hijack := exec.Command(flyBin, "hijack", "--", "sh", "-c", "echo marco > /tmp/fifo")

			hijackS := start(hijack)

			Eventually(flyS, 15*time.Second).Should(gbytes.Say("marco"))

			Eventually(hijackS, 5*time.Second).Should(gexec.Exit())

			Eventually(flyS, 10*time.Second).Should(gexec.Exit(0))
		})
	})

	Describe("aborting", func() {
		It("terminates the running task", func() {
			err := ioutil.WriteFile(
				filepath.Join(fixture, "run"),
				[]byte(`#!/bin/sh
trap "echo task got sigterm; exit 1" SIGTERM
sleep 1000 &
echo waiting
wait
`),
				0755,
			)
			Ω(err).ShouldNot(HaveOccurred())

			fly := exec.Command(flyBin)
			fly.Dir = fixture

			flyS := start(fly)

			Eventually(flyS, 30*time.Second).Should(gbytes.Say("waiting"))

			flyS.Signal(syscall.SIGTERM)

			Eventually(flyS, 10*time.Second).Should(gbytes.Say("task got sigterm"))

			// build should have been aborted
			Eventually(flyS, 10*time.Second).Should(gexec.Exit(3))
		})
	})
})
<commit_msg>Testflight now runs execute as its command again<commit_after>package flying_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"
	"time"

	"github.com/mgutz/ansi"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

var _ = Describe("Flying", func() {
	var tmpdir string
	var fixture string

	BeforeEach(func() {
		var err error

		tmpdir, err = ioutil.TempDir("", "fly-test")
		Ω(err).ShouldNot(HaveOccurred())

		fixture = filepath.Join(tmpdir, "fixture")

		err = os.MkdirAll(fixture, 0755)
		Ω(err).ShouldNot(HaveOccurred())

		err = ioutil.WriteFile(
			filepath.Join(fixture, "run"),
			[]byte(`#!/bin/sh
echo some output
echo FOO is $FOO
echo ARGS are "$@"
exit 0
`),
			0755,
		)
		Ω(err).ShouldNot(HaveOccurred())

		err = ioutil.WriteFile(
			filepath.Join(fixture, "build.yml"),
			[]byte(`---
platform: linux

image: /var/vcap/packages/busybox

inputs:
  - name: fixture

params:
  FOO: 1

run:
  path: fixture/run
`),
			0644,
		)
		Ω(err).ShouldNot(HaveOccurred())
	})

	AfterEach(func() {
		os.RemoveAll(tmpdir)
	})

	start := func(cmd *exec.Cmd) *gexec.Session {
		session, err := gexec.Start(
			cmd,
			gexec.NewPrefixedWriter(
				fmt.Sprintf("%s%s ", ansi.Color("[o]", "green"), ansi.Color("[fly]", "blue")),
				GinkgoWriter,
			),
			gexec.NewPrefixedWriter(
				fmt.Sprintf("%s%s ", ansi.Color("[e]", "red+bright"), ansi.Color("[fly]", "blue")),
				GinkgoWriter,
			),
		)
		Ω(err).ShouldNot(HaveOccurred())

		return session
	}

	It("works", func() {
		fly := exec.Command(flyBin, "execute", "-c", "build.yml", "--", "SOME", "ARGS")
		fly.Dir = fixture

		session := start(fly)

		Eventually(session, 30*time.Second).Should(gexec.Exit(0))

		Ω(session).Should(gbytes.Say("some output"))
		Ω(session).Should(gbytes.Say("FOO is 1"))
		Ω(session).Should(gbytes.Say("ARGS are SOME ARGS"))
	})

	Describe("hijacking", func() {
		It("executes an interactive command in a running task's container", func() {
			err := ioutil.WriteFile(
				filepath.Join(fixture, "run"),
				[]byte(`#!/bin/sh
mkfifo /tmp/fifo
echo waiting
cat < /tmp/fifo
`),
				0755,
			)
			Ω(err).ShouldNot(HaveOccurred())

			fly := exec.Command(flyBin, "execute")
			fly.Dir = fixture

			flyS := start(fly)

			Eventually(flyS, 30*time.Second).Should(gbytes.Say("waiting"))

			hijack := exec.Command(flyBin, "hijack", "--", "sh", "-c", "echo marco > /tmp/fifo")

			hijackS := start(hijack)

			Eventually(flyS, 15*time.Second).Should(gbytes.Say("marco"))

			Eventually(hijackS, 5*time.Second).Should(gexec.Exit())

			Eventually(flyS, 10*time.Second).Should(gexec.Exit(0))
		})
	})

	Describe("aborting", func() {
		It("terminates the running task", func() {
			err := ioutil.WriteFile(
				filepath.Join(fixture, "run"),
				[]byte(`#!/bin/sh
trap "echo task got sigterm; exit 1" SIGTERM
sleep 1000 &
echo waiting
wait
`),
				0755,
			)
			Ω(err).ShouldNot(HaveOccurred())

			fly := exec.Command(flyBin, "execute")
			fly.Dir = fixture

			flyS := start(fly)

			Eventually(flyS, 30*time.Second).Should(gbytes.Say("waiting"))

			flyS.Signal(syscall.SIGTERM)

			Eventually(flyS, 10*time.Second).Should(gbytes.Say("task got sigterm"))

			// build should have been aborted
			Eventually(flyS, 10*time.Second).Should(gexec.Exit(3))
		})
	})
})
<|endoftext|>


<commit_before>package audit

import (
	"encoding/json"
	"io"
	"time"

	"github.com/hashicorp/vault/logical"
)

// FormatJSON is a Formatter implementation that structures data into
// a JSON format.
type FormatJSON struct{}

func (f *FormatJSON) FormatRequest(
	w io.Writer,
	auth *logical.Auth,
	req *logical.Request,
	err error) error {

	// If auth is nil, make an empty one
	if auth == nil {
		auth = new(logical.Auth)
	}
	var errString string
	if err != nil {
		errString = err.Error()
	}

	// Encode!
	enc := json.NewEncoder(w)
	return enc.Encode(&JSONRequestEntry{
		Time:  time.Now().UTC().Format(time.RFC3339),
		Type:  "request",
		Error: errString,

		Auth: JSONAuth{
			DisplayName: auth.DisplayName,
			Policies:    auth.Policies,
			Metadata:    auth.Metadata,
		},

		Request: JSONRequest{
			ClientToken: req.ClientToken,
			Operation:   req.Operation,
			Path:        req.Path,
			Data:        req.Data,
			RemoteAddr:  getRemoteAddr(req),
		},
	})
}

func (f *FormatJSON) FormatResponse(
	w io.Writer,
	auth *logical.Auth,
	req *logical.Request,
	resp *logical.Response,
	err error) error {
	// If things are nil, make empty to avoid panics
	if auth == nil {
		auth = new(logical.Auth)
	}
	if resp == nil {
		resp = new(logical.Response)
	}
	var errString string
	if err != nil {
		errString = err.Error()
	}

	var respAuth *JSONAuth
	if resp.Auth != nil {
		respAuth = &JSONAuth{
			ClientToken: resp.Auth.ClientToken,
			Accessor:    resp.Auth.Accessor,
			DisplayName: resp.Auth.DisplayName,
			Policies:    resp.Auth.Policies,
			Metadata:    resp.Auth.Metadata,
		}
	}

	var respSecret *JSONSecret
	if resp.Secret != nil {
		respSecret = &JSONSecret{
			LeaseID: resp.Secret.LeaseID,
		}
	}

	// Encode!
	enc := json.NewEncoder(w)
	return enc.Encode(&JSONResponseEntry{
		Time:  time.Now().UTC().Format(time.RFC3339),
		Type:  "response",
		Error: errString,

		Auth: JSONAuth{
			DisplayName: auth.DisplayName,
			Policies:    auth.Policies,
			Metadata:    auth.Metadata,
		},

		Request: JSONRequest{
			Operation:  req.Operation,
			Path:       req.Path,
			Data:       req.Data,
			RemoteAddr: getRemoteAddr(req),
		},

		Response: JSONResponse{
			Auth:     respAuth,
			Secret:   respSecret,
			Data:     resp.Data,
			Redirect: resp.Redirect,
		},
	})
}

// JSONRequest is the structure of a request audit log entry in JSON.
type JSONRequestEntry struct {
	Time    string      `json:"time"`
	Type    string      `json:"type"`
	Auth    JSONAuth    `json:"auth"`
	Request JSONRequest `json:"request"`
	Error   string      `json:"error"`
}

// JSONResponseEntry is the structure of a response audit log entry in JSON.
type JSONResponseEntry struct {
	Time     string       `json:"time"`
	Type     string       `json:"type"`
	Error    string       `json:"error"`
	Auth     JSONAuth     `json:"auth"`
	Request  JSONRequest  `json:"request"`
	Response JSONResponse `json:"response"`
}

type JSONRequest struct {
	Operation   logical.Operation      `json:"operation"`
	ClientToken string                 `json:"client_token"`
	Path        string                 `json:"path"`
	Data        map[string]interface{} `json:"data"`
	RemoteAddr  string                 `json:"remote_address"`
}

type JSONResponse struct {
	Auth     *JSONAuth              `json:"auth,omitempty"`
	Secret   *JSONSecret            `json:"secret,emitempty"`
	Data     map[string]interface{} `json:"data"`
	Redirect string                 `json:"redirect"`
}

type JSONAuth struct {
	ClientToken string            `json:"client_token,omitempty"`
	Accessor    string            `json:"accessor,omitempty"`
	DisplayName string            `json:"display_name"`
	Policies    []string          `json:"policies"`
	Metadata    map[string]string `json:"metadata"`
}

type JSONSecret struct {
	LeaseID string `json:"lease_id"`
}

// getRemoteAddr safely gets the remote address avoiding a nil pointer
func getRemoteAddr(req *logical.Request) string {
	if req != nil && req.Connection != nil {
		return req.Connection.RemoteAddr
	}
	return ""
}
<commit_msg>Audit wrap info<commit_after>package audit

import (
	"encoding/json"
	"io"
	"time"

	"github.com/hashicorp/vault/logical"
)

// FormatJSON is a Formatter implementation that structures data into
// a JSON format.
type FormatJSON struct{}

func (f *FormatJSON) FormatRequest(
	w io.Writer,
	auth *logical.Auth,
	req *logical.Request,
	err error) error {

	// If auth is nil, make an empty one
	if auth == nil {
		auth = new(logical.Auth)
	}
	var errString string
	if err != nil {
		errString = err.Error()
	}

	// Encode!
	enc := json.NewEncoder(w)
	return enc.Encode(&JSONRequestEntry{
		Time:  time.Now().UTC().Format(time.RFC3339),
		Type:  "request",
		Error: errString,

		Auth: JSONAuth{
			DisplayName: auth.DisplayName,
			Policies:    auth.Policies,
			Metadata:    auth.Metadata,
		},

		Request: JSONRequest{
			ClientToken: req.ClientToken,
			Operation:   req.Operation,
			Path:        req.Path,
			Data:        req.Data,
			RemoteAddr:  getRemoteAddr(req),
			WrapTTL:     int64(req.WrapTTL / time.Second),
		},
	})
}

func (f *FormatJSON) FormatResponse(
	w io.Writer,
	auth *logical.Auth,
	req *logical.Request,
	resp *logical.Response,
	err error) error {
	// If things are nil, make empty to avoid panics
	if auth == nil {
		auth = new(logical.Auth)
	}
	if resp == nil {
		resp = new(logical.Response)
	}
	var errString string
	if err != nil {
		errString = err.Error()
	}

	var respAuth *JSONAuth
	if resp.Auth != nil {
		respAuth = &JSONAuth{
			ClientToken: resp.Auth.ClientToken,
			Accessor:    resp.Auth.Accessor,
			DisplayName: resp.Auth.DisplayName,
			Policies:    resp.Auth.Policies,
			Metadata:    resp.Auth.Metadata,
		}
	}

	var respSecret *JSONSecret
	if resp.Secret != nil {
		respSecret = &JSONSecret{
			LeaseID: resp.Secret.LeaseID,
		}
	}

	var respWrapInfo *JSONWrapInfo
	if resp.WrapInfo != nil {
		respWrapInfo = &JSONWrapInfo{
			TTL:   int64(resp.WrapInfo.TTL / time.Second),
			Token: resp.WrapInfo.Token,
		}
	}

	// Encode!
	enc := json.NewEncoder(w)
	return enc.Encode(&JSONResponseEntry{
		Time:  time.Now().UTC().Format(time.RFC3339),
		Type:  "response",
		Error: errString,

		Auth: JSONAuth{
			DisplayName: auth.DisplayName,
			Policies:    auth.Policies,
			Metadata:    auth.Metadata,
		},

		Request: JSONRequest{
			Operation:  req.Operation,
			Path:       req.Path,
			Data:       req.Data,
			RemoteAddr: getRemoteAddr(req),
			WrapTTL:    int64(req.WrapTTL / time.Second),
		},

		Response: JSONResponse{
			Auth:     respAuth,
			Secret:   respSecret,
			Data:     resp.Data,
			Redirect: resp.Redirect,
			WrapInfo: respWrapInfo,
		},
	})
}

// JSONRequest is the structure of a request audit log entry in JSON.
type JSONRequestEntry struct {
	Time    string      `json:"time"`
	Type    string      `json:"type"`
	Auth    JSONAuth    `json:"auth"`
	Request JSONRequest `json:"request"`
	Error   string      `json:"error"`
}

// JSONResponseEntry is the structure of a response audit log entry in JSON.
type JSONResponseEntry struct {
	Time     string       `json:"time"`
	Type     string       `json:"type"`
	Error    string       `json:"error"`
	Auth     JSONAuth     `json:"auth"`
	Request  JSONRequest  `json:"request"`
	Response JSONResponse `json:"response"`
}

type JSONRequest struct {
	Operation   logical.Operation      `json:"operation"`
	ClientToken string                 `json:"client_token"`
	Path        string                 `json:"path"`
	Data        map[string]interface{} `json:"data"`
	RemoteAddr  string                 `json:"remote_address"`
	WrapTTL     int64                  `json:"wrap_ttl"`
}

type JSONResponse struct {
	Auth     *JSONAuth              `json:"auth,omitempty"`
	Secret   *JSONSecret            `json:"secret,emitempty"`
	Data     map[string]interface{} `json:"data"`
	Redirect string                 `json:"redirect"`
	WrapInfo *JSONWrapInfo          `json:"wrap_info,omitempty"`
}

type JSONAuth struct {
	ClientToken string            `json:"client_token,omitempty"`
	Accessor    string            `json:"accessor,omitempty"`
	DisplayName string            `json:"display_name"`
	Policies    []string          `json:"policies"`
	Metadata    map[string]string `json:"metadata"`
}

type JSONSecret struct {
	LeaseID string `json:"lease_id"`
}

type JSONWrapInfo struct {
	TTL   int64  `json:"ttl"`
	Token string `json:"token"`
}

// getRemoteAddr safely gets the remote address avoiding a nil pointer
func getRemoteAddr(req *logical.Request) string {
	if req != nil && req.Connection != nil {
		return req.Connection.RemoteAddr
	}
	return ""
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// 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 fleet

import (
	"bytes"
	"fmt"
	"strings"
	"time"

	"github.com/coreos/mantle/kola/cluster"
	"github.com/coreos/mantle/kola/register"
	"github.com/coreos/mantle/kola/tests/etcd"
	"github.com/coreos/mantle/util"
)

var (
	masterconf = `{
  "ignition": { "version": "2.0.0" },
  "systemd": {
    "units": [
      {
        "name": "etcd2.service",
        "enable": true,
        "dropins": [{
          "name": "metadata.conf",
          "contents": "[Unit]\nWants=coreos-metadata.service\nAfter=coreos-metadata.service\n\n[Service]\nEnvironmentFile=-/run/metadata/coreos\nExecStart=\nExecStart=/usr/bin/etcd2 --discovery=$discovery --advertise-client-urls=http://$private_ipv4:2379 --initial-advertise-peer-urls=http://$private_ipv4:2380 --listen-client-urls=http://0.0.0.0:2379,http://0.0.0.0:4001 --listen-peer-urls=http://$private_ipv4:2380,http://$private_ipv4:7001"
        }]
      },
      {
        "name": "fleet.service",
        "enable": true,
        "dropins": [{
          "name": "environment.conf",
          "contents": "[Service]\nEnvironment=FLEET_ETCD_REQUEST_TIMEOUT=15"
        }]
      },
      {
        "name": "coreos-metadata.service",
        "dropins": [{
          "name": "qemu.conf",
          "contents": "[Unit]\nConditionKernelCommandLine=coreos.oem.id"
        }]
      }
    ]
  },
  "storage": {
    "files": [{
      "filesystem": "root",
      "path": "/etc/hostname",
      "contents": { "source": "data:,master" },
      "mode": 420
    }]
  }
}`

	proxyconf = `{
  "ignition": { "version": "2.0.0" },
  "systemd": {
    "units": [
      {
        "name": "etcd2.service",
        "enable": true,
        "dropins": [{
          "name": "metadata.conf",
          "contents": "[Unit]\nWants=coreos-metadata.service\nAfter=coreos-metadata.service\n\n[Service]\nEnvironmentFile=-/run/metadata/coreos\nExecStart=\nExecStart=/usr/bin/etcd2 --discovery=$discovery --proxy=on --listen-client-urls=http://0.0.0.0:2379,http://0.0.0.0:4001"
        }]
      },
      {
        "name": "fleet.service",
        "enable": true
      },
      {
        "name": "coreos-metadata.service",
        "dropins": [{
          "name": "qemu.conf",
          "contents": "[Unit]\nConditionKernelCommandLine=coreos.oem.id"
        }]
      }
    ]
  },
  "storage": {
    "files": [
      {
        "filesystem": "root",
        "path": "/etc/hostname",
        "contents": { "source": "data:,proxy" },
        "mode": 420
      },
      {
        "filesystem": "root",
        "path": "/home/core/hello.service",
        "contents": { "source": "data:,%5BUnit%5D%0ADescription=simple%20fleet%20test%0A%5BService%5D%0AExecStart=/bin/sh%20-c%20%22while%20sleep%201%3B%20do%20echo%20hello%20world%3B%20done%22" },
        "mode": 420
      }
    ]
  }
}`
)

func init() {
	register.Register(&register.Test{
		Run:         Proxy,
		ClusterSize: 0,
		Name:        "coreos.fleet.etcdproxy",
		UserData:    `#cloud-config`,
	})
}

// Test fleet running through an etcd2 proxy.
func Proxy(c cluster.TestCluster) error {
	discoveryURL, _ := c.GetDiscoveryURL(1)

	master, err := c.NewMachine(strings.Replace(masterconf, "$discovery", discoveryURL, -1))
	if err != nil {
		return fmt.Errorf("Cluster.NewMachine master: %s", err)
	}
	defer master.Destroy()

	proxy, err := c.NewMachine(strings.Replace(proxyconf, "$discovery", discoveryURL, -1))
	if err != nil {
		return fmt.Errorf("Cluster.NewMachine proxy: %s", err)
	}
	defer proxy.Destroy()

	// Wait for all etcd cluster nodes to be ready.
	if err = etcd.GetClusterHealth(master, 1); err != nil {
		return fmt.Errorf("cluster health master: %v", err)
	}
	if err = etcd.GetClusterHealth(proxy, 1); err != nil {
		return fmt.Errorf("cluster health proxy: %v", err)
	}

	// Several seconds can pass after etcd is ready before fleet notices.
	fleetStart := func() error {
		_, err = proxy.SSH("fleetctl start /home/core/hello.service")
		if err != nil {
			return fmt.Errorf("fleetctl start: %v", err)
		}
		return nil
	}
	if err := util.Retry(5, 5*time.Second, fleetStart); err != nil {
		return fmt.Errorf("fleetctl start failed: %v", err)
	}

	status, err := proxy.SSH("fleetctl list-units -l -fields active -no-legend")
	if err != nil {
		return fmt.Errorf("fleetctl list-units failed: %v", err)
	}

	if !bytes.Equal(status, []byte("active")) {
		return fmt.Errorf("unit not active")
	}

	return nil
}
<commit_msg>kola/tests/fleet: show the unit status in the error<commit_after>// Copyright 2015 CoreOS, Inc.
//
// 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 fleet

import (
	"bytes"
	"fmt"
	"strings"
	"time"

	"github.com/coreos/mantle/kola/cluster"
	"github.com/coreos/mantle/kola/register"
	"github.com/coreos/mantle/kola/tests/etcd"
	"github.com/coreos/mantle/util"
)

var (
	masterconf = `{
  "ignition": { "version": "2.0.0" },
  "systemd": {
    "units": [
      {
        "name": "etcd2.service",
        "enable": true,
        "dropins": [{
          "name": "metadata.conf",
          "contents": "[Unit]\nWants=coreos-metadata.service\nAfter=coreos-metadata.service\n\n[Service]\nEnvironmentFile=-/run/metadata/coreos\nExecStart=\nExecStart=/usr/bin/etcd2 --discovery=$discovery --advertise-client-urls=http://$private_ipv4:2379 --initial-advertise-peer-urls=http://$private_ipv4:2380 --listen-client-urls=http://0.0.0.0:2379,http://0.0.0.0:4001 --listen-peer-urls=http://$private_ipv4:2380,http://$private_ipv4:7001"
        }]
      },
      {
        "name": "fleet.service",
        "enable": true,
        "dropins": [{
          "name": "environment.conf",
          "contents": "[Service]\nEnvironment=FLEET_ETCD_REQUEST_TIMEOUT=15"
        }]
      },
      {
        "name": "coreos-metadata.service",
        "dropins": [{
          "name": "qemu.conf",
          "contents": "[Unit]\nConditionKernelCommandLine=coreos.oem.id"
        }]
      }
    ]
  },
  "storage": {
    "files": [{
      "filesystem": "root",
      "path": "/etc/hostname",
      "contents": { "source": "data:,master" },
      "mode": 420
    }]
  }
}`

	proxyconf = `{
  "ignition": { "version": "2.0.0" },
  "systemd": {
    "units": [
      {
        "name": "etcd2.service",
        "enable": true,
        "dropins": [{
          "name": "metadata.conf",
          "contents": "[Unit]\nWants=coreos-metadata.service\nAfter=coreos-metadata.service\n\n[Service]\nEnvironmentFile=-/run/metadata/coreos\nExecStart=\nExecStart=/usr/bin/etcd2 --discovery=$discovery --proxy=on --listen-client-urls=http://0.0.0.0:2379,http://0.0.0.0:4001"
        }]
      },
      {
        "name": "fleet.service",
        "enable": true
      },
      {
        "name": "coreos-metadata.service",
        "dropins": [{
          "name": "qemu.conf",
          "contents": "[Unit]\nConditionKernelCommandLine=coreos.oem.id"
        }]
      }
    ]
  },
  "storage": {
    "files": [
      {
        "filesystem": "root",
        "path": "/etc/hostname",
        "contents": { "source": "data:,proxy" },
        "mode": 420
      },
      {
        "filesystem": "root",
        "path": "/home/core/hello.service",
        "contents": { "source": "data:,%5BUnit%5D%0ADescription=simple%20fleet%20test%0A%5BService%5D%0AExecStart=/bin/sh%20-c%20%22while%20sleep%201%3B%20do%20echo%20hello%20world%3B%20done%22" },
        "mode": 420
      }
    ]
  }
}`
)

func init() {
	register.Register(&register.Test{
		Run:         Proxy,
		ClusterSize: 0,
		Name:        "coreos.fleet.etcdproxy",
		UserData:    `#cloud-config`,
	})
}

// Test fleet running through an etcd2 proxy.
func Proxy(c cluster.TestCluster) error {
	discoveryURL, _ := c.GetDiscoveryURL(1)

	master, err := c.NewMachine(strings.Replace(masterconf, "$discovery", discoveryURL, -1))
	if err != nil {
		return fmt.Errorf("Cluster.NewMachine master: %s", err)
	}
	defer master.Destroy()

	proxy, err := c.NewMachine(strings.Replace(proxyconf, "$discovery", discoveryURL, -1))
	if err != nil {
		return fmt.Errorf("Cluster.NewMachine proxy: %s", err)
	}
	defer proxy.Destroy()

	// Wait for all etcd cluster nodes to be ready.
	if err = etcd.GetClusterHealth(master, 1); err != nil {
		return fmt.Errorf("cluster health master: %v", err)
	}
	if err = etcd.GetClusterHealth(proxy, 1); err != nil {
		return fmt.Errorf("cluster health proxy: %v", err)
	}

	// Several seconds can pass after etcd is ready before fleet notices.
	fleetStart := func() error {
		_, err = proxy.SSH("fleetctl start /home/core/hello.service")
		if err != nil {
			return fmt.Errorf("fleetctl start: %v", err)
		}
		return nil
	}
	if err := util.Retry(5, 5*time.Second, fleetStart); err != nil {
		return fmt.Errorf("fleetctl start failed: %v", err)
	}

	status, err := proxy.SSH("fleetctl list-units -l -fields active -no-legend")
	if err != nil {
		return fmt.Errorf("fleetctl list-units failed: %v", err)
	}

	if !bytes.Equal(status, []byte("active")) {
		return fmt.Errorf("unit not active: %v", status)
	}

	return nil
}
<|endoftext|>


<commit_before>// Package protobuf contains a codec to encode and decode entities in Protocol Buffer
package protobuf

import (
	"errors"

	"github.com/golang/protobuf/proto"
	"github.com/asdine/storm/codec/gob"
)

// More details on Protocol Buffers https://github.com/golang/protobuf
var (
	Codec                       = new(protobufCodec)
	errNotProtocolBufferMessage = errors.New("value isn't a Protocol Buffers Message")
)

type protobufCodec int

// Encode value with protocol buffer.
// If type isn't a Protocol buffer Message, gob encoder will be used instead.
func (c protobufCodec) Encode(v interface{}) ([]byte, error) {
	message, ok := v.(proto.Message)
	if !ok {
		// toBytes() may need to encode non-protobuf type, if that occurs use gob
		return gob.Codec.Encode(v)
	}
	return proto.Marshal(message)
}

func (c protobufCodec) Decode(b []byte, v interface{}) error {
	message, ok := v.(proto.Message)
	if !ok {
		return errNotProtocolBufferMessage
	}
	return proto.Unmarshal(b, message)
}
<commit_msg>Using json instead of gob in protobuf codec<commit_after>// Package protobuf contains a codec to encode and decode entities in Protocol Buffer
package protobuf

import (
	"errors"

	"github.com/asdine/storm/codec/json"
	"github.com/golang/protobuf/proto"
)

// More details on Protocol Buffers https://github.com/golang/protobuf
var (
	Codec                       = new(protobufCodec)
	errNotProtocolBufferMessage = errors.New("value isn't a Protocol Buffers Message")
)

type protobufCodec int

// Encode value with protocol buffer.
// If type isn't a Protocol buffer Message, gob encoder will be used instead.
func (c protobufCodec) Encode(v interface{}) ([]byte, error) {
	message, ok := v.(proto.Message)
	if !ok {
		// toBytes() may need to encode non-protobuf type, if that occurs use json
		return json.Codec.Encode(v)
	}
	return proto.Marshal(message)
}

func (c protobufCodec) Decode(b []byte, v interface{}) error {
	message, ok := v.(proto.Message)
	if !ok {
		return errNotProtocolBufferMessage
	}
	return proto.Unmarshal(b, message)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/CleverbotIO/go-cleverbot.io"
	"github.com/PonyvilleFM/aura/pvfm/station"
	"github.com/bwmarrin/discordgo"
	"github.com/jzelinskie/geddit"
	"github.com/techniponi/doritobot/gitupdate"
)

// randomRange gives a random whole integer between the given integers [min, max)
func randomRange(min, max int) int {
	rand.Seed(time.Now().Unix())
	return rand.Intn(max-min) + min
}

// Config is a json file containing the login data and any user-configurable values
type Config struct {
	Username            string `json:"username"`
	Password            string `json:"password"`
	Bot                 bool   `json:"Bot"`
	BotToken            string `json:"botToken"`
	HTTPEndpointEnabled bool   `json:"httpEndpointEnabled"`
	EchoCommandEnabled  bool   `json:"echoCommandEnabled"`
}

// DerpiResults is a struct to contain Derpibooru search results
type DerpiResults struct {
	Search []struct {
		ID               string        `json:"id"`
		CreatedAt        time.Time     `json:"created_at"`
		UpdatedAt        time.Time     `json:"updated_at"`
		DuplicateReports []interface{} `json:"duplicate_reports"`
		FirstSeenAt      time.Time     `json:"first_seen_at"`
		UploaderID       string        `json:"uploader_id"`
		Score            int           `json:"score"`
		CommentCount     int           `json:"comment_count"`
		Width            int           `json:"width"`
		Height           int           `json:"height"`
		FileName         string        `json:"file_name"`
		Description      string        `json:"description"`
		Uploader         string        `json:"uploader"`
		Image            string        `json:"image"`
		Upvotes          int           `json:"upvotes"`
		Downvotes        int           `json:"downvotes"`
		Faves            int           `json:"faves"`
		Tags             string        `json:"tags"`
		TagIds           []string      `json:"tag_ids"`
		AspectRatio      float64       `json:"aspect_ratio"`
		OriginalFormat   string        `json:"original_format"`
		MimeType         string        `json:"mime_type"`
		Sha512Hash       string        `json:"sha512_hash"`
		OrigSha512Hash   string        `json:"orig_sha512_hash"`
		SourceURL        string        `json:"source_url"`
		Representations  struct {
			ThumbTiny  string `json:"thumb_tiny"`
			ThumbSmall string `json:"thumb_small"`
			Thumb      string `json:"thumb"`
			Small      string `json:"small"`
			Medium     string `json:"medium"`
			Large      string `json:"large"`
			Tall       string `json:"tall"`
			Full       string `json:"full"`
		} `json:"representations"`
		IsRendered  bool `json:"is_rendered"`
		IsOptimized bool `json:"is_optimized"`
	} `json:"search"`
	Total        int           `json:"total"`
	Interactions []interface{} `json:"interactions"`
}

// These need to be global
var cb *cleverbot.Session
var botErr error
var currentID string
var userIDError error
var dg *discordgo.Session
var err error
var login Config

func main() {
	// Read the config.json
	loginFile, fileErr := ioutil.ReadFile("./config.json")
	if fileErr != nil {
		fmt.Println(fileErr.Error())
		os.Exit(1)
	}

	// Parse it
	jsonErr := json.Unmarshal(loginFile, &login)

	if jsonErr != nil {
		fmt.Println(jsonErr.Error())
		os.Exit(1)
	}

	// Log in to discord
	if login.Bot {
		dg, err = discordgo.New("Bot " + login.BotToken)
	} else {
		dg, err = discordgo.New(login.Username, login.Password)
	}

	if err != nil {
		fmt.Println("Error creating session: ", err)
		os.Exit(1)
	} else {
		fmt.Println("Successfully logged in.")
	}

	// Message received handler
	dg.AddHandler(messageCreate)

	err = dg.Open()
	if err != nil {
		fmt.Println("Error opening connection: ", err)
		os.Exit(1)
	}

	// Open cleverbot API
	// TODO: move this to login.json
	cb, botErr = cleverbot.New("JHowZe3ddT6Da0JU", "8NSK1vZVH1lRNMIcTbu4hU6kGEyIDxsW", "")
	if botErr != nil {
		log.Fatal(botErr)
	}

	// HTTP endpoint handler
	http.HandleFunc("/chat", func(w http.ResponseWriter, r *http.Request) {
		if login.HTTPEndpointEnabled {
			id := r.URL.Query().Get("id")
			msg := r.URL.Query().Get("msg")
			if id != "" && msg != "" {
				dg.ChannelMessageSend(id, "Message from HTTP chat endpoint: \n`"+msg+"`")
				fmt.Fprintf(w, "You are sending: \n"+msg+"\nto channel ID: \n"+id)
			}
		}
	})

	http.HandleFunc("/repoupdate", func(w http.ResponseWriter, r *http.Request) {
		decoder := json.NewDecoder(r.Body)
		var update gitupdate.GitUpdate
		err := decoder.Decode(&update)
		if err != nil {
			log.Fatal(err)
		}
		defer r.Body.Close()
		updateString := "New commit pushed to <https://github.com/techniponi/doritobot> (" + update.HeadCommit.ID + "):\n" + update.HeadCommit.Author.Name + ": " + update.HeadCommit.Message + "\n" + update.HeadCommit.URL

		dg.ChannelMessageSend("298642620849324035", updateString)
	})

	dgUser, userIDError := dg.User("@me")
	currentID = dgUser.ID

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

	fmt.Println("Bot is now running.  Press CTRL-C to exit.")
	log.Fatal(http.ListenAndServe(":8080", nil))
	<-make(chan struct{})
	return
}

// messageCreate is the handler function for all incoming Discord messages
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	var msg []string
	if m.Author.Username == "PonyChat" {
		// this is disabled since my implementation was SHIT
		//msg = strings.Split(m.Content[strings.Index(m.Content, ">")+4:len(m.Content)], " ")
	} else {
		msg = strings.Split(m.Content, " ")
	}

	if len(msg) > 0 {
		switch msg[0] {
		case "nazoupdate": // Reminds everyone that Nazo is adorable
			s.ChannelMessageDelete(m.ChannelID, m.ID)
			s.ChannelMessageSend(m.ChannelID, "This is your daily reminder that <@!165846085020024832> is adorable.")
			break
		case "echo": // Echoes the given text
			if login.EchoCommandEnabled {
				s.ChannelMessageDelete(m.ChannelID, m.ID)
				/*if m.Author.Username == "PonyChat" {
					s.ChannelMessageSend(m.ChannelID, "`ds:` "+m.Content[15:len(m.Content)])
				} else {*/
				s.ChannelMessageSend(m.ChannelID, "`echo:`\n"+m.Content[11:len(m.Content)])
				//}
			}
			break
		case "cb": // Communicates with Cleverbot.
			response, botErr2 := cb.Ask(m.Content[2:len(m.Content)])
			if botErr2 != nil {
				log.Fatal(botErr2)
			}
			s.ChannelMessageSend(m.ChannelID, response)
			break
		case "db": // Grabs an image from Derpibooru results with a given list of tags - always a safe image!
			if len(msg) < 2 {
				s.ChannelMessageSend(m.ChannelID, "Error: not enough arguments")
				break
			}
			derpiTags := strings.Replace(m.Content[3:len(m.Content)], " ", "+", -1)
			resp, derpiHTTPErr := http.Get("https://derpibooru.org/search.json?q=safe," + derpiTags)
			if derpiHTTPErr != nil {
				s.ChannelMessageSend(m.ChannelID, "HTTP error, check console")
				log.Fatal(derpiHTTPErr)
				break
			}
			defer resp.Body.Close()
			derpiBody, derpiErr := ioutil.ReadAll(resp.Body)
			var derpiErr2 error
			results := DerpiResults{}
			derpiErr2 = json.Unmarshal(derpiBody, &results)
			if derpiErr != nil {
				s.ChannelMessageSend(m.ChannelID, "Error reading HTTP response")
				break
			}
			if derpiErr2 != nil {
				s.ChannelMessageSend(m.ChannelID, "Error reading derpibooru API response")
				break
			}
			if len(results.Search) > 0 {
				s.ChannelMessageSend(m.ChannelID, "http:"+results.Search[randomRange(0, len(results.Search))].Image)
			} else {
				s.ChannelMessageSend(m.ChannelID, "Error: no results")
			}
			break
		case "h": // h
			if m.Author.ID != currentID {
				s.ChannelMessageSend(m.ChannelID, "h")
			}
			break
		case "pvfmservers": // Gives a list of all available PVFM streams (direct links)
			currentMeta, metaErr := station.GetStats()
			if metaErr != nil {
				s.ChannelMessageSend(m.ChannelID, "Error receiving pvfm metadata")
				break
			}

			outputString := "**PVFM Servers:**\n"

			for _, element := range currentMeta.Icestats.Source {
				outputString += ":musical_note: " + element.ServerDescription + ":\n`" + strings.Replace(element.Listenurl, "aerial", "dj.bronyradio.com", -1) + "`\n"
			}

			outputString += "\n:cd: DJ Recordings:\n`http://darkling.darkwizards.com/wang/BronyRadio/?M=D`"

			s.ChannelMessageSend(m.ChannelID, outputString)

			break
		case "techgore":
			listOptions := geddit.ListingOptions{
				Limit: 50,
			}
			reddit := geddit.NewSession("discordbot")
			results, err := reddit.SubredditSubmissions("techsupportgore", geddit.NewSubmissions, listOptions)
			if err != nil {
				break
			}
			s.ChannelMessageSend(m.ChannelID, results[randomRange(0, len(results))].URL)
			break
		case "snuggle", "cuddle", "hug", "kiss", "boop", "glomp", "nuzzle":
			if len(msg) < 2 {
				s.ChannelMessageSend(m.ChannelID, "Who - Delta, Twisty, or Jac?")
				break
			}
			names := map[string]string{
				"awal":    "Twisty",
				"twisty":  "Twisty",
				"delta":   "Delta",
				"dorito":  "Delta",
				"techni":  "Delta",
				"nazo":    "Jac",
				"nuzzles": "Jac",
				"jac":     "Jac",
			}
			possibleResponses := []string{
				"\"ees\" softly.",
				"snuggles back.",
				"flops over.",
				"blushes profusely.",
				"twitches his ears and smiles.",
				"smiles lovingly.",
				"boops you back!",
				"glomps you!",
				"is happy.",
				"jumps with joy!",
				"wasn't expecting that! :heart:",
				"loves you.",
			}
			if names[msg[1]] == "" {
				s.ChannelMessageSend(m.ChannelID, "I'm afraid I don't know who that is. :c")
				break
			}
			s.ChannelMessageSend(m.ChannelID, names[msg[1]]+" "+possibleResponses[randomRange(0, len(possibleResponses))])

			break
		case "gay":
			possibleResponses := []string{
				"floof.zone/img/gay.jpg",
				"floof.zone/img/nazoblep.png",
				"floof.zone/img/awalblep.png",
				"floof.zone/img/floofbat-capall.png",
			}
			s.ChannelMessageSend(m.ChannelID, "http://"+possibleResponses[randomRange(0, len(possibleResponses))])
			break
		}
	}
}
<commit_msg>Update roleplay commands again<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/CleverbotIO/go-cleverbot.io"
	"github.com/PonyvilleFM/aura/pvfm/station"
	"github.com/bwmarrin/discordgo"
	"github.com/jzelinskie/geddit"
	"github.com/techniponi/doritobot/gitupdate"
)

// randomRange gives a random whole integer between the given integers [min, max)
func randomRange(min, max int) int {
	rand.Seed(time.Now().Unix())
	return rand.Intn(max-min) + min
}

// Config is a json file containing the login data and any user-configurable values
type Config struct {
	Username            string `json:"username"`
	Password            string `json:"password"`
	Bot                 bool   `json:"Bot"`
	BotToken            string `json:"botToken"`
	HTTPEndpointEnabled bool   `json:"httpEndpointEnabled"`
	EchoCommandEnabled  bool   `json:"echoCommandEnabled"`
}

// DerpiResults is a struct to contain Derpibooru search results
type DerpiResults struct {
	Search []struct {
		ID               string        `json:"id"`
		CreatedAt        time.Time     `json:"created_at"`
		UpdatedAt        time.Time     `json:"updated_at"`
		DuplicateReports []interface{} `json:"duplicate_reports"`
		FirstSeenAt      time.Time     `json:"first_seen_at"`
		UploaderID       string        `json:"uploader_id"`
		Score            int           `json:"score"`
		CommentCount     int           `json:"comment_count"`
		Width            int           `json:"width"`
		Height           int           `json:"height"`
		FileName         string        `json:"file_name"`
		Description      string        `json:"description"`
		Uploader         string        `json:"uploader"`
		Image            string        `json:"image"`
		Upvotes          int           `json:"upvotes"`
		Downvotes        int           `json:"downvotes"`
		Faves            int           `json:"faves"`
		Tags             string        `json:"tags"`
		TagIds           []string      `json:"tag_ids"`
		AspectRatio      float64       `json:"aspect_ratio"`
		OriginalFormat   string        `json:"original_format"`
		MimeType         string        `json:"mime_type"`
		Sha512Hash       string        `json:"sha512_hash"`
		OrigSha512Hash   string        `json:"orig_sha512_hash"`
		SourceURL        string        `json:"source_url"`
		Representations  struct {
			ThumbTiny  string `json:"thumb_tiny"`
			ThumbSmall string `json:"thumb_small"`
			Thumb      string `json:"thumb"`
			Small      string `json:"small"`
			Medium     string `json:"medium"`
			Large      string `json:"large"`
			Tall       string `json:"tall"`
			Full       string `json:"full"`
		} `json:"representations"`
		IsRendered  bool `json:"is_rendered"`
		IsOptimized bool `json:"is_optimized"`
	} `json:"search"`
	Total        int           `json:"total"`
	Interactions []interface{} `json:"interactions"`
}

// These need to be global
var cb *cleverbot.Session
var botErr error
var currentID string
var userIDError error
var dg *discordgo.Session
var err error
var login Config

func main() {
	// Read the config.json
	loginFile, fileErr := ioutil.ReadFile("./config.json")
	if fileErr != nil {
		fmt.Println(fileErr.Error())
		os.Exit(1)
	}

	// Parse it
	jsonErr := json.Unmarshal(loginFile, &login)

	if jsonErr != nil {
		fmt.Println(jsonErr.Error())
		os.Exit(1)
	}

	// Log in to discord
	if login.Bot {
		dg, err = discordgo.New("Bot " + login.BotToken)
	} else {
		dg, err = discordgo.New(login.Username, login.Password)
	}

	if err != nil {
		fmt.Println("Error creating session: ", err)
		os.Exit(1)
	} else {
		fmt.Println("Successfully logged in.")
	}

	// Message received handler
	dg.AddHandler(messageCreate)

	err = dg.Open()
	if err != nil {
		fmt.Println("Error opening connection: ", err)
		os.Exit(1)
	}

	// Open cleverbot API
	// TODO: move this to login.json
	cb, botErr = cleverbot.New("JHowZe3ddT6Da0JU", "8NSK1vZVH1lRNMIcTbu4hU6kGEyIDxsW", "")
	if botErr != nil {
		log.Fatal(botErr)
	}

	// HTTP endpoint handler
	http.HandleFunc("/chat", func(w http.ResponseWriter, r *http.Request) {
		if login.HTTPEndpointEnabled {
			id := r.URL.Query().Get("id")
			msg := r.URL.Query().Get("msg")
			if id != "" && msg != "" {
				dg.ChannelMessageSend(id, "Message from HTTP chat endpoint: \n`"+msg+"`")
				fmt.Fprintf(w, "You are sending: \n"+msg+"\nto channel ID: \n"+id)
			}
		}
	})

	http.HandleFunc("/repoupdate", func(w http.ResponseWriter, r *http.Request) {
		decoder := json.NewDecoder(r.Body)
		var update gitupdate.GitUpdate
		err := decoder.Decode(&update)
		if err != nil {
			log.Fatal(err)
		}
		defer r.Body.Close()
		updateString := "New commit pushed to <https://github.com/techniponi/doritobot> (" + update.HeadCommit.ID + "):\n" + update.HeadCommit.Author.Name + ": " + update.HeadCommit.Message + "\n" + update.HeadCommit.URL

		dg.ChannelMessageSend("298642620849324035", updateString)
	})

	dgUser, userIDError := dg.User("@me")
	currentID = dgUser.ID

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

	fmt.Println("Bot is now running.  Press CTRL-C to exit.")
	log.Fatal(http.ListenAndServe(":8080", nil))
	<-make(chan struct{})
	return
}

// messageCreate is the handler function for all incoming Discord messages
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	var msg []string
	if m.Author.Username == "PonyChat" {
		// this is disabled since my implementation was SHIT
		//msg = strings.Split(m.Content[strings.Index(m.Content, ">")+4:len(m.Content)], " ")
	} else {
		msg = strings.Split(m.Content, " ")
	}

	if len(msg) > 0 {
		switch msg[0] {
		case "nazoupdate": // Reminds everyone that Nazo is adorable
			s.ChannelMessageDelete(m.ChannelID, m.ID)
			s.ChannelMessageSend(m.ChannelID, "This is your daily reminder that <@!165846085020024832> is adorable.")
			break
		case "echo": // Echoes the given text
			if login.EchoCommandEnabled {
				s.ChannelMessageDelete(m.ChannelID, m.ID)
				/*if m.Author.Username == "PonyChat" {
					s.ChannelMessageSend(m.ChannelID, "`ds:` "+m.Content[15:len(m.Content)])
				} else {*/
				s.ChannelMessageSend(m.ChannelID, "`echo:`\n"+m.Content[11:len(m.Content)])
				//}
			}
			break
		case "cb": // Communicates with Cleverbot.
			response, botErr2 := cb.Ask(m.Content[2:len(m.Content)])
			if botErr2 != nil {
				log.Fatal(botErr2)
			}
			s.ChannelMessageSend(m.ChannelID, response)
			break
		case "db": // Grabs an image from Derpibooru results with a given list of tags - always a safe image!
			if len(msg) < 2 {
				s.ChannelMessageSend(m.ChannelID, "Error: not enough arguments")
				break
			}
			derpiTags := strings.Replace(m.Content[3:len(m.Content)], " ", "+", -1)
			resp, derpiHTTPErr := http.Get("https://derpibooru.org/search.json?q=safe," + derpiTags)
			if derpiHTTPErr != nil {
				s.ChannelMessageSend(m.ChannelID, "HTTP error, check console")
				log.Fatal(derpiHTTPErr)
				break
			}
			defer resp.Body.Close()
			derpiBody, derpiErr := ioutil.ReadAll(resp.Body)
			var derpiErr2 error
			results := DerpiResults{}
			derpiErr2 = json.Unmarshal(derpiBody, &results)
			if derpiErr != nil {
				s.ChannelMessageSend(m.ChannelID, "Error reading HTTP response")
				break
			}
			if derpiErr2 != nil {
				s.ChannelMessageSend(m.ChannelID, "Error reading derpibooru API response")
				break
			}
			if len(results.Search) > 0 {
				s.ChannelMessageSend(m.ChannelID, "http:"+results.Search[randomRange(0, len(results.Search))].Image)
			} else {
				s.ChannelMessageSend(m.ChannelID, "Error: no results")
			}
			break
		case "h": // h
			if m.Author.ID != currentID {
				s.ChannelMessageSend(m.ChannelID, "h")
			}
			break
		case "pvfmservers": // Gives a list of all available PVFM streams (direct links)
			currentMeta, metaErr := station.GetStats()
			if metaErr != nil {
				s.ChannelMessageSend(m.ChannelID, "Error receiving pvfm metadata")
				break
			}

			outputString := "**PVFM Servers:**\n"

			for _, element := range currentMeta.Icestats.Source {
				outputString += ":musical_note: " + element.ServerDescription + ":\n`" + strings.Replace(element.Listenurl, "aerial", "dj.bronyradio.com", -1) + "`\n"
			}

			outputString += "\n:cd: DJ Recordings:\n`http://darkling.darkwizards.com/wang/BronyRadio/?M=D`"

			s.ChannelMessageSend(m.ChannelID, outputString)

			break
		case "techgore":
			listOptions := geddit.ListingOptions{
				Limit: 50,
			}
			reddit := geddit.NewSession("discordbot")
			results, err := reddit.SubredditSubmissions("techsupportgore", geddit.NewSubmissions, listOptions)
			if err != nil {
				break
			}
			s.ChannelMessageSend(m.ChannelID, results[randomRange(0, len(results))].URL)
			break
		case "snuggle", "cuddle", "hug", "kiss", "boop", "glomp", "nuzzle":
			if len(msg) < 2 {
				s.ChannelMessageSend(m.ChannelID, "Who - Delta, Twisty, or Jac?")
				break
			}
			names := map[string]string{
				"awal":    "Twisty",
				"twisty":  "Twisty",
				"delta":   "Delta",
				"dorito":  "Delta",
				"techni":  "Delta",
				"nazo":    "Jac",
				"nuzzles": "Jac",
				"jac":     "Jac",
				"thorax":  "Thorax",
				"shining": "Shiny",
				"shiny":   "Shiny",
			}
			possibleResponses := []string{
				"\"ees\" softly.",
				"snuggles back.",
				"flops over.",
				"blushes profusely.",
				"twitches his ears and smiles.",
				"smiles lovingly.",
				"boops you back!",
				"glomps you!",
				"is happy.",
				"jumps with joy!",
				"wasn't expecting that! :heart:",
				"loves you.",
			}
			if names[msg[1]] == "" {
				s.ChannelMessageSend(m.ChannelID, "I'm afraid I don't know who that is. :c")
				break
			}
			s.ChannelMessageSend(m.ChannelID, names[msg[1]]+" "+possibleResponses[randomRange(0, len(possibleResponses))])

			break
		case "gay":
			possibleResponses := []string{
				"floof.zone/img/gay.jpg",
				"floof.zone/img/nazoblep.png",
				"floof.zone/img/awalblep.png",
				"floof.zone/img/floofbat-capall.png",
			}
			s.ChannelMessageSend(m.ChannelID, "http://"+possibleResponses[randomRange(0, len(possibleResponses))])
			break
		}
	}
}
<|endoftext|>