<commit_before>package aws

import (
	"fmt"
	"os"
	"regexp"
	"testing"

	"github.com/aws/aws-sdk-go/service/acm"
	"github.com/hashicorp/terraform/helper/resource"
)

const ACMCertificateRe = `^arn:[^:]+:acm:[^:]+:[^:]+:certificate/.+$`

func TestAccAWSAcmCertificateDataSource_singleIssued(t *testing.T) {
	if os.Getenv("ACM_CERTIFICATE_ROOT_DOMAIN") == "" {
		t.Skip("Environment variable ACM_CERTIFICATE_ROOT_DOMAIN is not set")
	}

	var arnRe *regexp.Regexp
	var domain string

	if os.Getenv("ACM_CERTIFICATE_SINGLE_ISSUED_MOST_RECENT_ARN") != "" {
		arnRe = regexp.MustCompile(fmt.Sprintf("^%s$", os.Getenv("ACM_CERTIFICATE_SINGLE_ISSUED_MOST_RECENT_ARN")))
	} else {
		arnRe = regexp.MustCompile(ACMCertificateRe)
	}

	if os.Getenv("ACM_CERTIFICATE_SINGLE_ISSUED_DOMAIN") != "" {
		domain = os.Getenv("ACM_CERTIFICATE_SINGLE_ISSUED_DOMAIN")
	} else {
		domain = fmt.Sprintf("tf-acc-single-issued.%s", os.Getenv("ACM_CERTIFICATE_ROOT_DOMAIN"))
	}

	resourceName := "data.aws_acm_certificate.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfig(domain),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithStatus(domain, acm.CertificateStatusIssued),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithTypes(domain, acm.CertificateTypeAmazonIssued),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecent(domain, true),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndStatus(domain, acm.CertificateStatusIssued, true),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndTypes(domain, acm.CertificateTypeAmazonIssued, true),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
		},
	})
}

func TestAccAWSAcmCertificateDataSource_multipleIssued(t *testing.T) {
	if os.Getenv("ACM_CERTIFICATE_ROOT_DOMAIN") == "" {
		t.Skip("Environment variable ACM_CERTIFICATE_ROOT_DOMAIN is not set")
	}

	var arnRe *regexp.Regexp
	var domain string

	if os.Getenv("ACM_CERTIFICATE_MULTIPLE_ISSUED_MOST_RECENT_ARN") != "" {
		arnRe = regexp.MustCompile(fmt.Sprintf("^%s$", os.Getenv("ACM_CERTIFICATE_MULTIPLE_ISSUED_MOST_RECENT_ARN")))
	} else {
		arnRe = regexp.MustCompile(ACMCertificateRe)
	}

	if os.Getenv("ACM_CERTIFICATE_MULTIPLE_ISSUED_DOMAIN") != "" {
		domain = os.Getenv("ACM_CERTIFICATE_MULTIPLE_ISSUED_DOMAIN")
	} else {
		domain = fmt.Sprintf("tf-acc-multiple-issued.%s", os.Getenv("ACM_CERTIFICATE_ROOT_DOMAIN"))
	}

	resourceName := "data.aws_acm_certificate.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfig(domain),
				ExpectError: regexp.MustCompile(`Multiple certificates for domain`),
			},
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfigWithStatus(domain, acm.CertificateStatusIssued),
				ExpectError: regexp.MustCompile(`Multiple certificates for domain`),
			},
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfigWithTypes(domain, acm.CertificateTypeAmazonIssued),
				ExpectError: regexp.MustCompile(`Multiple certificates for domain`),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecent(domain, true),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndStatus(domain, acm.CertificateStatusIssued, true),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndTypes(domain, acm.CertificateTypeAmazonIssued, true),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
		},
	})
}

func TestAccAWSAcmCertificateDataSource_noMatchReturnsError(t *testing.T) {
	if os.Getenv("ACM_CERTIFICATE_ROOT_DOMAIN") == "" {
		t.Skip("Environment variable ACM_CERTIFICATE_ROOT_DOMAIN is not set")
	}

	domain := fmt.Sprintf("tf-acc-nonexistent.%s", os.Getenv("ACM_CERTIFICATE_ROOT_DOMAIN"))

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfig(domain),
				ExpectError: regexp.MustCompile(`No certificate for domain`),
			},
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfigWithStatus(domain, acm.CertificateStatusIssued),
				ExpectError: regexp.MustCompile(`No certificate for domain`),
			},
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfigWithTypes(domain, acm.CertificateTypeAmazonIssued),
				ExpectError: regexp.MustCompile(`No certificate for domain`),
			},
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecent(domain, true),
				ExpectError: regexp.MustCompile(`No certificate for domain`),
			},
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndStatus(domain, acm.CertificateStatusIssued, true),
				ExpectError: regexp.MustCompile(`No certificate for domain`),
			},
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndTypes(domain, acm.CertificateTypeAmazonIssued, true),
				ExpectError: regexp.MustCompile(`No certificate for domain`),
			},
		},
	})
}

func testAccCheckAwsAcmCertificateDataSourceConfig(domain string) string {
	return fmt.Sprintf(`
data "aws_acm_certificate" "test" {
	domain = "%s"
}
`, domain)
}

func testAccCheckAwsAcmCertificateDataSourceConfigWithStatus(domain, status string) string {
	return fmt.Sprintf(`
data "aws_acm_certificate" "test" {
	domain = "%s"
	statuses = ["%s"]
}
`, domain, status)
}

func testAccCheckAwsAcmCertificateDataSourceConfigWithTypes(domain, certType string) string {
	return fmt.Sprintf(`
data "aws_acm_certificate" "test" {
	domain = "%s"
	types = ["%s"]
}
`, domain, certType)
}

func testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecent(domain string, mostRecent bool) string {
	return fmt.Sprintf(`
data "aws_acm_certificate" "test" {
	domain = "%s"
	most_recent = %v
}
`, domain, mostRecent)
}

func testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndStatus(domain, status string, mostRecent bool) string {
	return fmt.Sprintf(`
data "aws_acm_certificate" "test" {
	domain = "%s"
	statuses = ["%s"]
	most_recent = %v
}
`, domain, status, mostRecent)
}

func testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndTypes(domain, certType string, mostRecent bool) string {
	return fmt.Sprintf(`
data "aws_acm_certificate" "test" {
	domain = "%s"
	types = ["%s"]
	most_recent = %v
}
`, domain, certType, mostRecent)
}
<commit_msg>Add suggested acceptance test<commit_after>package aws

import (
	"fmt"
	"os"
	"regexp"
	"testing"

	"github.com/aws/aws-sdk-go/service/acm"
	"github.com/hashicorp/terraform/helper/resource"
)

const ACMCertificateRe = `^arn:[^:]+:acm:[^:]+:[^:]+:certificate/.+$`

func TestAccAWSAcmCertificateDataSource_singleIssued(t *testing.T) {
	if os.Getenv("ACM_CERTIFICATE_ROOT_DOMAIN") == "" {
		t.Skip("Environment variable ACM_CERTIFICATE_ROOT_DOMAIN is not set")
	}

	var arnRe *regexp.Regexp
	var domain string

	if os.Getenv("ACM_CERTIFICATE_SINGLE_ISSUED_MOST_RECENT_ARN") != "" {
		arnRe = regexp.MustCompile(fmt.Sprintf("^%s$", os.Getenv("ACM_CERTIFICATE_SINGLE_ISSUED_MOST_RECENT_ARN")))
	} else {
		arnRe = regexp.MustCompile(ACMCertificateRe)
	}

	if os.Getenv("ACM_CERTIFICATE_SINGLE_ISSUED_DOMAIN") != "" {
		domain = os.Getenv("ACM_CERTIFICATE_SINGLE_ISSUED_DOMAIN")
	} else {
		domain = fmt.Sprintf("tf-acc-single-issued.%s", os.Getenv("ACM_CERTIFICATE_ROOT_DOMAIN"))
	}

	resourceName := "data.aws_acm_certificate.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfig(domain),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithStatus(domain, acm.CertificateStatusIssued),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithTypes(domain, acm.CertificateTypeAmazonIssued),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecent(domain, true),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndStatus(domain, acm.CertificateStatusIssued, true),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndTypes(domain, acm.CertificateTypeAmazonIssued, true),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
		},
	})
}

func TestAccAWSAcmCertificateDataSource_multipleIssued(t *testing.T) {
	if os.Getenv("ACM_CERTIFICATE_ROOT_DOMAIN") == "" {
		t.Skip("Environment variable ACM_CERTIFICATE_ROOT_DOMAIN is not set")
	}

	var arnRe *regexp.Regexp
	var domain string

	if os.Getenv("ACM_CERTIFICATE_MULTIPLE_ISSUED_MOST_RECENT_ARN") != "" {
		arnRe = regexp.MustCompile(fmt.Sprintf("^%s$", os.Getenv("ACM_CERTIFICATE_MULTIPLE_ISSUED_MOST_RECENT_ARN")))
	} else {
		arnRe = regexp.MustCompile(ACMCertificateRe)
	}

	if os.Getenv("ACM_CERTIFICATE_MULTIPLE_ISSUED_DOMAIN") != "" {
		domain = os.Getenv("ACM_CERTIFICATE_MULTIPLE_ISSUED_DOMAIN")
	} else {
		domain = fmt.Sprintf("tf-acc-multiple-issued.%s", os.Getenv("ACM_CERTIFICATE_ROOT_DOMAIN"))
	}

	resourceName := "data.aws_acm_certificate.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfig(domain),
				ExpectError: regexp.MustCompile(`Multiple certificates for domain`),
			},
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfigWithStatus(domain, acm.CertificateStatusIssued),
				ExpectError: regexp.MustCompile(`Multiple certificates for domain`),
			},
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfigWithTypes(domain, acm.CertificateTypeAmazonIssued),
				ExpectError: regexp.MustCompile(`Multiple certificates for domain`),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecent(domain, true),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndStatus(domain, acm.CertificateStatusIssued, true),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
			{
				Config: testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndTypes(domain, acm.CertificateTypeAmazonIssued, true),
				Check: resource.ComposeTestCheckFunc(
					resource.TestMatchResourceAttr(resourceName, "arn", arnRe),
				),
			},
		},
	})
}

func TestAccAWSAcmCertificateDataSource_noMatchReturnsError(t *testing.T) {
	if os.Getenv("ACM_CERTIFICATE_ROOT_DOMAIN") == "" {
		t.Skip("Environment variable ACM_CERTIFICATE_ROOT_DOMAIN is not set")
	}

	domain := fmt.Sprintf("tf-acc-nonexistent.%s", os.Getenv("ACM_CERTIFICATE_ROOT_DOMAIN"))

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfig(domain),
				ExpectError: regexp.MustCompile(`No certificate for domain`),
			},
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfigWithStatus(domain, acm.CertificateStatusIssued),
				ExpectError: regexp.MustCompile(`No certificate for domain`),
			},
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfigWithTypes(domain, acm.CertificateTypeAmazonIssued),
				ExpectError: regexp.MustCompile(`No certificate for domain`),
			},
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecent(domain, true),
				ExpectError: regexp.MustCompile(`No certificate for domain`),
			},
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndStatus(domain, acm.CertificateStatusIssued, true),
				ExpectError: regexp.MustCompile(`No certificate for domain`),
			},
			{
				Config:      testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndTypes(domain, acm.CertificateTypeAmazonIssued, true),
				ExpectError: regexp.MustCompile(`No certificate for domain`),
			},
		},
	})
}

func TestAccAWSAcmCertificateDataSource_Rsa4096(t *testing.T) {
	resourceName := "aws_acm_certificate.test"
	dataSourceName := "data.aws_acm_certificate.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProvidersWithTLS,
		CheckDestroy: testAccCheckAcmCertificateDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsAcmCertificateDataSourceConfigRsa4096(),
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"),
				),
			},
		},
	})
}

func testAccCheckAwsAcmCertificateDataSourceConfig(domain string) string {
	return fmt.Sprintf(`
data "aws_acm_certificate" "test" {
	domain = "%s"
}
`, domain)
}

func testAccCheckAwsAcmCertificateDataSourceConfigWithStatus(domain, status string) string {
	return fmt.Sprintf(`
data "aws_acm_certificate" "test" {
	domain = "%s"
	statuses = ["%s"]
}
`, domain, status)
}

func testAccCheckAwsAcmCertificateDataSourceConfigWithTypes(domain, certType string) string {
	return fmt.Sprintf(`
data "aws_acm_certificate" "test" {
	domain = "%s"
	types = ["%s"]
}
`, domain, certType)
}

func testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecent(domain string, mostRecent bool) string {
	return fmt.Sprintf(`
data "aws_acm_certificate" "test" {
	domain = "%s"
	most_recent = %v
}
`, domain, mostRecent)
}

func testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndStatus(domain, status string, mostRecent bool) string {
	return fmt.Sprintf(`
data "aws_acm_certificate" "test" {
	domain = "%s"
	statuses = ["%s"]
	most_recent = %v
}
`, domain, status, mostRecent)
}

func testAccCheckAwsAcmCertificateDataSourceConfigWithMostRecentAndTypes(domain, certType string, mostRecent bool) string {
	return fmt.Sprintf(`
data "aws_acm_certificate" "test" {
	domain = "%s"
	types = ["%s"]
	most_recent = %v
}
`, domain, certType, mostRecent)
}

func testAccAwsAcmCertificateDataSourceConfigRsa4096() string {
	return fmt.Sprintf(`
resource "tls_private_key" "test" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

resource "tls_self_signed_cert" "test" {
  allowed_uses = [
    "key_encipherment",
    "digital_signature",
    "server_auth",
  ]

  key_algorithm         = "RSA"
  private_key_pem       = "${tls_private_key.test.private_key_pem}"
  validity_period_hours = 12

  subject {
    common_name  = "example.com"
    organization = "ACME Examples, Inc"
  }
}

resource "aws_acm_certificate" "test" {
  certificate_body = "${tls_self_signed_cert.test.cert_pem}"
  private_key      = "${tls_private_key.test.private_key_pem}"
}

data "aws_acm_certificate" "test" {
  domain = "${aws_acm_certificate.test.domain_name}"
}
`)
}<|endoftext|>


<commit_before>package raygun4go

import (
	"io/ioutil"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

type testElement struct {
	lineNumber  int
	packageName string
	fileName    string
	methodName  string
}

type testStack []testElement

func (t *testStack) AddEntry(lineNumber int, packageName, fileName, methodName string) {
	*t = append(*t, testElement{lineNumber, packageName, fileName, methodName})
}

func TestStack2Struct(t *testing.T) {
	Convey("#splitAtLastSlash", t, func() {
		testLine := "foo/bar/baz"
		left, right := splitAtLastSlash(testLine)
		So(left, ShouldEqual, "foo/bar")
		So(right, ShouldEqual, "baz")
	})

	Convey("#removeSpaceAndSuffix", t, func() {
		testLine := "foo:bar baz"
		result := removeSpaceAndSuffix(testLine)
		So(result, ShouldEqual, "foo:bar")
	})

	Convey("#Parse", t, func() {
		buf, _ := ioutil.ReadFile("_fixtures/stack_trace")

		stack := make(testStack, 0, 0)
		Parse(buf, &stack)

		expected := testStack{
			testElement{13,
				"main",
				"stack2struct_test.go",
				"func.001()"},
			testElement{44,
				"github.com/smartystreets/goconvey/convey",
				"registration.go",
				"(*action).Invoke(0x208304420)"},
		}

		So(len(stack), ShouldEqual, 5)

		firstEntry := stack[0]
		So(firstEntry.lineNumber, ShouldEqual, expected[0].lineNumber)
		So(firstEntry.packageName, ShouldEqual, expected[0].packageName)
		So(firstEntry.fileName, ShouldEqual, expected[0].fileName)
		So(firstEntry.methodName, ShouldEqual, expected[0].methodName)

		secondEntry := stack[1]
		So(secondEntry.lineNumber, ShouldEqual, expected[1].lineNumber)
		So(secondEntry.packageName, ShouldEqual, expected[1].packageName)
		So(secondEntry.fileName, ShouldEqual, expected[1].fileName)
		So(secondEntry.methodName, ShouldEqual, expected[1].methodName)

		So(stack[0], ShouldResemble, expected[0])
		So(stack[1], ShouldResemble, expected[1])
	})

	Convey("#ParseWithNoClassName", t, func() {
	    buf, _ := ioutil.ReadFile("_fixtures/stack_trace_with_no_class_name")

		stack := make(testStack, 0, 0)
		Parse(buf, &stack)

		expected := testStack{
			testElement{522,
				"",
				"panic.go",
				"panic(0x662440, 0x716bf0)"},
		}

		So(len(stack), ShouldEqual, 1)

		firstEntry := stack[0]
		So(firstEntry.lineNumber, ShouldEqual, expected[0].lineNumber)
		So(firstEntry.packageName, ShouldEqual, expected[0].packageName)
		So(firstEntry.fileName, ShouldEqual, expected[0].fileName)
		So(firstEntry.methodName, ShouldEqual, expected[0].methodName)

		So(stack[0], ShouldResemble, expected[0])
	})

	Convey("#ParseWithNoMemoryAddress", t, func() {
	    buf, _ := ioutil.ReadFile("_fixtures/stack_trace_with_no_memory_address")

		stack := make(testStack, 0, 0)
		Parse(buf, &stack)

		expected := testStack{
			testElement{13,
				"main",
				"stack2struct_test.go",
				"func.001()"},
		}

		So(len(stack), ShouldEqual, 1)

		firstEntry := stack[0]
		So(firstEntry.lineNumber, ShouldEqual, expected[0].lineNumber)
		So(firstEntry.packageName, ShouldEqual, expected[0].packageName)
		So(firstEntry.fileName, ShouldEqual, expected[0].fileName)
		So(firstEntry.methodName, ShouldEqual, expected[0].methodName)

		So(stack[0], ShouldResemble, expected[0])
	})

}
<commit_msg>Unit test<commit_after>package raygun4go

import (
	"io/ioutil"
	"testing"

	goerrors "github.com/go-errors/errors"
	. "github.com/smartystreets/goconvey/convey"
)

type testElement struct {
	lineNumber  int
	packageName string
	fileName    string
	methodName  string
}

type testStack []testElement

func (t *testStack) AddEntry(lineNumber int, packageName, fileName, methodName string) {
	*t = append(*t, testElement{lineNumber, packageName, fileName, methodName})
}

func TestStack2Struct(t *testing.T) {
	Convey("#splitAtLastSlash", t, func() {
		testLine := "foo/bar/baz"
		left, right := splitAtLastSlash(testLine)
		So(left, ShouldEqual, "foo/bar")
		So(right, ShouldEqual, "baz")
	})

	Convey("#removeSpaceAndSuffix", t, func() {
		testLine := "foo:bar baz"
		result := removeSpaceAndSuffix(testLine)
		So(result, ShouldEqual, "foo:bar")
	})

	Convey("#Parse", t, func() {
		buf, _ := ioutil.ReadFile("_fixtures/stack_trace")

		stack := make(testStack, 0, 0)
		Parse(buf, &stack)

		expected := testStack{
			testElement{13,
				"main",
				"stack2struct_test.go",
				"func.001()"},
			testElement{44,
				"github.com/smartystreets/goconvey/convey",
				"registration.go",
				"(*action).Invoke(0x208304420)"},
		}

		So(len(stack), ShouldEqual, 5)

		firstEntry := stack[0]
		So(firstEntry.lineNumber, ShouldEqual, expected[0].lineNumber)
		So(firstEntry.packageName, ShouldEqual, expected[0].packageName)
		So(firstEntry.fileName, ShouldEqual, expected[0].fileName)
		So(firstEntry.methodName, ShouldEqual, expected[0].methodName)

		secondEntry := stack[1]
		So(secondEntry.lineNumber, ShouldEqual, expected[1].lineNumber)
		So(secondEntry.packageName, ShouldEqual, expected[1].packageName)
		So(secondEntry.fileName, ShouldEqual, expected[1].fileName)
		So(secondEntry.methodName, ShouldEqual, expected[1].methodName)

		So(stack[0], ShouldResemble, expected[0])
		So(stack[1], ShouldResemble, expected[1])
	})

	Convey("#ParseWithNoClassName", t, func() {
		buf, _ := ioutil.ReadFile("_fixtures/stack_trace_with_no_class_name")

		stack := make(testStack, 0, 0)
		Parse(buf, &stack)

		expected := testStack{
			testElement{522,
				"",
				"panic.go",
				"panic(0x662440, 0x716bf0)"},
		}

		So(len(stack), ShouldEqual, 1)

		firstEntry := stack[0]
		So(firstEntry.lineNumber, ShouldEqual, expected[0].lineNumber)
		So(firstEntry.packageName, ShouldEqual, expected[0].packageName)
		So(firstEntry.fileName, ShouldEqual, expected[0].fileName)
		So(firstEntry.methodName, ShouldEqual, expected[0].methodName)

		So(stack[0], ShouldResemble, expected[0])
	})

	Convey("#ParseWithNoMemoryAddress", t, func() {
		buf, _ := ioutil.ReadFile("_fixtures/stack_trace_with_no_memory_address")

		stack := make(testStack, 0, 0)
		Parse(buf, &stack)

		expected := testStack{
			testElement{13,
				"main",
				"stack2struct_test.go",
				"func.001()"},
		}

		So(len(stack), ShouldEqual, 1)

		firstEntry := stack[0]
		So(firstEntry.lineNumber, ShouldEqual, expected[0].lineNumber)
		So(firstEntry.packageName, ShouldEqual, expected[0].packageName)
		So(firstEntry.fileName, ShouldEqual, expected[0].fileName)
		So(firstEntry.methodName, ShouldEqual, expected[0].methodName)

		So(stack[0], ShouldResemble, expected[0])
	})

	Convey("#LoadGoErrorStack", t, func() {
		testFrames := []goerrors.StackFrame{
			{File: "stack2struct_test.go",
				LineNumber: 13,
				Name:       "func.001()",
				Package:    "main"},
			{File: "registration.go",
				LineNumber: 44,
				Name:       "(*action).Invoke(0x208304420)",
				Package:    "github.com/smartystreets/goconvey/convey"},
		}

		stack := make(testStack, 0, 0)
		LoadGoErrorStack(testFrames, &stack)

		expected := testStack{
			testElement{13,
				"main",
				"stack2struct_test.go",
				"func.001()"},
			testElement{44,
				"github.com/smartystreets/goconvey/convey",
				"registration.go",
				"(*action).Invoke(0x208304420)"},
		}

		firstEntry := stack[0]
		So(firstEntry.lineNumber, ShouldEqual, expected[0].lineNumber)
		So(firstEntry.packageName, ShouldEqual, expected[0].packageName)
		So(firstEntry.fileName, ShouldEqual, expected[0].fileName)
		So(firstEntry.methodName, ShouldEqual, expected[0].methodName)

		secondEntry := stack[1]
		So(secondEntry.lineNumber, ShouldEqual, expected[1].lineNumber)
		So(secondEntry.packageName, ShouldEqual, expected[1].packageName)
		So(secondEntry.fileName, ShouldEqual, expected[1].fileName)
		So(secondEntry.methodName, ShouldEqual, expected[1].methodName)

		So(stack[0], ShouldResemble, expected[0])
		So(stack[1], ShouldResemble, expected[1])
	})
}
<|endoftext|>


<commit_before>package htmlfiller_test

import (
    "testing"
    . "launchpad.net/gocheck"
	"github.com/griffy/htmlfiller"
)

// hook gocheck into the gotest runner
func Test(t *testing.T) { TestingT(t) }

type S struct {}
var _ = Suite(&S{})

func (s *S) TestFillElement(c *C) {
    html := `<input name="test"/>`
    obsHtml := htmlfiller.FillElement(html, "test", "val")
    expHtml := `<input name="test" value="val"/>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<input name="test" value="old"/>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<input name="test" value="val"/>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<input name="test"></input>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<input name="test" value="val"></input>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<input name="test" value="old"></input>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<input name="test" value="val"></input>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<select name="test">
    <option value="opt1">Option 1</option>
    <option value="opt2">Option 2</option>
    <option value="opt3">Option 3</option>
    </select>`
    obsHtml = htmlfiller.FillElement(html, "test", "opt2")
    expHtml = `<select name="test">
    <option value="opt1">Option 1</option>
    <option value="opt2" selected="selected">Option 2</option>
    <option value="opt3">Option 3</option>
    </select>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<textarea name="test"></textarea>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<textarea name="test">val</textarea>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<textarea name="test">old</textarea>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<textarea name="test">val</textarea>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<span id="test"></span>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<span id="test">val</span>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<span id="test">old</span>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<span id="test">val</span>`
    c.Check(obsHtml, Equals, expHtml)
}

func (s *S) TestFill(c *C) {
    defaultVals := make(map[string]string)
    defaultVals["elem1"] = "val"
    defaultVals["elem2"] = "opt2"
    defaultVals["elem3"] = "val"
    html := `<form action="">

    <input type="text" name="elem1"/>

    <select name="elem2">
    <option value="opt1">Option 1</option>
    <option value="opt2">Option 2</option>
    </select>

    <textarea name="elem3"></textarea>
    </form>`
    obsHtml := htmlfiller.Fill(html, defaultVals)
    expHtml := `<form action="">

    <input type="text" name="elem1" value="val"/>

    <select name="elem2">
    <option value="opt1">Option 1</option>
    <option value="opt2" selected="selected">Option 2</option>
    </select>

    <textarea name="elem3">val</textarea>
    </form>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<form action="">

    <input type="text" name="elem1" value="old"/>

    <select name="elem2">
    <option value="opt1" selected="selected">Option 1</option>
    <option value="opt2">Option 2</option>
    </select>

    <textarea name="elem3">old</textarea>
    </form>`
    obsHtml = htmlfiller.Fill(html, defaultVals)
    expHtml = `<form action="">

    <input type="text" name="elem1" value="val"/>

    <select name="elem2">
    <option value="opt1">Option 1</option>
    <option value="opt2" selected="selected">Option 2</option>
    </select>

    <textarea name="elem3">val</textarea>
    </form>`
    c.Check(obsHtml, Equals, expHtml)

    errors := make(map[string]string)
    errors["elem1"] = "Invalid value"
    errors["elem2"] = "Invalid option"
    errors["elem3"] = "Invalid value"
    html = `<form action="">

    <input type="text" name="elem1"/>

    <select name="elem2">
    <option value="opt1">Option 1</option>
    <option value="opt2">Option 2</option>
    </select>

    <textarea name="elem3"></textarea>
    </form>`
    obsHtml = htmlfiller.Fill(html, defaultVals, errors)
    expHtml = `<form action="">
    Invalid value
    <input type="text" name="elem1" value="val"/>
    Invalid option
    <select name="elem2">
    <option value="opt1">Option 1</option>
    <option value="opt2" selected="selected">Option 2</option>
    </select>
    Invalid value
    <textarea name="elem3">val</textarea>
    </form>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<form action="">

    <input type="text" name="elem1" value="old"/>

    <select name="elem2">
    <option value="opt1" selected="selected">Option 1</option>
    <option value="opt2">Option 2</option>
    </select>

    <textarea name="elem3">old</textarea>
    </form>`
    obsHtml = htmlfiller.Fill(html, defaultVals, errors)
    expHtml = `<form action="">
    Invalid value
    <input type="text" name="elem1" value="val"/>
    Invalid option
    <select name="elem2">
    <option value="opt1">Option 1</option>
    <option value="opt2" selected="selected">Option 2</option>
    </select>
    Invalid value
    <textarea name="elem3">val</textarea>
    </form>`
    c.Check(obsHtml, Equals, expHtml)
}

<commit_msg>add a test for checkboxes<commit_after>package htmlfiller_test

import (
    "testing"
    . "launchpad.net/gocheck"
	"github.com/griffy/htmlfiller"
)

// hook gocheck into the gotest runner
func Test(t *testing.T) { TestingT(t) }

type S struct {}
var _ = Suite(&S{})

func (s *S) TestFillElement(c *C) {
    html := `<input name="test"/>`
    obsHtml := htmlfiller.FillElement(html, "test", "val")
    expHtml := `<input name="test" value="val"/>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<input name="test" value="old"/>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<input name="test" value="val"/>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<input name="test"></input>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<input name="test" value="val"></input>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<input name="test" value="old"></input>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<input name="test" value="val"></input>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<input type="checkbox" name="test" value="val"/>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<input type="checkbox" name="test" value="val" checked="checked"/>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<input name="test"></input>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<input name="test" value="val"></input>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<input name="test" value="old"></input>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<input name="test" value="val"></input>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<select name="test">
    <option value="opt1">Option 1</option>
    <option value="opt2">Option 2</option>
    <option value="opt3">Option 3</option>
    </select>`
    obsHtml = htmlfiller.FillElement(html, "test", "opt2")
    expHtml = `<select name="test">
    <option value="opt1">Option 1</option>
    <option value="opt2" selected="selected">Option 2</option>
    <option value="opt3">Option 3</option>
    </select>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<textarea name="test"></textarea>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<textarea name="test">val</textarea>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<textarea name="test">old</textarea>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<textarea name="test">val</textarea>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<span id="test"></span>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<span id="test">val</span>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<span id="test">old</span>`
    obsHtml = htmlfiller.FillElement(html, "test", "val")
    expHtml = `<span id="test">val</span>`
    c.Check(obsHtml, Equals, expHtml)
}

func (s *S) TestFill(c *C) {
    defaultVals := make(map[string]string)
    defaultVals["elem1"] = "val"
    defaultVals["elem2"] = "opt2"
    defaultVals["elem3"] = "val"
    html := `<form action="">

    <input type="text" name="elem1"/>

    <select name="elem2">
    <option value="opt1">Option 1</option>
    <option value="opt2">Option 2</option>
    </select>

    <textarea name="elem3"></textarea>
    </form>`
    obsHtml := htmlfiller.Fill(html, defaultVals)
    expHtml := `<form action="">

    <input type="text" name="elem1" value="val"/>

    <select name="elem2">
    <option value="opt1">Option 1</option>
    <option value="opt2" selected="selected">Option 2</option>
    </select>

    <textarea name="elem3">val</textarea>
    </form>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<form action="">

    <input type="text" name="elem1" value="old"/>

    <select name="elem2">
    <option value="opt1" selected="selected">Option 1</option>
    <option value="opt2">Option 2</option>
    </select>

    <textarea name="elem3">old</textarea>
    </form>`
    obsHtml = htmlfiller.Fill(html, defaultVals)
    expHtml = `<form action="">

    <input type="text" name="elem1" value="val"/>

    <select name="elem2">
    <option value="opt1">Option 1</option>
    <option value="opt2" selected="selected">Option 2</option>
    </select>

    <textarea name="elem3">val</textarea>
    </form>`
    c.Check(obsHtml, Equals, expHtml)

    errors := make(map[string]string)
    errors["elem1"] = "Invalid value"
    errors["elem2"] = "Invalid option"
    errors["elem3"] = "Invalid value"
    html = `<form action="">

    <input type="text" name="elem1"/>

    <select name="elem2">
    <option value="opt1">Option 1</option>
    <option value="opt2">Option 2</option>
    </select>

    <textarea name="elem3"></textarea>
    </form>`
    obsHtml = htmlfiller.Fill(html, defaultVals, errors)
    expHtml = `<form action="">
    Invalid value
    <input type="text" name="elem1" value="val"/>
    Invalid option
    <select name="elem2">
    <option value="opt1">Option 1</option>
    <option value="opt2" selected="selected">Option 2</option>
    </select>
    Invalid value
    <textarea name="elem3">val</textarea>
    </form>`
    c.Check(obsHtml, Equals, expHtml)

    html = `<form action="">

    <input type="text" name="elem1" value="old"/>

    <select name="elem2">
    <option value="opt1" selected="selected">Option 1</option>
    <option value="opt2">Option 2</option>
    </select>

    <textarea name="elem3">old</textarea>
    </form>`
    obsHtml = htmlfiller.Fill(html, defaultVals, errors)
    expHtml = `<form action="">
    Invalid value
    <input type="text" name="elem1" value="val"/>
    Invalid option
    <select name="elem2">
    <option value="opt1">Option 1</option>
    <option value="opt2" selected="selected">Option 2</option>
    </select>
    Invalid value
    <textarea name="elem3">val</textarea>
    </form>`
    c.Check(obsHtml, Equals, expHtml)
}

<|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 restplugin

import (
	"github.com/gorilla/mux"
	aclplugin "github.com/ligato/vpp-agent/plugins/defaultplugins/aclplugin/vppcalls"
	ifplugin "github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/vppdump"
	l2plugin "github.com/ligato/vpp-agent/plugins/defaultplugins/l2plugin/vppdump"
	//l3plugin "github.com/ligato/vpp-agent/plugins/defaultplugins/l3plugin/vppdump"
	"git.fd.io/govpp.git/core/bin_api/vpe"
	"github.com/unrolled/render"
	"net/http"
	"strconv"
	//"github.com/ligato/vpp-agent/plugins/defaultplugins/l3plugin"
	"encoding/json"
	"fmt"
	"github.com/docker/docker/daemon/logger"
	"io/ioutil"
)

//interfaceGetHandler - used to get list of all interfaces
func (plugin *RESTAPIPlugin) interfacesGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		plugin.Deps.Log.Info("Getting list of all interfaces")

		// create an API channel
		ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
		if err != nil {
			plugin.Deps.Log.Errorf("Error: %v", err)
			formatter.JSON(w, http.StatusInternalServerError, nil)
		} else {
			res, err := ifplugin.DumpInterfaces(plugin.Deps.Log, ch, nil)
			if err != nil {
				plugin.Deps.Log.Errorf("Error: %v", err)
				formatter.JSON(w, http.StatusInternalServerError, nil)
			} else {
				plugin.Deps.Log.Debug(res)
				formatter.JSON(w, http.StatusOK, res)
			}
		}
		defer ch.Close()
	}
}

//bridgeDomainGetHandler - used to get list of all bridge domains
func (plugin *RESTAPIPlugin) bridgeDomainIdsGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		plugin.Deps.Log.Info("Getting list of all bridge domain ids")

		// create an API channel
		ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
		if err != nil {
			plugin.Deps.Log.Errorf("Error: %v", err)
			formatter.JSON(w, http.StatusInternalServerError, nil)
		} else {
			res, err := l2plugin.DumpBridgeDomainIDs(plugin.Deps.Log, ch, nil)
			if err != nil {
				plugin.Deps.Log.Errorf("Error: %v", err)
				formatter.JSON(w, http.StatusInternalServerError, nil)
			} else {
				plugin.Deps.Log.Debug(res)
				formatter.JSON(w, http.StatusOK, res)
			}
		}
		defer ch.Close()
	}
}

//bridgeDomainGetHandler - used to get list of all bridge domains
func (plugin *RESTAPIPlugin) bridgeDomainsGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		plugin.Deps.Log.Info("Getting list of all bridge domains")

		// create an API channel
		ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
		if err != nil {
			plugin.Deps.Log.Errorf("Error: %v", err)
			formatter.JSON(w, http.StatusInternalServerError, nil)
		} else {
			res, err := l2plugin.DumpBridgeDomains(plugin.Deps.Log, ch, nil)
			if err != nil {
				plugin.Deps.Log.Errorf("Error: %v", err)
				formatter.JSON(w, http.StatusInternalServerError, nil)
			} else {
				plugin.Deps.Log.Debug(res)
				formatter.JSON(w, http.StatusOK, res)
			}
		}
		defer ch.Close()
	}
}

//fibTableEntriesGetHandler - used to get list of all fib entries
func (plugin *RESTAPIPlugin) fibTableEntriesGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		plugin.Deps.Log.Info("Getting list of all fibs")

		// create an API channel
		ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
		if err != nil {
			plugin.Deps.Log.Errorf("Error: %v", err)
			formatter.JSON(w, http.StatusInternalServerError, nil)
		} else {
			res, err := l2plugin.DumpFIBTableEntries(plugin.Deps.Log, ch, nil)
			if err != nil {
				plugin.Deps.Log.Errorf("Error: %v", err)
				formatter.JSON(w, http.StatusInternalServerError, nil)
			} else {
				plugin.Deps.Log.Debug(res)
				formatter.JSON(w, http.StatusOK, res)
			}
		}
		defer ch.Close()
	}
}

//xconnectPairsGetHandler - used to get list of all connect pairs (transmit and receive interfaces)
func (plugin *RESTAPIPlugin) xconnectPairsGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		plugin.Deps.Log.Info("Getting list of all xconnect pairs")

		// create an API channel
		ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
		if err != nil {
			plugin.Deps.Log.Errorf("Error: %v", err)
			formatter.JSON(w, http.StatusInternalServerError, nil)
		} else {
			res, err := l2plugin.DumpXConnectPairs(plugin.Deps.Log, ch, nil)
			if err != nil {
				plugin.Deps.Log.Errorf("Error: %v", err)
				formatter.JSON(w, http.StatusInternalServerError, nil)
			} else {
				plugin.Deps.Log.Debug(res)
				formatter.JSON(w, http.StatusOK, res)
			}
		}
		defer ch.Close()
	}
}

//staticRoutesGetHandler - used to get list of all static routes
/*
func (plugin *RESTAPIPlugin) staticRoutesGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		plugin.Deps.Log.Info("Getting list of all static routes")

		// create an API channel
		ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
		if err != nil {
			plugin.Deps.Log.Errorf("Error: %v", err)
			formatter.JSON(w, http.StatusInternalServerError, nil)
		} else {
			res, err := l3plugin.DumpStaticRoutes(plugin.Deps.Log, ch, nil)
			if err != nil {
				plugin.Deps.Log.Errorf("Error: %v", err)
				formatter.JSON(w, http.StatusInternalServerError, nil)
			} else {
				plugin.Deps.Log.Debug(res)
				formatter.JSON(w, http.StatusOK, res)
			}
		}
		defer ch.Close()
	}
}
*/

//interfaceAclPostHandler - used to get acl configuration for a particular interface
func (plugin *RESTAPIPlugin) interfaceAclPostHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		plugin.Deps.Log.Info("Getting list of all static routes")

		params := mux.Vars(req)
		if params != nil && len(params) > 0 {
			swIndexStr := params["swIndex"]
			if swIndexStr != "" {
				swIndexuInt64, err := strconv.ParseUint(swIndexStr, 10, 32)
				swIndex := uint32(swIndexuInt64)
				if err != nil {
					// create an API channel
					ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
					if err != nil {
						plugin.Deps.Log.Errorf("Error: %v", err)
						formatter.JSON(w, http.StatusInternalServerError, nil)
					} else {
						res, err := aclplugin.DumpInterface(swIndex, ch, nil)
						if err != nil {
							plugin.Deps.Log.Errorf("Error: %v", err)
							formatter.JSON(w, http.StatusInternalServerError, nil)
						} else {
							plugin.Deps.Log.Debug(res)
							formatter.JSON(w, http.StatusOK, res)
						}
					}
					defer ch.Close()
				}
			} else {
				formatter.JSON(w, http.StatusBadRequest, "swIndex parameter not found")
			}
		}
	}
}

//showCommandHandler - used to execute VPP CLI show commands
func (plugin *RESTAPIPlugin) showCommandHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		//params := mux.Vars(req)
		//if params != nil && len(params) > 0 {
		//	showCommand := params["showCommand"]

		/* Parse input request */
		var reqParam map[string]string
		body, err := ioutil.ReadAll(req.Body)
		if err != nil {
			plugin.Deps.Log.Error("Failed to parse request body.")
			formatter.JSON(w, http.StatusInternalServerError, err)
		}

		plugin.Deps.Log.Infof("request body = %v", body)
		err = json.Unmarshal(body, &reqParam)
		if err != nil {
			plugin.Deps.Log.Error("Failed to unmarshall request body.")
			formatter.JSON(w, http.StatusInternalServerError, err)
		}

		command, ok := reqParam["vppclicommand"]

		if !ok {
			plugin.Deps.Log.Error("command paramenter not included.")
			formatter.JSON(w, http.StatusInternalServerError, err)
			//TODO: return
		}

		plugin.Deps.Log.Infof("Received request to execute command :: %v ", command)
		plugin.Deps.Log.WithField("VPPCLI command", command)

		if command != "" {
			// create an API channel
			ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
			if err != nil {
				plugin.Deps.Log.Errorf("Error: %v", err)
				formatter.JSON(w, http.StatusInternalServerError, err)
			} else {
				// prepare the message
				req := &vpe.CliInband{}
				req.Length = uint32(len(command))
				req.Cmd = []byte(command)

				reply := &vpe.CliInbandReply{}
				err = ch.SendRequest(req).ReceiveReply(reply)
				if err != nil {
					plugin.Deps.Log.Errorf("Error: %v", err)
					formatter.JSON(w, http.StatusInternalServerError, err)
				}

				if 0 != reply.Retval {
					plugin.Deps.Log.Errorf("Command returned code :: %v", reply.Retval)
				}

				plugin.Deps.Log.Infof("Command returned reply :: %v", string(reply.Reply))
				plugin.Deps.Log.WithField("VPPCLI response", string(reply.Reply))
				formatter.JSON(w, http.StatusOK, reply)
			}
			defer ch.Close()
		} else {
			formatter.JSON(w, http.StatusBadRequest, "showCommand parameter is empty")
		}
		//} else {
		//	formatter.JSON(w, http.StatusBadRequest, "showCommand parameter not found")
		//}
	}
}
<commit_msg>SPOPT-1690 - REST API for VPP<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 restplugin

import (
	"github.com/gorilla/mux"
	aclplugin "github.com/ligato/vpp-agent/plugins/defaultplugins/aclplugin/vppcalls"
	ifplugin "github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/vppdump"
	l2plugin "github.com/ligato/vpp-agent/plugins/defaultplugins/l2plugin/vppdump"
	//l3plugin "github.com/ligato/vpp-agent/plugins/defaultplugins/l3plugin/vppdump"
	"git.fd.io/govpp.git/core/bin_api/vpe"
	"github.com/unrolled/render"
	"net/http"
	"strconv"
	//"github.com/ligato/vpp-agent/plugins/defaultplugins/l3plugin"
	"encoding/json"
	"io/ioutil"
)

//interfaceGetHandler - used to get list of all interfaces
func (plugin *RESTAPIPlugin) interfacesGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		plugin.Deps.Log.Info("Getting list of all interfaces")

		// create an API channel
		ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
		if err != nil {
			plugin.Deps.Log.Errorf("Error: %v", err)
			formatter.JSON(w, http.StatusInternalServerError, nil)
		} else {
			res, err := ifplugin.DumpInterfaces(plugin.Deps.Log, ch, nil)
			if err != nil {
				plugin.Deps.Log.Errorf("Error: %v", err)
				formatter.JSON(w, http.StatusInternalServerError, nil)
			} else {
				plugin.Deps.Log.Debug(res)
				formatter.JSON(w, http.StatusOK, res)
			}
		}
		defer ch.Close()
	}
}

//bridgeDomainGetHandler - used to get list of all bridge domains
func (plugin *RESTAPIPlugin) bridgeDomainIdsGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		plugin.Deps.Log.Info("Getting list of all bridge domain ids")

		// create an API channel
		ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
		if err != nil {
			plugin.Deps.Log.Errorf("Error: %v", err)
			formatter.JSON(w, http.StatusInternalServerError, nil)
		} else {
			res, err := l2plugin.DumpBridgeDomainIDs(plugin.Deps.Log, ch, nil)
			if err != nil {
				plugin.Deps.Log.Errorf("Error: %v", err)
				formatter.JSON(w, http.StatusInternalServerError, nil)
			} else {
				plugin.Deps.Log.Debug(res)
				formatter.JSON(w, http.StatusOK, res)
			}
		}
		defer ch.Close()
	}
}

//bridgeDomainGetHandler - used to get list of all bridge domains
func (plugin *RESTAPIPlugin) bridgeDomainsGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		plugin.Deps.Log.Info("Getting list of all bridge domains")

		// create an API channel
		ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
		if err != nil {
			plugin.Deps.Log.Errorf("Error: %v", err)
			formatter.JSON(w, http.StatusInternalServerError, nil)
		} else {
			res, err := l2plugin.DumpBridgeDomains(plugin.Deps.Log, ch, nil)
			if err != nil {
				plugin.Deps.Log.Errorf("Error: %v", err)
				formatter.JSON(w, http.StatusInternalServerError, nil)
			} else {
				plugin.Deps.Log.Debug(res)
				formatter.JSON(w, http.StatusOK, res)
			}
		}
		defer ch.Close()
	}
}

//fibTableEntriesGetHandler - used to get list of all fib entries
func (plugin *RESTAPIPlugin) fibTableEntriesGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		plugin.Deps.Log.Info("Getting list of all fibs")

		// create an API channel
		ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
		if err != nil {
			plugin.Deps.Log.Errorf("Error: %v", err)
			formatter.JSON(w, http.StatusInternalServerError, nil)
		} else {
			res, err := l2plugin.DumpFIBTableEntries(plugin.Deps.Log, ch, nil)
			if err != nil {
				plugin.Deps.Log.Errorf("Error: %v", err)
				formatter.JSON(w, http.StatusInternalServerError, nil)
			} else {
				plugin.Deps.Log.Debug(res)
				formatter.JSON(w, http.StatusOK, res)
			}
		}
		defer ch.Close()
	}
}

//xconnectPairsGetHandler - used to get list of all connect pairs (transmit and receive interfaces)
func (plugin *RESTAPIPlugin) xconnectPairsGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		plugin.Deps.Log.Info("Getting list of all xconnect pairs")

		// create an API channel
		ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
		if err != nil {
			plugin.Deps.Log.Errorf("Error: %v", err)
			formatter.JSON(w, http.StatusInternalServerError, nil)
		} else {
			res, err := l2plugin.DumpXConnectPairs(plugin.Deps.Log, ch, nil)
			if err != nil {
				plugin.Deps.Log.Errorf("Error: %v", err)
				formatter.JSON(w, http.StatusInternalServerError, nil)
			} else {
				plugin.Deps.Log.Debug(res)
				formatter.JSON(w, http.StatusOK, res)
			}
		}
		defer ch.Close()
	}
}

//staticRoutesGetHandler - used to get list of all static routes
/*
func (plugin *RESTAPIPlugin) staticRoutesGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		plugin.Deps.Log.Info("Getting list of all static routes")

		// create an API channel
		ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
		if err != nil {
			plugin.Deps.Log.Errorf("Error: %v", err)
			formatter.JSON(w, http.StatusInternalServerError, nil)
		} else {
			res, err := l3plugin.DumpStaticRoutes(plugin.Deps.Log, ch, nil)
			if err != nil {
				plugin.Deps.Log.Errorf("Error: %v", err)
				formatter.JSON(w, http.StatusInternalServerError, nil)
			} else {
				plugin.Deps.Log.Debug(res)
				formatter.JSON(w, http.StatusOK, res)
			}
		}
		defer ch.Close()
	}
}
*/

//interfaceAclPostHandler - used to get acl configuration for a particular interface
func (plugin *RESTAPIPlugin) interfaceAclPostHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		plugin.Deps.Log.Info("Getting list of all static routes")

		params := mux.Vars(req)
		if params != nil && len(params) > 0 {
			swIndexStr := params["swIndex"]
			if swIndexStr != "" {
				swIndexuInt64, err := strconv.ParseUint(swIndexStr, 10, 32)
				swIndex := uint32(swIndexuInt64)
				if err != nil {
					// create an API channel
					ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
					if err != nil {
						plugin.Deps.Log.Errorf("Error: %v", err)
						formatter.JSON(w, http.StatusInternalServerError, nil)
					} else {
						res, err := aclplugin.DumpInterface(swIndex, ch, nil)
						if err != nil {
							plugin.Deps.Log.Errorf("Error: %v", err)
							formatter.JSON(w, http.StatusInternalServerError, nil)
						} else {
							plugin.Deps.Log.Debug(res)
							formatter.JSON(w, http.StatusOK, res)
						}
					}
					defer ch.Close()
				}
			} else {
				formatter.JSON(w, http.StatusBadRequest, "swIndex parameter not found")
			}
		}
	}
}

//showCommandHandler - used to execute VPP CLI show commands
func (plugin *RESTAPIPlugin) showCommandHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {

		//params := mux.Vars(req)
		//if params != nil && len(params) > 0 {
		//	showCommand := params["showCommand"]

		/* Parse input request */
		var reqParam map[string]string
		body, err := ioutil.ReadAll(req.Body)
		if err != nil {
			plugin.Deps.Log.Error("Failed to parse request body.")
			formatter.JSON(w, http.StatusInternalServerError, err)
		}

		plugin.Deps.Log.Infof("request body = %v", body)
		err = json.Unmarshal(body, &reqParam)
		if err != nil {
			plugin.Deps.Log.Error("Failed to unmarshall request body.")
			formatter.JSON(w, http.StatusInternalServerError, err)
		}

		command, ok := reqParam["vppclicommand"]

		if !ok {
			plugin.Deps.Log.Error("command paramenter not included.")
			formatter.JSON(w, http.StatusInternalServerError, err)
			//TODO: return
		}

		plugin.Deps.Log.Infof("Received request to execute command :: %v ", command)
		plugin.Deps.Log.WithField("VPPCLI command", command)

		if command != "" {
			// create an API channel
			ch, err := plugin.Deps.GoVppmux.NewAPIChannel()
			if err != nil {
				plugin.Deps.Log.Errorf("Error: %v", err)
				formatter.JSON(w, http.StatusInternalServerError, err)
			} else {
				// prepare the message
				req := &vpe.CliInband{}
				req.Length = uint32(len(command))
				req.Cmd = []byte(command)

				reply := &vpe.CliInbandReply{}
				err = ch.SendRequest(req).ReceiveReply(reply)
				if err != nil {
					plugin.Deps.Log.Errorf("Error: %v", err)
					formatter.JSON(w, http.StatusInternalServerError, err)
				}

				if 0 != reply.Retval {
					plugin.Deps.Log.Errorf("Command returned code :: %v", reply.Retval)
				}

				plugin.Deps.Log.Infof("Command returned reply :: %v", string(reply.Reply))
				plugin.Deps.Log.WithField("VPPCLI response", string(reply.Reply))
				formatter.JSON(w, http.StatusOK, reply)
			}
			defer ch.Close()
		} else {
			formatter.JSON(w, http.StatusBadRequest, "showCommand parameter is empty")
		}
		//} else {
		//	formatter.JSON(w, http.StatusBadRequest, "showCommand parameter not found")
		//}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"runtime"
)

type Build struct{}

func main() {
	build := new(Build)
	build.do()
}

func (b *Build) do() {
	switch runtime.GOOS {
	case "darwin":
		b.darwin()
	default:
		fmt.Printf("not supported os: %s.\n", runtime.GOOS)
	}
}

// darwin is building a new .pkg installer for darwin based OS'es. create a
// folder called "root", which will be used as the installer content.
func (b *Build) darwin() {
	version := "1.0.0"
	scriptDir := "./darwin/scripts"
	installRoot := "./root"
	tempDest, err := ioutil.TempDir("", "tempDest")
	if err != nil {
		return
	}
	defer os.RemoveAll(tempDest)

	cmdPkg := exec.Command("pkgbuild",
		"--identifier", "com.koding.kite.pkg",
		"--version", version,
		"--scripts", scriptDir,
		"--root", installRoot,
		"--install-location", "/",
		tempDest+"/com.koding.kite.pkg", // used for next step, also set up for distribution.xml
	)

	res, err := cmdPkg.CombinedOutput()
	if err != nil {
		fmt.Println("res, err", string(res), err)
		return
	}

	distribution := "./darwin/Distribution.xml" // TODO: create it via a template
	resources := "./darwin/Resources"
	targetFile := "koding-kd-tool.pkg"

	cmdBuild := exec.Command("productbuild",
		"--distribution", distribution,
		"--resources", resources,
		"--package-path", tempDest,
		targetFile,
	)

	res, err = cmdBuild.CombinedOutput()
	if err != nil {
		fmt.Println("res, err", string(res), err)
		return
	}

	fmt.Println("everything is ok")

}
<commit_msg>kd/build: add templating for darwin scripts<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"runtime"
	"text/template"
)

type Build struct{}

func main() {
	build := new(Build)
	build.do()
}

func (b *Build) do() {
	switch runtime.GOOS {
	case "darwin":
		b.darwin()
	default:
		fmt.Printf("not supported os: %s.\n", runtime.GOOS)
	}
}

// darwin is building a new .pkg installer for darwin based OS'es. create a
// folder called "root", which will be used as the installer content.
func (b *Build) darwin() {
	const (
		postInstall = `#!/bin/bash

KITE_PLIST="/Library/LaunchAgents/com.koding.kite.{{.}}.plist"
chown root:wheel ${KITE_PLIST}
chmod 644 ${KITE_PLIST}

echo $USER
su $USER -c "/bin/launchctl load ${KITE_PLIST}"

exit 0
`

		preInstall = `#!/bin/sh

KDFILE=/usr/local/bin/{{.}}

echo "Removing previous installation"
if [ -f $KDFILE  ]; then
    rm -r $KDFILE
fi

echo "Checking for plist"
if /bin/launchctl list "com.koding.kite.{{.}}.plist" &> /dev/null; then
    echo "Unloading plist"
    /bin/launchctl unload "/Library/LaunchAgents/com.koding.kite.{{.}}.plist"
fi

exit 0
`
	)

	version := "1.0.0"
	scriptDir := "./darwin/scripts"
	installRoot := "./root"
	tempDest, err := ioutil.TempDir("", "tempDest")
	if err != nil {
		return
	}
	defer os.RemoveAll(tempDest)

	templatePost := template.Must(template.New("postInstall").Parse(postInstall))
	templatePost.Execute(os.Stdout, "fatih")

	templatePre := template.Must(template.New("preInstall").Parse(preInstall))
	templatePre.Execute(os.Stdout, "fatih")

	cmdPkg := exec.Command("pkgbuild",
		"--identifier", "com.koding.kite.pkg",
		"--version", version,
		"--scripts", scriptDir,
		"--root", installRoot,
		"--install-location", "/",
		tempDest+"/com.koding.kite.pkg", // used for next step, also set up for distribution.xml
	)

	res, err := cmdPkg.CombinedOutput()
	if err != nil {
		fmt.Println("res, err", string(res), err)
		return
	}

	distribution := "./darwin/Distribution.xml" // TODO: create it via a template
	resources := "./darwin/Resources"
	targetFile := "koding-kd-tool.pkg"

	cmdBuild := exec.Command("productbuild",
		"--distribution", distribution,
		"--resources", resources,
		"--package-path", tempDest,
		targetFile,
	)

	res, err = cmdBuild.CombinedOutput()
	if err != nil {
		fmt.Println("res, err", string(res), err)
		return
	}

	fmt.Println("everything is ok")

}
<|endoftext|>


<commit_before>package suggestionbox

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"path"
	"strings"

	"github.com/pkg/errors"
)

// Model represents a single model inside Suggestionbox.
type Model struct {
	// ID is the ID of the model.
	ID string `json:"id,omitempty"`
	// Name is the human readable name of the Model.
	Name string `json:"name"`
	// Options are optional Model settings to adjust the behaviour
	// of this Model within Suggestionbox.
	Options *ModelOptions `json:"options,omitempty"`
	// Choices are the options this Model will select from.
	Choices []Choice `json:"choices,omitempty"`
}

// NewModel makes a new Model.
func NewModel(id, name string, choices ...Choice) Model {
	return Model{
		ID:      id,
		Name:    name,
		Choices: choices,
	}
}

// Feature represents a single feature, to describe an input or a choice
// for example age:28 or location:"London".
type Feature struct {
	// Key is the name of the Feature.
	Key string `json:"key"`
	// Value is the string value of this Feature.
	Value string `json:"value"`
	// Type is the type of the Feature.
	// Can be "number", "text", "keyword", "list", "image_url" or "image_base64"..
	Type string `json:"type"`
}

// Choice is an option with features.
type Choice struct {
	// ID is a unique ID for this choice.
	ID string `json:"id"`
	// Features holds all the Feature objects that describe
	// this choice.
	Features []Feature `json:"features,omitempty"`
}

// NewChoice creates a new Choice.
func NewChoice(id string, features ...Feature) Choice {
	return Choice{
		ID:       id,
		Features: features,
	}
}

// ModelOptions describes the behaviours of a Model.
type ModelOptions struct {
	// RewardExpirationSeconds is the number of seconds to wait for the reward before it expires.
	RewardExpirationSeconds int `json:"reward_expiration_seconds,omitempty"`

	// Epsilon enables proportionate exploiting vs exploring ratio.
	Epsilon float64 `json:"epsilon,omitempty"`

	// SoftmaxLambda enables adaptive exploiting vs exploring ratio.
	SoftmaxLambda float64 `json:"softmax_lambda,omitempty"`

	// Ngrams describes the n-grams for text analysis.
	Ngrams int `json:"ngrams,omitempty"`
	// Skipgrams describes the skip-grams for the text analysis.
	Skipgrams int `json:"skipgrams,omitempty"`
}

// ListModels gets a Model by its ID.
func (c *Client) ListModels(ctx context.Context) ([]Model, error) {
	u, err := url.Parse(c.addr + "/suggestionbox/models")
	if err != nil {
		return nil, err
	}
	if !u.IsAbs() {
		return nil, errors.New("box address must be absolute")
	}
	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
	if err != nil {
		return nil, err
	}
	req = req.WithContext(ctx)
	req.Header.Set("Accept", "application/json; charset=utf-8")
	resp, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, errors.New(resp.Status)
	}
	var response struct {
		Success bool
		Error   string
		Models  []Model
	}
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		return nil, errors.Wrap(err, "decoding response")
	}
	if !response.Success {
		return nil, ErrSuggestionbox(response.Error)
	}
	return response.Models, nil
}

// GetModel gets a Model by its ID.
func (c *Client) GetModel(ctx context.Context, modelID string) (Model, error) {
	var model Model
	u, err := url.Parse(c.addr + "/" + path.Join("suggestionbox", "models", modelID))
	if err != nil {
		return model, err
	}
	if !u.IsAbs() {
		return model, errors.New("box address must be absolute")
	}
	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
	if err != nil {
		return model, err
	}
	req = req.WithContext(ctx)
	req.Header.Set("Accept", "application/json; charset=utf-8")
	resp, err := c.HTTPClient.Do(req)
	if err != nil {
		return model, err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return model, errors.New(resp.Status)
	}
	var response struct {
		Success bool
		Error   string
		Model
	}
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		return model, errors.Wrap(err, "decoding response")
	}
	if !response.Success {
		return model, ErrSuggestionbox(response.Error)
	}
	return response.Model, nil
}

// DeleteModel gets a Model by its ID.
func (c *Client) DeleteModel(ctx context.Context, modelID string) error {
	u, err := url.Parse(c.addr + "/" + path.Join("suggestionbox", "models", modelID))
	if err != nil {
		return err
	}
	if !u.IsAbs() {
		return errors.New("box address must be absolute")
	}
	req, err := http.NewRequest(http.MethodDelete, u.String(), nil)
	if err != nil {
		return err
	}
	req = req.WithContext(ctx)
	req.Header.Set("Accept", "application/json; charset=utf-8")
	resp, err := c.HTTPClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return errors.New(resp.Status)
	}
	var response struct {
		Success bool
		Error   string
		Model
	}
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		return errors.Wrap(err, "decoding response")
	}
	if !response.Success {
		return ErrSuggestionbox(response.Error)
	}
	return nil
}

// CreateModel creates the Model in Suggestionbox.
// If no ID is set, one will be assigned in the return Model.
func (c *Client) CreateModel(ctx context.Context, model Model) (Model, error) {
	u, err := url.Parse(c.addr + "/suggestionbox/models")
	if err != nil {
		return model, err
	}
	if !u.IsAbs() {
		return model, errors.New("box address must be absolute")
	}
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(model); err != nil {
		return model, errors.Wrap(err, "encoding request body")
	}
	req, err := http.NewRequest(http.MethodPost, u.String(), &buf)
	if err != nil {
		return model, err
	}
	req = req.WithContext(ctx)
	req.Header.Set("Accept", "application/json; charset=utf-8")
	req.Header.Set("Content-Type", "application/json; charset=utf-8")
	resp, err := c.HTTPClient.Do(req)
	if err != nil {
		return model, err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return model, errors.New(resp.Status)
	}
	var response struct {
		Success bool
		Error   string
		Model
	}
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		return model, errors.Wrap(err, "decoding response")
	}
	if !response.Success {
		return model, ErrSuggestionbox(response.Error)
	}
	return response.Model, nil
}

// FeatureNumber makes a numerical Feature.
func FeatureNumber(key string, value float64) Feature {
	return Feature{
		Type:  "number",
		Key:   key,
		Value: fmt.Sprintf("%v", value),
	}
}

// FeatureText makes a textual Feature that will be tokenized.
// Use FeatureKeyword for values that should not be tokenized.
func FeatureText(key string, text string) Feature {
	return Feature{
		Type:  "text",
		Key:   key,
		Value: text,
	}
}

// FeatureKeyword makes a textual Feature that will not be tokenized.
// Use FeatureList to provide multiple keywords in a single Feature.
// Use Text for bodies of text that should be tokenized.
func FeatureKeyword(key string, keyword string) Feature {
	return Feature{
		Type:  "keyword",
		Key:   key,
		Value: keyword,
	}
}

// FeatureList makes a Feature made up of multiple keywords.
func FeatureList(key string, keywords ...string) Feature {
	return Feature{
		Type:  "list",
		Key:   key,
		Value: strings.Join(keywords, ","),
	}
}

// FeatureImageURL makes a Feature that points to a hosted image.
func FeatureImageURL(key string, url string) Feature {
	return Feature{
		Type:  "image_url",
		Key:   key,
		Value: url,
	}
}

// FeatureImageBase64 makes a Feature that is base 64 encoded.
func FeatureImageBase64(key string, data string) Feature {
	return Feature{
		Type:  "image_base64",
		Key:   key,
		Value: data,
	}
}
<commit_msg>comment tweak<commit_after>package suggestionbox

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"path"
	"strings"

	"github.com/pkg/errors"
)

// Model represents a single model inside Suggestionbox.
type Model struct {
	// ID is the ID of the model.
	ID string `json:"id,omitempty"`
	// Name is the human readable name of the Model.
	Name string `json:"name"`
	// Options are optional Model settings to adjust the behaviour
	// of this Model within Suggestionbox.
	Options *ModelOptions `json:"options,omitempty"`
	// Choices are the options this Model will select from.
	Choices []Choice `json:"choices,omitempty"`
}

// NewModel makes a new Model.
func NewModel(id, name string, choices ...Choice) Model {
	return Model{
		ID:      id,
		Name:    name,
		Choices: choices,
	}
}

// Feature represents a single feature, to describe an input or a choice
// for example age:28 or location:"London".
type Feature struct {
	// Key is the name of the Feature.
	Key string `json:"key"`
	// Value is the string value of this Feature.
	Value string `json:"value"`
	// Type is the type of the Feature.
	// Can be "number", "text", "keyword", "list", "image_url" or "image_base64"..
	Type string `json:"type"`
}

// Choice is an option with features.
type Choice struct {
	// ID is a unique ID for this choice.
	ID string `json:"id"`
	// Features holds all the Feature objects that describe
	// this choice.
	Features []Feature `json:"features,omitempty"`
}

// NewChoice creates a new Choice.
func NewChoice(id string, features ...Feature) Choice {
	return Choice{
		ID:       id,
		Features: features,
	}
}

// ModelOptions describes the behaviours of a Model.
type ModelOptions struct {
	// RewardExpirationSeconds is the number of seconds to wait for
	// the reward before it expires.
	RewardExpirationSeconds int `json:"reward_expiration_seconds,omitempty"`

	// Epsilon enables proportionate exploiting vs exploring ratio.
	Epsilon float64 `json:"epsilon,omitempty"`

	// SoftmaxLambda enables adaptive exploiting vs exploring ratio.
	SoftmaxLambda float64 `json:"softmax_lambda,omitempty"`

	// Ngrams describes the n-grams for text analysis.
	Ngrams int `json:"ngrams,omitempty"`
	// Skipgrams describes the skip-grams for the text analysis.
	Skipgrams int `json:"skipgrams,omitempty"`
}

// ListModels gets a Model by its ID.
func (c *Client) ListModels(ctx context.Context) ([]Model, error) {
	u, err := url.Parse(c.addr + "/suggestionbox/models")
	if err != nil {
		return nil, err
	}
	if !u.IsAbs() {
		return nil, errors.New("box address must be absolute")
	}
	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
	if err != nil {
		return nil, err
	}
	req = req.WithContext(ctx)
	req.Header.Set("Accept", "application/json; charset=utf-8")
	resp, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, errors.New(resp.Status)
	}
	var response struct {
		Success bool
		Error   string
		Models  []Model
	}
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		return nil, errors.Wrap(err, "decoding response")
	}
	if !response.Success {
		return nil, ErrSuggestionbox(response.Error)
	}
	return response.Models, nil
}

// GetModel gets a Model by its ID.
func (c *Client) GetModel(ctx context.Context, modelID string) (Model, error) {
	var model Model
	u, err := url.Parse(c.addr + "/" + path.Join("suggestionbox", "models", modelID))
	if err != nil {
		return model, err
	}
	if !u.IsAbs() {
		return model, errors.New("box address must be absolute")
	}
	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
	if err != nil {
		return model, err
	}
	req = req.WithContext(ctx)
	req.Header.Set("Accept", "application/json; charset=utf-8")
	resp, err := c.HTTPClient.Do(req)
	if err != nil {
		return model, err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return model, errors.New(resp.Status)
	}
	var response struct {
		Success bool
		Error   string
		Model
	}
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		return model, errors.Wrap(err, "decoding response")
	}
	if !response.Success {
		return model, ErrSuggestionbox(response.Error)
	}
	return response.Model, nil
}

// DeleteModel gets a Model by its ID.
func (c *Client) DeleteModel(ctx context.Context, modelID string) error {
	u, err := url.Parse(c.addr + "/" + path.Join("suggestionbox", "models", modelID))
	if err != nil {
		return err
	}
	if !u.IsAbs() {
		return errors.New("box address must be absolute")
	}
	req, err := http.NewRequest(http.MethodDelete, u.String(), nil)
	if err != nil {
		return err
	}
	req = req.WithContext(ctx)
	req.Header.Set("Accept", "application/json; charset=utf-8")
	resp, err := c.HTTPClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return errors.New(resp.Status)
	}
	var response struct {
		Success bool
		Error   string
		Model
	}
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		return errors.Wrap(err, "decoding response")
	}
	if !response.Success {
		return ErrSuggestionbox(response.Error)
	}
	return nil
}

// CreateModel creates the Model in Suggestionbox.
// If no ID is set, one will be assigned in the return Model.
func (c *Client) CreateModel(ctx context.Context, model Model) (Model, error) {
	u, err := url.Parse(c.addr + "/suggestionbox/models")
	if err != nil {
		return model, err
	}
	if !u.IsAbs() {
		return model, errors.New("box address must be absolute")
	}
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(model); err != nil {
		return model, errors.Wrap(err, "encoding request body")
	}
	req, err := http.NewRequest(http.MethodPost, u.String(), &buf)
	if err != nil {
		return model, err
	}
	req = req.WithContext(ctx)
	req.Header.Set("Accept", "application/json; charset=utf-8")
	req.Header.Set("Content-Type", "application/json; charset=utf-8")
	resp, err := c.HTTPClient.Do(req)
	if err != nil {
		return model, err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return model, errors.New(resp.Status)
	}
	var response struct {
		Success bool
		Error   string
		Model
	}
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		return model, errors.Wrap(err, "decoding response")
	}
	if !response.Success {
		return model, ErrSuggestionbox(response.Error)
	}
	return response.Model, nil
}

// FeatureNumber makes a numerical Feature.
func FeatureNumber(key string, value float64) Feature {
	return Feature{
		Type:  "number",
		Key:   key,
		Value: fmt.Sprintf("%v", value),
	}
}

// FeatureText makes a textual Feature that will be tokenized.
// Use FeatureKeyword for values that should not be tokenized.
func FeatureText(key string, text string) Feature {
	return Feature{
		Type:  "text",
		Key:   key,
		Value: text,
	}
}

// FeatureKeyword makes a textual Feature that will not be tokenized.
// Use FeatureList to provide multiple keywords in a single Feature.
// Use Text for bodies of text that should be tokenized.
func FeatureKeyword(key string, keyword string) Feature {
	return Feature{
		Type:  "keyword",
		Key:   key,
		Value: keyword,
	}
}

// FeatureList makes a Feature made up of multiple keywords.
func FeatureList(key string, keywords ...string) Feature {
	return Feature{
		Type:  "list",
		Key:   key,
		Value: strings.Join(keywords, ","),
	}
}

// FeatureImageURL makes a Feature that points to a hosted image.
func FeatureImageURL(key string, url string) Feature {
	return Feature{
		Type:  "image_url",
		Key:   key,
		Value: url,
	}
}

// FeatureImageBase64 makes a Feature that is base 64 encoded.
func FeatureImageBase64(key string, data string) Feature {
	return Feature{
		Type:  "image_base64",
		Key:   key,
		Value: data,
	}
}
<|endoftext|>


<commit_before>// Server application serves index engine via rest API.
// TODO :
//  - Create a goroutine that will pull mutations from UPR and update the
//    index.

package main

import (
	//	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/couchbaselabs/indexing/api"
	"github.com/couchbaselabs/indexing/catalog"
	//	"github.com/couchbaselabs/indexing/engine/llrb"
	"github.com/couchbaselabs/indexing/engine/leveldb"
	"log"
	"net/http"
	//	"strconv"
	"sync"
)

var c catalog.IndexCatalog
var ddlLock sync.Mutex

const (
	DEFAULT_LIMIT int = 100
)

func main() {
	var err error

	// Create index catalog
	if c, err = catalog.NewIndexCatalog("./"); err != nil {
		log.Fatalf("Fatal error opening catalog: %v", err)
	}

	openIndexEngine()

	addr := ":8095"
	// Subscribe to HTTP server handlers
	http.HandleFunc("/create", handleCreate)
	http.HandleFunc("/drop", handleDrop)
	http.HandleFunc("/scan", handleScan)
	http.HandleFunc("/stats", handleStats)

	//FIXME add error handing to this
	go StartMutationManager()

	//FIXME This doesn't work on Ctrl-C
	defer freeResourcesOnExit()
	log.Println("Indexer Listening on", addr)
	if err := http.ListenAndServe(addr, nil); err != nil {
		log.Fatalf("Fatal: %v", err)
	}

}

// /create
func handleCreate(w http.ResponseWriter, r *http.Request) {
	var res api.IndexMetaResponse
	var err error

	indexinfo := indexRequest(r).Index // Get IndexInfo

	ddlLock.Lock()
	defer ddlLock.Unlock()

	if err = assignIndexEngine(&indexinfo); err == nil {
		if _, err = c.Create(indexinfo); err == nil {
			res = api.IndexMetaResponse{
				Status: api.SUCCESS,
			}
			log.Printf("Created index(%v) %v", indexinfo.Uuid, indexinfo.Name)
		}
	}
	if err != nil {
		res = createMetaResponseFromError(err)
		log.Println("ERROR: Failed to create index", err)
	}
	RegisterIndexWithMutationHandler(indexinfo)
	sendResponse(w, res)
}

// /drop
func handleDrop(w http.ResponseWriter, r *http.Request) {
	var res api.IndexMetaResponse
	var err error

	indexinfo := indexRequest(r).Index

	ddlLock.Lock()
	defer ddlLock.Unlock()

	if indexinfo, err = c.Index(indexinfo.Uuid); err == nil {
		if err = indexinfo.Engine.Destroy(); err == nil {
			if _, err = c.Drop(indexinfo.Uuid); err == nil {
				res = api.IndexMetaResponse{
					Status: api.SUCCESS,
				}
			}
		}
		log.Printf("Dropped index(%v) %v", indexinfo.Uuid, indexinfo.Name)
	}

	if err != nil {
		res = createMetaResponseFromError(err)
		log.Println("ERROR: Failed to drop index", err)
	}
	sendResponse(w, res)
}

// /scan
func handleScan(w http.ResponseWriter, r *http.Request) {
	var err error

	indexreq := indexRequest(r) // Gather request
	uuid := indexreq.Index.Uuid
	q := indexreq.Params

	log.Printf("Received Scan Index %v Params %v %v", uuid, q.Low, q.High)

	// Scan
	rows := make([]api.IndexRow, 0)
	var totalRows uint64
	var lowkey, highkey api.Key

	if lowkey, err = api.NewKey(q.Low, ""); err != nil {
		sendScanResponse(w, nil, 0, err)
		return
	}

	if highkey, err = api.NewKey(q.High, ""); err != nil {
		sendScanResponse(w, nil, 0, err)
		return
	}

	if indexinfo, err := c.Index(uuid); err == nil {
		switch q.ScanType {

		case api.COUNT:
			totalRows, err = countQuery(&indexinfo, q.Limit)

		case api.EXISTS:
			var exists bool
			exists, err = existsQuery(&indexinfo, lowkey)
			if exists {
				totalRows = 1
			}

		case api.LOOKUP:

			rows, err = lookupQuery(&indexinfo,
				lowkey, q.Limit)
			totalRows = uint64(len(rows))

		case api.RANGESCAN:

			rows, err = rangeQuery(&indexinfo, lowkey, highkey, q.Inclusion, q.Limit)
			totalRows = uint64(len(rows))

		case api.FULLSCAN:
			rows, err = scanQuery(&indexinfo, q.Limit)
			totalRows = uint64(len(rows))

		case api.RANGECOUNT:
			totalRows, err = rangeCountQuery(&indexinfo, lowkey, highkey, q.Inclusion, q.Limit)
		}
	}
	// send back the response
	sendScanResponse(w, rows, totalRows, err)
}

// /stats.
func handleStats(w http.ResponseWriter, r *http.Request) {
	panic("Not yet impleted")
}

//---- helper functions

func countQuery(indexinfo *api.IndexInfo, limit int64) (
	uint64, error) {

	if counter, ok := indexinfo.Engine.(api.Counter); ok {
		count, err := counter.CountTotal()
		return count, err
	}
	err := errors.New("Index does not support Looker interface")
	return uint64(0), err
}

func existsQuery(indexinfo *api.IndexInfo, key api.Key) (bool, error) {

	if exister, ok := indexinfo.Engine.(api.Exister); ok {
		exists := exister.Exists(key)
		return exists, nil
	}
	err := errors.New("Index does not support Exister interface")
	return false, err
}

func scanQuery(indexinfo *api.IndexInfo, limit int64) (
	[]api.IndexRow, error) {

	if looker, ok := indexinfo.Engine.(api.Looker); ok {
		ch, cherr := looker.ValueSet()
		return receiveValue(ch, cherr, limit)
	}
	err := errors.New("Index does not support Looker interface")
	return nil, err
}

func rangeQuery(
	indexinfo *api.IndexInfo, low, high api.Key, incl api.Inclusion,
	limit int64) ([]api.IndexRow, error) {

	if ranger, ok := indexinfo.Engine.(api.Ranger); ok {
		ch, cherr, _ := ranger.ValueRange(low, high, incl)
		return receiveValue(ch, cherr, limit)
	}
	err := errors.New("Index does not support ranger interface")
	return nil, err
}

func lookupQuery(indexinfo *api.IndexInfo, key api.Key, limit int64) (
	[]api.IndexRow, error) {

	if looker, ok := indexinfo.Engine.(api.Looker); ok {
		log.Printf("Looking up key %s", key.String())
		ch, cherr := looker.Lookup(key)
		return receiveValue(ch, cherr, limit)
	}
	err := errors.New("Index does not support looker interface")
	return nil, err
}

func rangeCountQuery(
	indexinfo *api.IndexInfo, low, high api.Key, incl api.Inclusion,
	limit int64) (uint64, error) {

	if rangeCounter, ok := indexinfo.Engine.(api.RangeCounter); ok {
		totalRows, err := rangeCounter.CountRange(low, high, incl)
		return totalRows, err
	}
	err := errors.New("Index does not support RangeCounter interface")
	return 0, err
}
func sendResponse(w http.ResponseWriter, res interface{}) {
	var buf []byte
	var err error
	header := w.Header()
	header["Content-Type"] = []string{"application/json"}

	if buf, err = json.Marshal(&res); err != nil {
		log.Println("Unable to marshal response", res)
	}
	w.Write(buf)
}

func sendScanResponse(w http.ResponseWriter, rows []api.IndexRow, totalRows uint64, err error) {
	var res api.IndexScanResponse

	if err == nil {
		res = api.IndexScanResponse{
			Status:    api.SUCCESS,
			TotalRows: totalRows,
			Rows:      rows,
			Errors:    nil,
		}
	} else {
		indexerr := api.IndexError{Code: string(api.ERROR), Msg: err.Error()}
		res = api.IndexScanResponse{
			Status:    api.SUCCESS,
			TotalRows: uint64(0),
			Rows:      nil,
			Errors:    []api.IndexError{indexerr},
		}
	}
	sendResponse(w, res)
}

func receiveValue(ch chan api.Value, cherr chan error, limit int64) (
	[]api.IndexRow, error) {

	//FIXME limit should be sent to the engine and only limit response be sent on the
	//channel
	rows := make([]api.IndexRow, 0)
	var nolimit = false
	if limit == 0 {
		nolimit = true
	}
	ok := true
	var value api.Value
	var err error
	for ok && (limit > 0 || nolimit) {
		select {
		case value, ok = <-ch:
			if ok {
				log.Printf("Indexer Received Value %s", value.String())
				row := api.IndexRow{
					Key:   value.KeyBytes(),
					Value: value.Docid(),
				}
				rows = append(rows, row)
				limit--
			}
		case err, ok = <-cherr:
			if err != nil {
				return rows, err
			}
		}
	}
	return rows, nil
}

// Parse HTTP Request to get IndexInfo.
func indexRequest(r *http.Request) *api.IndexRequest {
	indexreq := api.IndexRequest{}
	buf := make([]byte, r.ContentLength, r.ContentLength)
	r.Body.Read(buf)
	json.Unmarshal(buf, &indexreq)
	return &indexreq
}

func createMetaResponseFromError(err error) api.IndexMetaResponse {

	indexerr := api.IndexError{Code: string(api.ERROR), Msg: err.Error()}
	res := api.IndexMetaResponse{
		Status: api.ERROR,
		Errors: []api.IndexError{indexerr},
	}
	return res
}

// Instantiate index engine
func assignIndexEngine(indexinfo *api.IndexInfo) error {
	var err error
	indexinfo.Engine = nil
	switch indexinfo.Using {
	//	case api.Llrb:
	//		indexinfo.Engine = llrb.NewIndexEngine(indexinfo.Uuid)
	case api.Llrb:
		indexinfo.Engine = leveldb.NewIndexEngine(indexinfo.Uuid)
	default:
		err = errors.New(fmt.Sprintf("Invalid index-type, `%v`", indexinfo.Using))
	}
	return err
}

func openIndexEngine() error {

	var err error
	var indexinfos []api.IndexInfo
	//For the existing indexes, open the existing engine
	if _, indexinfos, err = c.List(""); err != nil {
		log.Printf("Error while retrieving index list %v", err)
		return err
	}

	for _, indexinfo := range indexinfos {
		log.Printf("Try Finding Existing Engine for Index %v", indexinfo)
		switch indexinfo.Using {
		case api.Llrb:
			indexinfo.Engine = leveldb.OpenIndexEngine(indexinfo.Uuid)
			log.Printf("Got Existing Engine for Index %v", indexinfo.Uuid)
		default:
			err = errors.New(fmt.Sprintf("Unknown Index Type. Skipping Opening Engine"))
		}
	}

	return err

}

func freeResourcesOnExit() {

	//purge the catalog
	if err := c.Purge(); err != nil {
		log.Printf("Error Purging Catalog %v", err)
	}

	//close the index engines
	if err := closeIndexEngines(); err != nil {
		log.Printf("Error Closing Index Engine %v", err)
	}

	//FIXME close the mutation manager?

}

func closeIndexEngines() error {

	if _, indexinfos, err := c.List(""); err == nil {

		for _, indexinfo := range indexinfos {
			if err := indexinfo.Engine.Close(); err != nil {
				return err
			}
		}
	} else {
		return err
	}

	return nil
}
<commit_msg>Return Error status for errors in indexer<commit_after>// Server application serves index engine via rest API.
// TODO :
//  - Create a goroutine that will pull mutations from UPR and update the
//    index.

package main

import (
	//	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/couchbaselabs/indexing/api"
	"github.com/couchbaselabs/indexing/catalog"
	//	"github.com/couchbaselabs/indexing/engine/llrb"
	"github.com/couchbaselabs/indexing/engine/leveldb"
	"log"
	"net/http"
	//	"strconv"
	"sync"
)

var c catalog.IndexCatalog
var ddlLock sync.Mutex

const (
	DEFAULT_LIMIT int = 100
)

func main() {
	var err error

	// Create index catalog
	if c, err = catalog.NewIndexCatalog("./"); err != nil {
		log.Fatalf("Fatal error opening catalog: %v", err)
	}

	openIndexEngine()

	addr := ":8095"
	// Subscribe to HTTP server handlers
	http.HandleFunc("/create", handleCreate)
	http.HandleFunc("/drop", handleDrop)
	http.HandleFunc("/scan", handleScan)
	http.HandleFunc("/stats", handleStats)

	//FIXME add error handing to this
	go StartMutationManager()

	//FIXME This doesn't work on Ctrl-C
	defer freeResourcesOnExit()
	log.Println("Indexer Listening on", addr)
	if err := http.ListenAndServe(addr, nil); err != nil {
		log.Fatalf("Fatal: %v", err)
	}

}

// /create
func handleCreate(w http.ResponseWriter, r *http.Request) {
	var res api.IndexMetaResponse
	var err error

	indexinfo := indexRequest(r).Index // Get IndexInfo

	ddlLock.Lock()
	defer ddlLock.Unlock()

	if err = assignIndexEngine(&indexinfo); err == nil {
		if _, err = c.Create(indexinfo); err == nil {
			res = api.IndexMetaResponse{
				Status: api.SUCCESS,
			}
			log.Printf("Created index(%v) %v", indexinfo.Uuid, indexinfo.Name)
		}
	}
	if err != nil {
		res = createMetaResponseFromError(err)
		log.Println("ERROR: Failed to create index", err)
	}
	RegisterIndexWithMutationHandler(indexinfo)
	sendResponse(w, res)
}

// /drop
func handleDrop(w http.ResponseWriter, r *http.Request) {
	var res api.IndexMetaResponse
	var err error

	indexinfo := indexRequest(r).Index

	ddlLock.Lock()
	defer ddlLock.Unlock()

	if indexinfo, err = c.Index(indexinfo.Uuid); err == nil {
		if err = indexinfo.Engine.Destroy(); err == nil {
			if _, err = c.Drop(indexinfo.Uuid); err == nil {
				res = api.IndexMetaResponse{
					Status: api.SUCCESS,
				}
			}
		}
		log.Printf("Dropped index(%v) %v", indexinfo.Uuid, indexinfo.Name)
	}

	if err != nil {
		res = createMetaResponseFromError(err)
		log.Println("ERROR: Failed to drop index", err)
	}
	sendResponse(w, res)
}

// /scan
func handleScan(w http.ResponseWriter, r *http.Request) {
	var err error

	indexreq := indexRequest(r) // Gather request
	uuid := indexreq.Index.Uuid
	q := indexreq.Params

	log.Printf("Received Scan Index %v Params %v %v", uuid, q.Low, q.High)

	// Scan
	rows := make([]api.IndexRow, 0)
	var totalRows uint64
	var lowkey, highkey api.Key

	if lowkey, err = api.NewKey(q.Low, ""); err != nil {
		sendScanResponse(w, nil, 0, err)
		return
	}

	if highkey, err = api.NewKey(q.High, ""); err != nil {
		sendScanResponse(w, nil, 0, err)
		return
	}

	var indexinfo api.IndexInfo
	if indexinfo, err = c.Index(uuid); err == nil {
		switch q.ScanType {

		case api.COUNT:
			totalRows, err = countQuery(&indexinfo, q.Limit)

		case api.EXISTS:
			var exists bool
			exists, err = existsQuery(&indexinfo, lowkey)
			if exists {
				totalRows = 1
			}

		case api.LOOKUP:

			rows, err = lookupQuery(&indexinfo, lowkey, q.Limit)
			totalRows = uint64(len(rows))

		case api.RANGESCAN:

			rows, err = rangeQuery(&indexinfo, lowkey, highkey, q.Inclusion, q.Limit)
			totalRows = uint64(len(rows))

		case api.FULLSCAN:
			rows, err = scanQuery(&indexinfo, q.Limit)
			totalRows = uint64(len(rows))

		case api.RANGECOUNT:
			totalRows, err = rangeCountQuery(&indexinfo, lowkey, highkey, q.Inclusion, q.Limit)
		}
	}
	// send back the response
	sendScanResponse(w, rows, totalRows, err)
}

// /stats.
func handleStats(w http.ResponseWriter, r *http.Request) {
	panic("Not yet impleted")
}

//---- helper functions

func countQuery(indexinfo *api.IndexInfo, limit int64) (
	uint64, error) {

	if counter, ok := indexinfo.Engine.(api.Counter); ok {
		count, err := counter.CountTotal()
		return count, err
	}
	err := errors.New("Index does not support Looker interface")
	return uint64(0), err
}

func existsQuery(indexinfo *api.IndexInfo, key api.Key) (bool, error) {

	if exister, ok := indexinfo.Engine.(api.Exister); ok {
		exists := exister.Exists(key)
		return exists, nil
	}
	err := errors.New("Index does not support Exister interface")
	return false, err
}

func scanQuery(indexinfo *api.IndexInfo, limit int64) (
	[]api.IndexRow, error) {

	if looker, ok := indexinfo.Engine.(api.Looker); ok {
		ch, cherr := looker.ValueSet()
		return receiveValue(ch, cherr, limit)
	}
	err := errors.New("Index does not support Looker interface")
	return nil, err
}

func rangeQuery(
	indexinfo *api.IndexInfo, low, high api.Key, incl api.Inclusion,
	limit int64) ([]api.IndexRow, error) {

	if ranger, ok := indexinfo.Engine.(api.Ranger); ok {
		ch, cherr, _ := ranger.ValueRange(low, high, incl)
		return receiveValue(ch, cherr, limit)
	}
	err := errors.New("Index does not support ranger interface")
	return nil, err
}

func lookupQuery(indexinfo *api.IndexInfo, key api.Key, limit int64) (
	[]api.IndexRow, error) {

	if looker, ok := indexinfo.Engine.(api.Looker); ok {
		log.Printf("Looking up key %s", key.String())
		ch, cherr := looker.Lookup(key)
		return receiveValue(ch, cherr, limit)
	}
	err := errors.New("Index does not support looker interface")
	return nil, err
}

func rangeCountQuery(
	indexinfo *api.IndexInfo, low, high api.Key, incl api.Inclusion,
	limit int64) (uint64, error) {

	if rangeCounter, ok := indexinfo.Engine.(api.RangeCounter); ok {
		totalRows, err := rangeCounter.CountRange(low, high, incl)
		return totalRows, err
	}
	err := errors.New("Index does not support RangeCounter interface")
	return 0, err
}
func sendResponse(w http.ResponseWriter, res interface{}) {
	var buf []byte
	var err error
	header := w.Header()
	header["Content-Type"] = []string{"application/json"}

	if buf, err = json.Marshal(&res); err != nil {
		log.Println("Unable to marshal response", res)
	}
	w.Write(buf)
}

func sendScanResponse(w http.ResponseWriter, rows []api.IndexRow, totalRows uint64, err error) {
	var res api.IndexScanResponse

	if err == nil {
		res = api.IndexScanResponse{
			Status:    api.SUCCESS,
			TotalRows: totalRows,
			Rows:      rows,
			Errors:    nil,
		}
	} else {
		indexerr := api.IndexError{Code: string(api.ERROR), Msg: err.Error()}
		res = api.IndexScanResponse{
			Status:    api.ERROR,
			TotalRows: uint64(0),
			Rows:      nil,
			Errors:    []api.IndexError{indexerr},
		}
	}
	sendResponse(w, res)
}

func receiveValue(ch chan api.Value, cherr chan error, limit int64) (
	[]api.IndexRow, error) {

	//FIXME limit should be sent to the engine and only limit response be sent on the
	//channel
	rows := make([]api.IndexRow, 0)
	var nolimit = false
	if limit == 0 {
		nolimit = true
	}
	ok := true
	var value api.Value
	var err error
	for ok && (limit > 0 || nolimit) {
		select {
		case value, ok = <-ch:
			if ok {
				log.Printf("Indexer Received Value %s", value.String())
				row := api.IndexRow{
					Key:   value.KeyBytes(),
					Value: value.Docid(),
				}
				rows = append(rows, row)
				limit--
			}
		case err, ok = <-cherr:
			if err != nil {
				return rows, err
			}
		}
	}
	return rows, nil
}

// Parse HTTP Request to get IndexInfo.
func indexRequest(r *http.Request) *api.IndexRequest {
	indexreq := api.IndexRequest{}
	buf := make([]byte, r.ContentLength, r.ContentLength)
	r.Body.Read(buf)
	json.Unmarshal(buf, &indexreq)
	return &indexreq
}

func createMetaResponseFromError(err error) api.IndexMetaResponse {

	indexerr := api.IndexError{Code: string(api.ERROR), Msg: err.Error()}
	res := api.IndexMetaResponse{
		Status: api.ERROR,
		Errors: []api.IndexError{indexerr},
	}
	return res
}

// Instantiate index engine
func assignIndexEngine(indexinfo *api.IndexInfo) error {
	var err error
	indexinfo.Engine = nil
	switch indexinfo.Using {
	//	case api.Llrb:
	//		indexinfo.Engine = llrb.NewIndexEngine(indexinfo.Uuid)
	case api.Llrb:
		indexinfo.Engine = leveldb.NewIndexEngine(indexinfo.Uuid)
	default:
		err = errors.New(fmt.Sprintf("Invalid index-type, `%v`", indexinfo.Using))
	}
	return err
}

func openIndexEngine() error {

	var err error
	var indexinfos []api.IndexInfo
	//For the existing indexes, open the existing engine
	if _, indexinfos, err = c.List(""); err != nil {
		log.Printf("Error while retrieving index list %v", err)
		return err
	}

	for _, indexinfo := range indexinfos {
		log.Printf("Try Finding Existing Engine for Index %v", indexinfo)
		switch indexinfo.Using {
		case api.Llrb:
			indexinfo.Engine = leveldb.OpenIndexEngine(indexinfo.Uuid)
			log.Printf("Got Existing Engine for Index %v", indexinfo.Uuid)
		default:
			err = errors.New(fmt.Sprintf("Unknown Index Type. Skipping Opening Engine"))
		}
	}

	return err

}

func freeResourcesOnExit() {

	//purge the catalog
	if err := c.Purge(); err != nil {
		log.Printf("Error Purging Catalog %v", err)
	}

	//close the index engines
	if err := closeIndexEngines(); err != nil {
		log.Printf("Error Closing Index Engine %v", err)
	}

	//FIXME close the mutation manager?

}

func closeIndexEngines() error {

	if _, indexinfos, err := c.List(""); err == nil {

		for _, indexinfo := range indexinfos {
			if err := indexinfo.Engine.Close(); err != nil {
				return err
			}
		}
	} else {
		return err
	}

	return nil
}
<|endoftext|>