<commit_before>package aws

import (
	"fmt"
	"testing"

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

func TestAccLexSlotType_basic(t *testing.T) {
	rName := "aws_lex_slot_type.test"
	testSlotTypeID := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsLexSlotTypeNotExists(testSlotTypeID, LexSlotTypeVersionLatest),
		Steps: []resource.TestStep{
			{
				Config: testAccAwsLexSlotTypeConfig_basic(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, LexSlotTypeVersionLatest),
					resource.TestCheckResourceAttr(rName, "description", ""),
					resource.TestCheckResourceAttr(rName, "enumeration_value.#", "0"),
					resource.TestCheckResourceAttr(rName, "name", testSlotTypeID),
					resource.TestCheckResourceAttr(rName, "value_selection_strategy", lexmodelbuildingservice.SlotValueSelectionStrategyOriginalValue),
					resource.TestCheckResourceAttrSet(rName, "checksum"),
					resource.TestCheckResourceAttrSet(rName, "version"),
					testAccCheckResourceAttrRfc3339(rName, "created_date"),
					testAccCheckResourceAttrRfc3339(rName, "last_updated_date"),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
		},
	})
}

func TestAccAwsLexSlotType_createVersion(t *testing.T) {
	rName := "aws_lex_slot_type.test"
	testSlotTypeID := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsLexSlotTypeNotExists(testSlotTypeID, LexSlotTypeVersionLatest),
		Steps: []resource.TestStep{
			{
				Config: testAccAwsLexSlotTypeConfig_withoutVersion(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, LexSlotTypeVersionLatest),
					testAccCheckAwsLexSlotTypeNotExists(testSlotTypeID, "1"),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
			{
				Config: testAccAwsLexSlotTypeConfig_basic(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, LexSlotTypeVersionLatest),
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, "1"),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
		},
	})
}

func TestAccAwsLexSlotType_description(t *testing.T) {
	rName := "aws_lex_slot_type.test"
	testSlotTypeID := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsLexSlotTypeNotExists(testSlotTypeID, LexSlotTypeVersionLatest),
		Steps: []resource.TestStep{
			{
				Config: testAccAwsLexSlotTypeConfig_basic(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, LexSlotTypeVersionLatest),
					resource.TestCheckResourceAttr(rName, "description", ""),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
			{
				Config: testAccAwsLexSlotTypeUpdateConfig_description(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, LexSlotTypeVersionLatest),
					resource.TestCheckResourceAttr(rName, "description", "Types of flowers to pick up"),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
		},
	})
}

func TestAccAwsLexSlotType_enumerationValues(t *testing.T) {
	rName := "aws_lex_slot_type.test"
	testSlotTypeID := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsLexSlotTypeNotExists(testSlotTypeID, LexSlotTypeVersionLatest),
		Steps: []resource.TestStep{
			{
				Config: testAccAwsLexSlotTypeConfig_basic(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, LexSlotTypeVersionLatest),
					resource.TestCheckResourceAttr(rName, "enumeration_value.#", "1"),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
			{
				Config: testAccAwsLexSlotTypeConfig_enumerationValues(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, LexSlotTypeVersionLatest),
					resource.TestCheckResourceAttr(rName, "enumeration_value.#", "2"),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
		},
	})
}

func TestAccAwsLexSlotType_name(t *testing.T) {
	rName := "aws_lex_slot_type.test"
	testSlotTypeID1 := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)
	testSlotTypeID2 := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsLexSlotTypeNotExists(testSlotTypeID1, LexSlotTypeVersionLatest),
		Steps: []resource.TestStep{
			{
				Config: testAccAwsLexSlotTypeConfig_basic(testSlotTypeID1),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID1, LexSlotTypeVersionLatest),
					resource.TestCheckResourceAttr(rName, "name", testSlotTypeID1),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
			{
				Config: testAccAwsLexSlotTypeConfig_basic(testSlotTypeID2),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID2, LexSlotTypeVersionLatest),
					resource.TestCheckResourceAttr(rName, "name", testSlotTypeID2),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
		},
	})
}

func TestAccAwsLexSlotType_valueSelectionStrategy(t *testing.T) {
	rName := "aws_lex_slot_type.test"
	testSlotTypeID := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsLexSlotTypeNotExists(testSlotTypeID, LexSlotTypeVersionLatest),
		Steps: []resource.TestStep{
			{
				Config: testAccAwsLexSlotTypeConfig_basic(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, LexSlotTypeVersionLatest),
					resource.TestCheckResourceAttr(rName, "value_selection_strategy", lexmodelbuildingservice.SlotValueSelectionStrategyOriginalValue),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
			{
				Config: testAccAwsLexSlotTypeConfig_valueSelectionStrategy(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, LexSlotTypeVersionLatest),
					resource.TestCheckResourceAttr(rName, "value_selection_strategy", lexmodelbuildingservice.SlotValueSelectionStrategyTopResolution),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
		},
	})
}

func TestAccAwsLexSlotType_disappears(t *testing.T) {
	resourceName := "aws_lex_slot_type.test"
	rName := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsLexSlotTypeNotExists(rName, LexSlotTypeVersionLatest),
		Steps: []resource.TestStep{
			{
				Config: testAccAwsLexSlotTypeConfig_basic(rName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(rName, LexSlotTypeVersionLatest),
					testAccCheckResourceDisappears(testAccProvider, resourceAwsLexSlotType(), resourceName),
				),
				ExpectNonEmptyPlan: true,
			},
		},
	})
}

func testAccCheckAwsLexSlotTypeExists(slotTypeName, slotTypeVersion string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		conn := testAccProvider.Meta().(*AWSClient).lexmodelconn

		_, err := conn.GetSlotType(&lexmodelbuildingservice.GetSlotTypeInput{
			Name:    aws.String(slotTypeName),
			Version: aws.String(slotTypeVersion),
		})
		if isAWSErr(err, lexmodelbuildingservice.ErrCodeNotFoundException, "") {
			return fmt.Errorf("error slot type %s not found, %s", slotTypeName, err)
		}
		if err != nil {
			return fmt.Errorf("error getting slot type %s: %s", slotTypeName, err)
		}

		return nil
	}
}

func testAccCheckAwsLexSlotTypeNotExists(slotTypeName, slotTypeVersion string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		conn := testAccProvider.Meta().(*AWSClient).lexmodelconn

		_, err := conn.GetSlotType(&lexmodelbuildingservice.GetSlotTypeInput{
			Name:    aws.String(slotTypeName),
			Version: aws.String(slotTypeVersion),
		})
		if isAWSErr(err, lexmodelbuildingservice.ErrCodeNotFoundException, "") {
			return nil
		}
		if err != nil {
			return fmt.Errorf("error getting slot type %s: %s", slotTypeName, err)
		}

		return fmt.Errorf("error slot type exists %s", slotTypeName)
	}
}

func testAccAwsLexSlotTypeConfig_basic(rName string) string {
	return fmt.Sprintf(`
resource "aws_lex_slot_type" "test" {
  name = "%s"
  enumeration_value {
    synonyms = [
      "Lirium",
      "Martagon",
    ]
    value = "lilies"
  }
  create_version = true
}
`, rName)
}

func testAccAwsLexSlotTypeConfig_withoutVersion(rName string) string {
	return fmt.Sprintf(`
resource "aws_lex_slot_type" "test" {
  name = "%s"
  enumeration_value {
    synonyms = [
      "Lirium",
      "Martagon",
    ]
    value = "lilies"
  }
  create_version = false
}
`, rName)
}

func testAccAwsLexSlotTypeUpdateConfig_description(rName string) string {
	return fmt.Sprintf(`
resource "aws_lex_slot_type" "test" {
  description = "Types of flowers to pick up"
  name        = "%s"
  enumeration_value {
    synonyms = [
      "Lirium",
      "Martagon",
    ]
    value = "lilies"
  }
}
`, rName)
}

func testAccAwsLexSlotTypeConfig_enumerationValues(rName string) string {
	return fmt.Sprintf(`
resource "aws_lex_slot_type" "test" {
  enumeration_value {
    synonyms = [
      "Lirium",
      "Martagon",
    ]

    value = "lilies"
  }

  enumeration_value {
    synonyms = [
      "Eduardoregelia",
      "Podonix",
    ]

    value = "tulips"
  }

  name = "%s"
}
`, rName)
}

func testAccAwsLexSlotTypeConfig_valueSelectionStrategy(rName string) string {
	return fmt.Sprintf(`
resource "aws_lex_slot_type" "test" {
  name                     = "%s"
  value_selection_strategy = "TOP_RESOLUTION"
  enumeration_value {
    synonyms = [
      "Lirium",
      "Martagon",
    ]
    value = "lilies"
  }
}
`, rName)
}
<commit_msg>Update exists test function to set output<commit_after>package aws

import (
	"fmt"
	"testing"

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

func TestAccLexSlotType_basic(t *testing.T) {
	var v lexmodelbuildingservice.GetSlotTypeOutput
	rName := "aws_lex_slot_type.test"
	testSlotTypeID := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsLexSlotTypeNotExists(testSlotTypeID, LexSlotTypeVersionLatest),
		Steps: []resource.TestStep{
			{
				Config: testAccAwsLexSlotTypeConfig_basic(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, &v),
					resource.TestCheckResourceAttr(rName, "description", ""),
					resource.TestCheckResourceAttr(rName, "enumeration_value.#", "0"),
					resource.TestCheckResourceAttr(rName, "name", testSlotTypeID),
					resource.TestCheckResourceAttr(rName, "value_selection_strategy", lexmodelbuildingservice.SlotValueSelectionStrategyOriginalValue),
					resource.TestCheckResourceAttrSet(rName, "checksum"),
					resource.TestCheckResourceAttrSet(rName, "version"),
					testAccCheckResourceAttrRfc3339(rName, "created_date"),
					testAccCheckResourceAttrRfc3339(rName, "last_updated_date"),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
		},
	})
}

func TestAccAwsLexSlotType_createVersion(t *testing.T) {
	var v lexmodelbuildingservice.GetSlotTypeOutput
	rName := "aws_lex_slot_type.test"
	testSlotTypeID := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsLexSlotTypeNotExists(testSlotTypeID, LexSlotTypeVersionLatest),
		Steps: []resource.TestStep{
			{
				Config: testAccAwsLexSlotTypeConfig_withoutVersion(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, &v),
					testAccCheckAwsLexSlotTypeNotExists(testSlotTypeID, "1"),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
			{
				Config: testAccAwsLexSlotTypeConfig_basic(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, &v),
					testAccCheckAwsLexSlotTypeExistsWithVersion(testSlotTypeID, "1", &v),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
		},
	})
}

func TestAccAwsLexSlotType_description(t *testing.T) {
	var v lexmodelbuildingservice.GetSlotTypeOutput
	rName := "aws_lex_slot_type.test"
	testSlotTypeID := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsLexSlotTypeNotExists(testSlotTypeID, LexSlotTypeVersionLatest),
		Steps: []resource.TestStep{
			{
				Config: testAccAwsLexSlotTypeConfig_basic(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, &v),
					resource.TestCheckResourceAttr(rName, "description", ""),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
			{
				Config: testAccAwsLexSlotTypeUpdateConfig_description(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, &v),
					resource.TestCheckResourceAttr(rName, "description", "Types of flowers to pick up"),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
		},
	})
}

func TestAccAwsLexSlotType_enumerationValues(t *testing.T) {
	var v lexmodelbuildingservice.GetSlotTypeOutput
	rName := "aws_lex_slot_type.test"
	testSlotTypeID := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsLexSlotTypeNotExists(testSlotTypeID, LexSlotTypeVersionLatest),
		Steps: []resource.TestStep{
			{
				Config: testAccAwsLexSlotTypeConfig_basic(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, &v),
					resource.TestCheckResourceAttr(rName, "enumeration_value.#", "1"),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
			{
				Config: testAccAwsLexSlotTypeConfig_enumerationValues(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, &v),
					resource.TestCheckResourceAttr(rName, "enumeration_value.#", "2"),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
		},
	})
}

func TestAccAwsLexSlotType_name(t *testing.T) {
	var v lexmodelbuildingservice.GetSlotTypeOutput
	rName := "aws_lex_slot_type.test"
	testSlotTypeID1 := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)
	testSlotTypeID2 := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsLexSlotTypeNotExists(testSlotTypeID1, LexSlotTypeVersionLatest),
		Steps: []resource.TestStep{
			{
				Config: testAccAwsLexSlotTypeConfig_basic(testSlotTypeID1),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID1, &v),
					resource.TestCheckResourceAttr(rName, "name", testSlotTypeID1),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
			{
				Config: testAccAwsLexSlotTypeConfig_basic(testSlotTypeID2),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID2, &v),
					resource.TestCheckResourceAttr(rName, "name", testSlotTypeID2),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
		},
	})
}

func TestAccAwsLexSlotType_valueSelectionStrategy(t *testing.T) {
	var v lexmodelbuildingservice.GetSlotTypeOutput
	rName := "aws_lex_slot_type.test"
	testSlotTypeID := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsLexSlotTypeNotExists(testSlotTypeID, LexSlotTypeVersionLatest),
		Steps: []resource.TestStep{
			{
				Config: testAccAwsLexSlotTypeConfig_basic(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, &v),
					resource.TestCheckResourceAttr(rName, "value_selection_strategy", lexmodelbuildingservice.SlotValueSelectionStrategyOriginalValue),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
			{
				Config: testAccAwsLexSlotTypeConfig_valueSelectionStrategy(testSlotTypeID),
				Check: resource.ComposeAggregateTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(testSlotTypeID, &v),
					resource.TestCheckResourceAttr(rName, "value_selection_strategy", lexmodelbuildingservice.SlotValueSelectionStrategyTopResolution),
				),
			},
			{
				ResourceName:            rName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"create_version"},
			},
		},
	})
}

func TestAccAwsLexSlotType_disappears(t *testing.T) {
	var v lexmodelbuildingservice.GetSlotTypeOutput
	resourceName := "aws_lex_slot_type.test"
	rName := "test_slot_type_" + acctest.RandStringFromCharSet(8, acctest.CharSetAlpha)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsLexSlotTypeNotExists(rName, LexSlotTypeVersionLatest),
		Steps: []resource.TestStep{
			{
				Config: testAccAwsLexSlotTypeConfig_basic(rName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsLexSlotTypeExists(rName, &v),
					testAccCheckResourceDisappears(testAccProvider, resourceAwsLexSlotType(), resourceName),
				),
				ExpectNonEmptyPlan: true,
			},
		},
	})
}

func testAccCheckAwsLexSlotTypeExistsWithVersion(slotTypeName, slotTypeVersion string, output *lexmodelbuildingservice.GetSlotTypeOutput) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		var err error
		conn := testAccProvider.Meta().(*AWSClient).lexmodelconn

		output, err = conn.GetSlotType(&lexmodelbuildingservice.GetSlotTypeInput{
			Name:    aws.String(slotTypeName),
			Version: aws.String(slotTypeVersion),
		})
		if isAWSErr(err, lexmodelbuildingservice.ErrCodeNotFoundException, "") {
			return fmt.Errorf("error slot type %s not found, %s", slotTypeName, err)
		}
		if err != nil {
			return fmt.Errorf("error getting slot type %s: %s", slotTypeName, err)
		}

		return nil
	}
}

func testAccCheckAwsLexSlotTypeExists(slotTypeName string, output *lexmodelbuildingservice.GetSlotTypeOutput) resource.TestCheckFunc {
	return testAccCheckAwsLexSlotTypeExistsWithVersion(slotTypeName, LexSlotTypeVersionLatest, output)
}

func testAccCheckAwsLexSlotTypeNotExists(slotTypeName, slotTypeVersion string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		conn := testAccProvider.Meta().(*AWSClient).lexmodelconn

		_, err := conn.GetSlotType(&lexmodelbuildingservice.GetSlotTypeInput{
			Name:    aws.String(slotTypeName),
			Version: aws.String(slotTypeVersion),
		})
		if isAWSErr(err, lexmodelbuildingservice.ErrCodeNotFoundException, "") {
			return nil
		}
		if err != nil {
			return fmt.Errorf("error getting slot type %s: %s", slotTypeName, err)
		}

		return fmt.Errorf("error slot type exists %s", slotTypeName)
	}
}

func testAccAwsLexSlotTypeConfig_basic(rName string) string {
	return fmt.Sprintf(`
resource "aws_lex_slot_type" "test" {
  name = "%s"
  enumeration_value {
    synonyms = [
      "Lirium",
      "Martagon",
    ]
    value = "lilies"
  }
  create_version = true
}
`, rName)
}

func testAccAwsLexSlotTypeConfig_withoutVersion(rName string) string {
	return fmt.Sprintf(`
resource "aws_lex_slot_type" "test" {
  name = "%s"
  enumeration_value {
    synonyms = [
      "Lirium",
      "Martagon",
    ]
    value = "lilies"
  }
  create_version = false
}
`, rName)
}

func testAccAwsLexSlotTypeUpdateConfig_description(rName string) string {
	return fmt.Sprintf(`
resource "aws_lex_slot_type" "test" {
  description = "Types of flowers to pick up"
  name        = "%s"
  enumeration_value {
    synonyms = [
      "Lirium",
      "Martagon",
    ]
    value = "lilies"
  }
}
`, rName)
}

func testAccAwsLexSlotTypeConfig_enumerationValues(rName string) string {
	return fmt.Sprintf(`
resource "aws_lex_slot_type" "test" {
  enumeration_value {
    synonyms = [
      "Lirium",
      "Martagon",
    ]

    value = "lilies"
  }

  enumeration_value {
    synonyms = [
      "Eduardoregelia",
      "Podonix",
    ]

    value = "tulips"
  }

  name = "%s"
}
`, rName)
}

func testAccAwsLexSlotTypeConfig_valueSelectionStrategy(rName string) string {
	return fmt.Sprintf(`
resource "aws_lex_slot_type" "test" {
  name                     = "%s"
  value_selection_strategy = "TOP_RESOLUTION"
  enumeration_value {
    synonyms = [
      "Lirium",
      "Martagon",
    ]
    value = "lilies"
  }
}
`, rName)
}
<|endoftext|>


<commit_before>package server

import (
	"net/http"
	"strconv"

	"github.com/TeaMeow/KitSvc/model"
	"github.com/TeaMeow/KitSvc/module/event"
	"github.com/TeaMeow/KitSvc/module/mq"
	"github.com/TeaMeow/KitSvc/shared/auth"
	"github.com/TeaMeow/KitSvc/shared/token"
	"github.com/TeaMeow/KitSvc/store"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	"github.com/olahol/melody"
)

func Created(c *gin.Context) {
	var u model.User
	if err := c.Bind(&u); err != nil {
		c.AbortWithError(http.StatusBadRequest, err)
		return
	}
	//fmt.Println(u)
}

//
func CreateUser(c *gin.Context) {
	var u model.User

	if err := c.Bind(&u); err != nil {
		c.AbortWithError(http.StatusBadRequest, err)
		return
	}
	// Validate the data.
	if err := u.Validate(); err != nil {
		c.String(http.StatusBadRequest, err.Error())
		return
	}
	// Encrypt the user password.
	if err := auth.Encrypt(&u.Password); err != nil {
		c.AbortWithError(http.StatusInternalServerError, err)
		return
	}
	// Insert the user to the database.
	if err := store.CreateUser(c, &u); err != nil {
		c.AbortWithError(http.StatusInternalServerError, err)
		return
	}
	//
	//if err := mq.SendMail(c, &u); err != nil {
	//	c.AbortWithError(http.StatusInternalServerError, err)
	//	return
	//}
	go mq.SendMail(c, &u)

	go event.UserCreated(c, &u)

	// Show the user information.
	c.JSON(http.StatusOK, u)
}

//
func GetUser(c *gin.Context) {
	// Get the `username` from the url parameter.
	username := c.Param("username")

	// Get the user by the `username`` from the database.
	if u, err := store.GetUser(c, username); err != nil {
		c.String(http.StatusNotFound, "The user was not found.")
	} else {
		c.JSON(http.StatusOK, u)
	}
}

//
func DeleteUser(c *gin.Context) {
	// Get the user id from the url parameter.
	userID, _ := strconv.Atoi(c.Param("id"))
	// Delete the user in the database.
	if err := store.DeleteUser(c, userID); err != nil {
		if err == gorm.ErrRecordNotFound {
			c.String(http.StatusNotFound, "The user doesn't exist.")
		} else {
			c.AbortWithError(http.StatusInternalServerError, err)
		}
		return
	}

	c.String(http.StatusOK, "The user has been deleted successfully.")
}

//
func UpdateUser(c *gin.Context) {
	// Get the user id from the url parameter.
	userID, _ := strconv.Atoi(c.Param("id"))

	// Binding the user data.
	var u model.User
	if err := c.Bind(&u); err != nil {
		c.AbortWithError(http.StatusBadRequest, err)
		return
	}

	// We update the record based on the user id.
	u.ID = userID

	// Validate the data.
	if err := u.Validate(); err != nil {
		c.String(http.StatusBadRequest, err.Error())
		return
	}
	// Parse the json web token.
	if _, err := token.ParseRequest(c); err != nil {
		c.String(http.StatusForbidden, "The token was incorrect.")
		return
	}
	// Encrypt the user password.
	if err := auth.Encrypt(&u.Password); err != nil {
		c.AbortWithError(http.StatusInternalServerError, err)
		return
	}
	// Update the user in the database.
	if err := store.UpdateUser(c, &u); err != nil {
		if err == gorm.ErrRecordNotFound {
			c.String(http.StatusNotFound, "The user doesn't exist.")
		} else {
			c.AbortWithError(http.StatusInternalServerError, err)
		}
		return
	}

	c.JSON(http.StatusOK, u)
}

//
func Login(c *gin.Context) {
	// Binding the data with the user struct.
	var u model.User
	if err := c.Bind(&u); err != nil {
		c.AbortWithError(http.StatusBadRequest, err)
		return
	}
	// Get the user information by the login username.
	d, err := store.GetUser(c, u.Username)
	if err != nil {
		c.String(http.StatusNotFound, "The user doesn't exist.")
		return
	}
	// Compare the login password with the user password.
	if err := auth.Compare(d.Password, u.Password); err != nil {
		c.String(http.StatusForbidden, "The password was incorrect.")
		return
	}
	// Sign the json web token.
	t, err := token.Sign(c, token.Content{ID: d.ID, Username: d.Username}, "")
	if err != nil {
		c.AbortWithError(http.StatusBadRequest, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{"token": t})
}

func WebSocket(c *gin.Context) {
	w, _ := c.Get("websocket")
	ws := w.(melody.Melody)

	ws.Broadcast([]byte("Wow"))
}

func SendMail(c *gin.Context) {

}
<commit_msg>Use u.Encrypt instead of auth.Encrypt<commit_after>package server

import (
	"net/http"
	"strconv"

	"github.com/TeaMeow/KitSvc/model"
	"github.com/TeaMeow/KitSvc/module/event"
	"github.com/TeaMeow/KitSvc/module/mq"
	"github.com/TeaMeow/KitSvc/shared/auth"
	"github.com/TeaMeow/KitSvc/shared/token"
	"github.com/TeaMeow/KitSvc/store"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	"github.com/olahol/melody"
)

func Created(c *gin.Context) {
	var u model.User
	if err := c.Bind(&u); err != nil {
		c.AbortWithError(http.StatusBadRequest, err)
		return
	}
	//fmt.Println(u)
}

//
func CreateUser(c *gin.Context) {
	var u model.User

	if err := c.Bind(&u); err != nil {
		c.AbortWithError(http.StatusBadRequest, err)
		return
	}
	// Validate the data.
	if err := u.Validate(); err != nil {
		c.String(http.StatusBadRequest, err.Error())
		return
	}
	// Encrypt the user password.
	if err := u.Encrypt(); err != nil {
		c.AbortWithError(http.StatusInternalServerError, err)
		return
	}

	// Insert the user to the database.
	if err := store.CreateUser(c, &u); err != nil {
		c.AbortWithError(http.StatusInternalServerError, err)
		return
	}
	//
	go mq.SendMail(c, &u)

	go event.UserCreated(c, &u)

	// Show the user information.
	c.JSON(http.StatusOK, u)
}

//
func GetUser(c *gin.Context) {
	// Get the `username` from the url parameter.
	username := c.Param("username")

	// Get the user by the `username`` from the database.
	if u, err := store.GetUser(c, username); err != nil {
		c.String(http.StatusNotFound, "The user was not found.")
	} else {
		c.JSON(http.StatusOK, u)
	}
}

//
func DeleteUser(c *gin.Context) {
	// Get the user id from the url parameter.
	userID, _ := strconv.Atoi(c.Param("id"))
	// Delete the user in the database.
	if err := store.DeleteUser(c, userID); err != nil {
		if err == gorm.ErrRecordNotFound {
			c.String(http.StatusNotFound, "The user doesn't exist.")
		} else {
			c.AbortWithError(http.StatusInternalServerError, err)
		}
		return
	}

	c.String(http.StatusOK, "The user has been deleted successfully.")
}

//
func UpdateUser(c *gin.Context) {
	// Get the user id from the url parameter.
	userID, _ := strconv.Atoi(c.Param("id"))

	// Binding the user data.
	var u model.User
	if err := c.Bind(&u); err != nil {
		c.AbortWithError(http.StatusBadRequest, err)
		return
	}

	// We update the record based on the user id.
	u.ID = userID

	// Validate the data.
	if err := u.Validate(); err != nil {
		c.String(http.StatusBadRequest, err.Error())
		return
	}
	// Parse the json web token.
	if _, err := token.ParseRequest(c); err != nil {
		c.String(http.StatusForbidden, "The token was incorrect.")
		return
	}
	// Encrypt the user password.
	if err := u.Encrypt(); err != nil {
		c.AbortWithError(http.StatusInternalServerError, err)
		return
	}
	// Update the user in the database.
	if err := store.UpdateUser(c, &u); err != nil {
		if err == gorm.ErrRecordNotFound {
			c.String(http.StatusNotFound, "The user doesn't exist.")
		} else {
			c.AbortWithError(http.StatusInternalServerError, err)
		}
		return
	}

	c.JSON(http.StatusOK, u)
}

//
func Login(c *gin.Context) {
	// Binding the data with the user struct.
	var u model.User
	if err := c.Bind(&u); err != nil {
		c.AbortWithError(http.StatusBadRequest, err)
		return
	}
	// Get the user information by the login username.
	d, err := store.GetUser(c, u.Username)
	if err != nil {
		c.String(http.StatusNotFound, "The user doesn't exist.")
		return
	}
	// Compare the login password with the user password.
	if err := auth.Compare(d.Password, u.Password); err != nil {
		c.String(http.StatusForbidden, "The password was incorrect.")
		return
	}
	// Sign the json web token.
	t, err := token.Sign(c, token.Content{ID: d.ID, Username: d.Username}, "")
	if err != nil {
		c.AbortWithError(http.StatusBadRequest, err)
		return
	}

	c.JSON(http.StatusOK, model.Token{Token: t})
}

func WebSocket(c *gin.Context) {
	w, _ := c.Get("websocket")
	ws := w.(melody.Melody)

	ws.Broadcast([]byte("Wow"))
}

func SendMail(c *gin.Context) {

}
<|endoftext|>


<commit_before>package gomake

import (
	"container/list"
	"fmt"
	"sync"
)

// Rule is a node in a dependency graph.
type Rule struct {
	// Target is the identifier for the rule in the results from Evaluate.
	Target string
	// Description is an optional field describing the rule.
	Description string
	// Dependencies is a list of rules that must be evaluated before this.
	Dependencies []*Rule
	// Evaluate is the arbitrary function to evaluate the rule.
	Evaluate func() error
}

// NewRule initializes a new named Rule with its direct dependencies and
// evaluate function.
func NewRule(target, description string, dependencies []*Rule, evaluate func() error) *Rule {
	return &Rule{
		Target:       target,
		Description:  description,
		Dependencies: dependencies,
		Evaluate:     evaluate,
	}
}

// Evaluate traverses root rule's dependency graph and creates goroutines for
// all rules it visit. Each goroutine will wait for its dependencies to be
// evaluated before evaluating itself, but if any dependency evaluates with an
// error, it will exit early.
func Evaluate(root *Rule) map[string]error {
	var (
		wg sync.WaitGroup // Waits for all goroutines in rule's dependency graph
		mu sync.Mutex     // Protects errs map
	)

	errs := make(map[*Rule]chan error)

	// Protect errs map until all goroutines are started
	mu.Lock()

	queue := list.New()
	queue.PushBack(root)
	for elem := queue.Front(); elem != nil; elem = elem.Next() {

		rule := elem.Value.(*Rule)

		// Skip if visited already
		_, ok := errs[rule]
		if ok {
			continue
		}

		// Mark as visited and create result channel
		errs[rule] = make(chan error, 1)

		// Add dependencies to rules to visit
		for _, dependency := range rule.Dependencies {
			queue.PushBack(dependency)
		}

		wg.Add(1)
		go func(rule *Rule) {
			defer wg.Done()

			mu.Lock()
			ruleCh := errs[rule]
			mu.Unlock()

			// Wait for dependencies to be evaluated
			for _, dependency := range rule.Dependencies {
				mu.Lock()
				dependencyCh := errs[dependency]
				mu.Unlock()

				err := <-dependencyCh
				dependencyCh <- err

				// If any dependency returns err, exit early
				if err != nil {
					ruleCh <- nil
					return
				}
			}

			err := rule.Evaluate()
			ruleCh <- err
		}(rule)
	}

	// Unlock so that rules can start evaluating
	mu.Unlock()
	wg.Wait()

	// Build results map
	results := make(map[string]error)
	for rule, err := range errs {
		results[rule.Target] = <-err
	}

	return results
}

// HandleResults displays all the target errs and returns a combined error.
func HandleResults(results map[string]error) error {
	var errs []error
	for target, err := range results {
		if err != nil {
			fmt.Printf("%s: %s", target, err)
			errs = append(errs, err)
		}
	}

	if len(errs) > 0 {
		return fmt.Errorf("%s", errs)
	}

	return nil
}
<commit_msg>Update comments<commit_after>package gomake

import (
	"container/list"
	"fmt"
	"sync"
)

// Rule is a node in a dependency graph.
type Rule struct {
	// Target is the identifier for the rule in the results from Evaluate.
	Target string
	// Description is an optional field describing the rule.
	Description string
	// Dependencies is a list of rules that must be evaluated before this.
	Dependencies []*Rule
	// Evaluate is the arbitrary function to evaluate the rule.
	Evaluate func() error
}

// NewRule initializes a new named Rule with its direct dependencies and
// evaluate function.
func NewRule(target, description string, dependencies []*Rule, evaluate func() error) *Rule {
	return &Rule{
		Target:       target,
		Description:  description,
		Dependencies: dependencies,
		Evaluate:     evaluate,
	}
}

// Evaluate traverses root rule's dependency graph and creates goroutines for
// all rules it visit. Each goroutine will wait for its dependencies to be
// evaluated before evaluating itself, but if any dependency evaluates with an
// error, it will exit early.
func Evaluate(root *Rule) map[string]error {
	var (
		// Waits for all goroutines in rule's dependency graph to finish evaluating
		wg sync.WaitGroup
		// Protects errs map
		mu sync.Mutex
	)

	errs := make(map[*Rule]chan error)

	// Stall rule evaluation until all rules have been visited
	mu.Lock()

	queue := list.New()
	queue.PushBack(root)
	for elem := queue.Front(); elem != nil; elem = elem.Next() {

		rule := elem.Value.(*Rule)

		// Skip if visited already
		_, ok := errs[rule]
		if ok {
			continue
		}

		// Mark as visited and create result channel
		errs[rule] = make(chan error, 1)

		// Add dependencies to rules to visit
		for _, dependency := range rule.Dependencies {
			queue.PushBack(dependency)
		}

		wg.Add(1)
		go func(rule *Rule) {
			defer wg.Done()

			mu.Lock()
			ruleCh := errs[rule]
			mu.Unlock()

			// Wait for dependencies to be evaluated
			for _, dependency := range rule.Dependencies {
				mu.Lock()
				dependencyCh := errs[dependency]
				mu.Unlock()

				err := <-dependencyCh
				dependencyCh <- err

				// If any dependency returns err, exit early
				if err != nil {
					ruleCh <- nil
					return
				}
			}

			err := rule.Evaluate()
			ruleCh <- err
		}(rule)
	}

	// Rules can begin evaluating
	mu.Unlock()
	wg.Wait()

	// Build results map
	results := make(map[string]error)
	for rule, err := range errs {
		results[rule.Target] = <-err
	}

	return results
}

// HandleResults displays all the target errs and returns a combined error.
func HandleResults(results map[string]error) error {
	var errs []error
	for target, err := range results {
		if err != nil {
			fmt.Printf("%s: %s", target, err)
			errs = append(errs, err)
		}
	}

	if len(errs) > 0 {
		return fmt.Errorf("%s", errs)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"testing"
	"time"
)

const (
	ANY_DB_DRIVER     = ""
	MULTI_DOMAIN_MODE = ""
	TEST_DEPLOYED_ON  = "localhost:9999"
	TEST_DB           = "goslow_test"
)

var DATA_SOURCE = map[string]string{
	ANY_DB_DRIVER: "", // value doesn't matter
	"sqlite3":     DEFAULT_CONFIG.dataSource,
	"postgres":    "postgres://localhost/" + TEST_DB,
}

type TestCase struct {
	driver                 string
	dataSource             string
	createDefaultEndpoints bool
	adminPathPrefix        string
}

type TestCases []*TestCase

// TODO: do we need *TestCase argument in ServerTest?
type ServerTest func(*testing.T, *httptest.Server, *TestCase)

var (
	multiDomainTestCases = TestCases{
		NewTestCase(ANY_DB_DRIVER, MULTI_DOMAIN_MODE),
	}

	endpointCreationTestCases = TestCases{
		NewTestCase(ANY_DB_DRIVER, MULTI_DOMAIN_MODE),
		NewTestCase(ANY_DB_DRIVER, "/goslow"),
		NewTestCase(ANY_DB_DRIVER, "/goslow/"),
		NewTestCase(ANY_DB_DRIVER, "/te"),
		NewTestCase(ANY_DB_DRIVER, "/te/"),
		NewTestCase(ANY_DB_DRIVER, "/composite/path"),
	}
)

func NewTestCase(driver string, adminPathPrefix string) *TestCase {
	dataSource, knownDriver := DATA_SOURCE[driver]
	if !knownDriver {
		log.Fatalf("unknown driver: <%s>", driver)
	}
	createDefaultEndpoints := (adminPathPrefix == MULTI_DOMAIN_MODE)
	return &TestCase{
		driver:                 driver,
		dataSource:             dataSource,
		createDefaultEndpoints: createDefaultEndpoints,
		adminPathPrefix:        adminPathPrefix,
	}
}

func TestZeroSite(t *testing.T) {
	runAll(t, zeroSiteServerTest, multiDomainTestCases)
}

func runAll(t *testing.T, serverTest ServerTest, testCases TestCases) {
	for _, testCase := range runnable(expandToConcreteDriver(testCases)) {
		run(t, serverTest, testCase)
	}
}

func runnable(testCases TestCases) TestCases {
	runnableTestCases := make(TestCases, 0)
	for _, testCase := range testCases {
		if testCase.runnable() {
			runnableTestCases = append(runnableTestCases, testCase)
		}
	}
	return runnableTestCases
}

func expandToConcreteDriver(testCases TestCases) TestCases {
	concreteTestCases := make(TestCases, 0)
	for _, testCase := range testCases {
		if testCase.driver == ANY_DB_DRIVER {
			concreteTestCases = append(concreteTestCases, NewTestCase("sqlite3", testCase.adminPathPrefix))
			concreteTestCases = append(concreteTestCases, NewTestCase("postgres", testCase.adminPathPrefix))
		} else {
			concreteTestCases = append(concreteTestCases, testCase)
		}
	}
	return concreteTestCases
}

func (testCase *TestCase) runnable() bool {
	return !testCase.skippable()
}

func (testCase *TestCase) skippable() bool {
	return testCase.driver == "postgres" && testing.Short()
}

func run(t *testing.T, serverTest ServerTest, testCase *TestCase) {
	if testCase.driver == "postgres" {
		createDb(TEST_DB)
		defer dropDb(TEST_DB)
	}
	goSlowServer := newGoSlowServer(testCase)
	server := httptest.NewServer(goSlowServer)
	defer server.Close()
	defer goSlowServer.storage.db.Close() // so we can drop database
	serverTest(t, server, testCase)
}

func zeroSiteServerTest(t *testing.T, server *httptest.Server, testCase *TestCase) {
	shouldRespondWith(t, DEFAULT_RESPONSE,
		createGET(server.URL, "/", makeFullDomain("0")))
}

func shouldRespondWith(t *testing.T, expectedResponse []byte, request *http.Request) {
	response := do(request)
	bytesShouldBeEqual(t, expectedResponse, read(response))
}

func TestTooLargeDelay(t *testing.T) {
	runAll(t, tooLargeDelayServerTest, multiDomainTestCases)
}

func tooLargeDelayServerTest(t *testing.T, server *httptest.Server, testCase *TestCase) {
	dontAllowToCreateEndpointWithDelay(t, server, time.Duration(1000)*time.Second)
}

func dontAllowToCreateEndpointWithDelay(t *testing.T, server *httptest.Server, delay time.Duration) {
	withNewDomain(server, func(domain string) {
		resp := createEndpoint(server, &Endpoint{Site: getSite(domain), Path: "/", Delay: delay})

		shouldHaveStatusCode(t, http.StatusBadRequest, resp)
		shouldHaveStatusCode(t, http.StatusNotFound, GET(server.URL, "/", domain))
	})
}

type DomainTest func(domain string)

func withNewDomain(server *httptest.Server, domainTest DomainTest) {
	domain := createDomain(server, &Endpoint{Path: "/path-is-irrelevant"})
	domainTest(domain)
}

func TestChangeBuiltinSites(t *testing.T) {
	runAll(t, changeBuiltinSitesServerTest, multiDomainTestCases)
}

func changeBuiltinSitesServerTest(t *testing.T, server *httptest.Server, testCase *TestCase) {
	dontAllowToChangeSite(t, server, "0", http.StatusForbidden)
	dontAllowToChangeSite(t, server, "599", http.StatusForbidden)
	dontAllowToChangeSite(t, server, "create", http.StatusForbidden)
}

func dontAllowToChangeSite(t *testing.T, server *httptest.Server, site string, expectedStatusCode int) {
	resp := createEndpoint(server, &Endpoint{Site: site, Path: "/test", Response: []byte("hop"), Method: "GET"})
	shouldHaveStatusCode(t, expectedStatusCode, resp)
}

func TestChangeUnknownSites(t *testing.T) {
	runAll(t, changeUnknownSitesServerTest, multiDomainTestCases)
}

func changeUnknownSitesServerTest(t *testing.T, server *httptest.Server, testCase *TestCase) {
	dontAllowToChangeSite(t, server, "", http.StatusNotFound)
	dontAllowToChangeSite(t, server, "uknown-site", http.StatusNotFound)
	dontAllowToChangeSite(t, server, "admin-500", http.StatusNotFound)
	dontAllowToChangeSite(t, server, "admin-create", http.StatusNotFound)
}

func TestDelay(t *testing.T) {
	runAll(t, checkDelay, multiDomainTestCases)
}

func checkDelay(t *testing.T, server *httptest.Server, testCase *TestCase) {
	shouldRespondIn(t,
		createGET(server.URL, "/", makeFullDomain("0")),
		0, 0.1) // seconds
	shouldRespondIn(t,
		createGET(server.URL, "/", makeFullDomain("1")),
		1, 1.1) // seconds
}

func TestStatus(t *testing.T) {
	runAll(t, checkStatus, multiDomainTestCases)
}

func checkStatus(t *testing.T, server *httptest.Server, testCase *TestCase) {
	for _, statusCode := range []int{200, 404, 500} {
		resp := GET(server.URL, "/", makeFullDomain(strconv.Itoa(statusCode)))
		shouldHaveStatusCode(t, statusCode, resp)
	}
}

func TestEndpointCreation(t *testing.T) {
	runAll(t, checkEndpointCreationTestCase, endpointCreationTestCases)
}

func checkEndpointCreationTestCase(t *testing.T, server *httptest.Server, testCase *TestCase) {
	prefix := testCase.adminPathPrefix
	isInSingleSiteMode := prefix != ""
	domain, site := TEST_DEPLOYED_ON, ""
	root_response := []byte("haha")
	test_response := []byte("hop")
	test_post_response := []byte("for POST")
	empty_payload := []byte("")

	if isInSingleSiteMode {
		resp := createEndpoint(server, &Endpoint{Path: join(prefix, "/"), Response: root_response})
		shouldHaveStatusCode(t, http.StatusOK, resp)
	} else {
		domain = createDomain(server, &Endpoint{Path: join(prefix, "/"), Response: root_response})
		site = getSite(domain)
	}

	bytesShouldBeEqual(t, read(GET(server.URL, "/", domain)), root_response)

	// testing GET endpoint
	resp := createEndpoint(server, &Endpoint{Site: site, Path: join(prefix, "/test"), Response: test_response, Method: "GET"})
	shouldHaveStatusCode(t, http.StatusOK, resp)
	// checking that GET /test endpoint works
	bytesShouldBeEqual(t, read(GET(server.URL, "/test", domain)), test_response)
	// checking that GET /test doesn't affect POST
	resp = POST(server.URL, "/test", domain, []byte(""))
	intShouldBeEqual(t, 404, resp.StatusCode)

	// testing POST endpoint
	resp = createEndpoint(server, &Endpoint{Site: site, Path: join(prefix, "/test"), Response: test_post_response, Method: "POST",
		Delay: time.Duration(100) * time.Millisecond})
	shouldHaveStatusCode(t, http.StatusOK, resp)
	// checking that POST endpoint doesn't affect GET
	bytesShouldBeEqual(t, read(GET(server.URL, "/test", domain)), test_response)
	// checking that POST /test endpoint works
	bytesShouldBeEqual(t, read(POST(server.URL, "/test", domain, empty_payload)), test_post_response)
	shouldRespondIn(t, createPOST(server.URL, "/test", domain, empty_payload), 0.1, 0.15)
}

func newGoSlowServer(testCase *TestCase) *Server {
	config := DEFAULT_CONFIG // copies DEFAULT_CONFIG
	config.deployedOn = TEST_DEPLOYED_ON
	config.createDefaultEndpoints = testCase.createDefaultEndpoints
	config.adminPathPrefix = testCase.adminPathPrefix
	config.driver = testCase.driver
	config.dataSource = testCase.dataSource
	return NewServer(&config)
}

func GET(url, path, host string) *http.Response {
	req := createGET(url, path, host)
	return do(req)
}

func do(req *http.Request) *http.Response {
	resp, err := new(http.Client).Do(req)
	if err != nil {
		log.Fatal(err)
	}
	return resp
}

func createGET(url, path, host string) *http.Request {
	return createRequest("GET", url, path, host, nil)
}

func createRequest(method, url, path, host string, body io.Reader) *http.Request {
	req, err := http.NewRequest(method, url+path, body)
	if err != nil {
		log.Fatal(err)
	}
	req.Host = host
	return req
}

func read(resp *http.Response) []byte {
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	return body
}

func makeFullDomain(site string) string {
	return fmt.Sprintf("%s.%s", site, TEST_DEPLOYED_ON)
}

func bytesShouldBeEqual(t *testing.T, expected, actual []byte) {
	if !bytes.Equal(expected, actual) {
		t.Fatalf("<<%v>> != <<%v>>", string(expected), string(actual))
	}
}

func intShouldBeEqual(t *testing.T, expected, actual int) {
	if expected != actual {
		t.Fatalf("<<%v>> != <<%v>>", expected, actual)
	}
}

func shouldRespondIn(t *testing.T, req *http.Request, minSeconds, maxSeconds float64) {
	start := time.Now()
	resp := do(req)
	read(resp)
	duration := time.Since(start)
	minDuration := toDuration(minSeconds)
	maxDuration := toDuration(maxSeconds)
	if duration < minDuration || duration > maxDuration {
		t.Fatalf("%s%s answered in %v. Not in the interval [%v; %v]",
			req.Host, req.URL.Path, duration, minDuration, maxDuration)
	}
}

func shouldHaveStatusCode(t *testing.T, statusCode int, resp *http.Response) {
	intShouldBeEqual(t, statusCode, resp.StatusCode)
}

func toDuration(seconds float64) time.Duration {
	return time.Duration(seconds*1000) * time.Millisecond
}

func createDomain(server *httptest.Server, endpoint *Endpoint) string {
	resp := POST(server.URL, fmt.Sprintf("%s?output=short&method=GET", endpoint.Path),
		makeFullDomain("create"), endpoint.Response)
	return string(read(resp))
}

func POST(url, path, host string, payload []byte) *http.Response {
	req := createPOST(url, path, host, payload)
	return do(req)
}

func createPOST(url, path, host string, payload []byte) *http.Request {
	return createRequest("POST", url, path, host, bytes.NewReader(payload))
}

func getSite(domain string) string {
	return strings.Split(domain, ".")[0]
}

func createEndpoint(server *httptest.Server, endpoint *Endpoint) *http.Response {
	req := createPOST(server.URL, endpoint.Path, makeFullDomain("admin-"+endpoint.Site),
		endpoint.Response)
	req.URL.RawQuery = getQueryString(endpoint)
	return do(req)
}

func getQueryString(endpoint *Endpoint) string {
	params := url.Values{}
	params.Set("method", endpoint.Method)
	params.Set("delay", fmt.Sprintf("%f", endpoint.Delay.Seconds()))
	return params.Encode()
}

// Wrapper around path.Join. Preserves trailing slash.
func join(elem ...string) string {
	lastElem := elem[len(elem)-1]
	shouldEndWithSlash := strings.HasSuffix(lastElem, "/")
	joined := path.Join(elem...)
	if shouldEndWithSlash && !strings.HasSuffix(joined, "/") {
		joined += "/"
	}
	return joined
}

func createDb(name string) {
	cmd := exec.Command("createdb", name)
	err := cmd.Run()
	if err != nil {
		log.Fatalf("createdb error: %s", err)
	}
}

func dropDb(name string) {
	cmd := exec.Command("dropdb", name)
	err := cmd.Run()
	if err != nil {
		log.Fatalf("dropdb error: %s", err)
	}
}
<commit_msg>Change argument order in shouldRespondInTimeInterval<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"testing"
	"time"
)

const (
	ANY_DB_DRIVER     = ""
	MULTI_DOMAIN_MODE = ""
	TEST_DEPLOYED_ON  = "localhost:9999"
	TEST_DB           = "goslow_test"
)

var DATA_SOURCE = map[string]string{
	ANY_DB_DRIVER: "", // value doesn't matter
	"sqlite3":     DEFAULT_CONFIG.dataSource,
	"postgres":    "postgres://localhost/" + TEST_DB,
}

type TestCase struct {
	driver                 string
	dataSource             string
	createDefaultEndpoints bool
	adminPathPrefix        string
}

type TestCases []*TestCase

// TODO: do we need *TestCase argument in ServerTest?
type ServerTest func(*testing.T, *httptest.Server, *TestCase)

var (
	multiDomainTestCases = TestCases{
		NewTestCase(ANY_DB_DRIVER, MULTI_DOMAIN_MODE),
	}

	endpointCreationTestCases = TestCases{
		NewTestCase(ANY_DB_DRIVER, MULTI_DOMAIN_MODE),
		NewTestCase(ANY_DB_DRIVER, "/goslow"),
		NewTestCase(ANY_DB_DRIVER, "/goslow/"),
		NewTestCase(ANY_DB_DRIVER, "/te"),
		NewTestCase(ANY_DB_DRIVER, "/te/"),
		NewTestCase(ANY_DB_DRIVER, "/composite/path"),
	}
)

func NewTestCase(driver string, adminPathPrefix string) *TestCase {
	dataSource, knownDriver := DATA_SOURCE[driver]
	if !knownDriver {
		log.Fatalf("unknown driver: <%s>", driver)
	}
	createDefaultEndpoints := (adminPathPrefix == MULTI_DOMAIN_MODE)
	return &TestCase{
		driver:                 driver,
		dataSource:             dataSource,
		createDefaultEndpoints: createDefaultEndpoints,
		adminPathPrefix:        adminPathPrefix,
	}
}

func TestZeroSite(t *testing.T) {
	runAll(t, zeroSiteServerTest, multiDomainTestCases)
}

func runAll(t *testing.T, serverTest ServerTest, testCases TestCases) {
	for _, testCase := range runnable(expandToConcreteDriver(testCases)) {
		run(t, serverTest, testCase)
	}
}

func runnable(testCases TestCases) TestCases {
	runnableTestCases := make(TestCases, 0)
	for _, testCase := range testCases {
		if testCase.runnable() {
			runnableTestCases = append(runnableTestCases, testCase)
		}
	}
	return runnableTestCases
}

func expandToConcreteDriver(testCases TestCases) TestCases {
	concreteTestCases := make(TestCases, 0)
	for _, testCase := range testCases {
		if testCase.driver == ANY_DB_DRIVER {
			concreteTestCases = append(concreteTestCases, NewTestCase("sqlite3", testCase.adminPathPrefix))
			concreteTestCases = append(concreteTestCases, NewTestCase("postgres", testCase.adminPathPrefix))
		} else {
			concreteTestCases = append(concreteTestCases, testCase)
		}
	}
	return concreteTestCases
}

func (testCase *TestCase) runnable() bool {
	return !testCase.skippable()
}

func (testCase *TestCase) skippable() bool {
	return testCase.driver == "postgres" && testing.Short()
}

func run(t *testing.T, serverTest ServerTest, testCase *TestCase) {
	if testCase.driver == "postgres" {
		createDb(TEST_DB)
		defer dropDb(TEST_DB)
	}
	goSlowServer := newGoSlowServer(testCase)
	server := httptest.NewServer(goSlowServer)
	defer server.Close()
	defer goSlowServer.storage.db.Close() // so we can drop database
	serverTest(t, server, testCase)
}

func zeroSiteServerTest(t *testing.T, server *httptest.Server, testCase *TestCase) {
	shouldRespondWith(t, DEFAULT_RESPONSE,
		createGET(server.URL, "/", makeFullDomain("0")))
}

func shouldRespondWith(t *testing.T, expectedResponse []byte, request *http.Request) {
	response := do(request)
	bytesShouldBeEqual(t, expectedResponse, read(response))
}

func TestTooLargeDelay(t *testing.T) {
	runAll(t, tooLargeDelayServerTest, multiDomainTestCases)
}

func tooLargeDelayServerTest(t *testing.T, server *httptest.Server, testCase *TestCase) {
	dontAllowToCreateEndpointWithDelay(t, server, time.Duration(1000)*time.Second)
}

func dontAllowToCreateEndpointWithDelay(t *testing.T, server *httptest.Server, delay time.Duration) {
	withNewDomain(server, func(domain string) {
		resp := createEndpoint(server, &Endpoint{Site: getSite(domain), Path: "/", Delay: delay})

		shouldHaveStatusCode(t, http.StatusBadRequest, resp)
		shouldHaveStatusCode(t, http.StatusNotFound, GET(server.URL, "/", domain))
	})
}

type DomainTest func(domain string)

func withNewDomain(server *httptest.Server, domainTest DomainTest) {
	domain := createDomain(server, &Endpoint{Path: "/path-is-irrelevant"})
	domainTest(domain)
}

func TestChangeBuiltinSites(t *testing.T) {
	runAll(t, changeBuiltinSitesServerTest, multiDomainTestCases)
}

func changeBuiltinSitesServerTest(t *testing.T, server *httptest.Server, testCase *TestCase) {
	dontAllowToChangeSite(t, server, "0", http.StatusForbidden)
	dontAllowToChangeSite(t, server, "599", http.StatusForbidden)
	dontAllowToChangeSite(t, server, "create", http.StatusForbidden)
}

func dontAllowToChangeSite(t *testing.T, server *httptest.Server, site string, expectedStatusCode int) {
	resp := createEndpoint(server, &Endpoint{Site: site, Path: "/test", Response: []byte("hop"), Method: "GET"})
	shouldHaveStatusCode(t, expectedStatusCode, resp)
}

func TestChangeUnknownSites(t *testing.T) {
	runAll(t, changeUnknownSitesServerTest, multiDomainTestCases)
}

func changeUnknownSitesServerTest(t *testing.T, server *httptest.Server, testCase *TestCase) {
	dontAllowToChangeSite(t, server, "", http.StatusNotFound)
	dontAllowToChangeSite(t, server, "uknown-site", http.StatusNotFound)
	dontAllowToChangeSite(t, server, "admin-500", http.StatusNotFound)
	dontAllowToChangeSite(t, server, "admin-create", http.StatusNotFound)
}

func TestDelay(t *testing.T) {
	runAll(t, delayServerTest, multiDomainTestCases)
}

func delayServerTest(t *testing.T, server *httptest.Server, testCase *TestCase) {
	shouldRespondInTimeInterval(t, 0, 0.1, // seconds
		createGET(server.URL, "/", makeFullDomain("0")),
	)

	shouldRespondInTimeInterval(t, 1, 1.1, // seconds
		createGET(server.URL, "/", makeFullDomain("1")),
	)
}

func TestStatus(t *testing.T) {
	runAll(t, checkStatus, multiDomainTestCases)
}

func checkStatus(t *testing.T, server *httptest.Server, testCase *TestCase) {
	for _, statusCode := range []int{200, 404, 500} {
		resp := GET(server.URL, "/", makeFullDomain(strconv.Itoa(statusCode)))
		shouldHaveStatusCode(t, statusCode, resp)
	}
}

func TestEndpointCreation(t *testing.T) {
	runAll(t, checkEndpointCreationTestCase, endpointCreationTestCases)
}

func checkEndpointCreationTestCase(t *testing.T, server *httptest.Server, testCase *TestCase) {
	prefix := testCase.adminPathPrefix
	isInSingleSiteMode := prefix != ""
	domain, site := TEST_DEPLOYED_ON, ""
	root_response := []byte("haha")
	test_response := []byte("hop")
	test_post_response := []byte("for POST")
	empty_payload := []byte("")

	if isInSingleSiteMode {
		resp := createEndpoint(server, &Endpoint{Path: join(prefix, "/"), Response: root_response})
		shouldHaveStatusCode(t, http.StatusOK, resp)
	} else {
		domain = createDomain(server, &Endpoint{Path: join(prefix, "/"), Response: root_response})
		site = getSite(domain)
	}

	bytesShouldBeEqual(t, read(GET(server.URL, "/", domain)), root_response)

	// testing GET endpoint
	resp := createEndpoint(server, &Endpoint{Site: site, Path: join(prefix, "/test"), Response: test_response, Method: "GET"})
	shouldHaveStatusCode(t, http.StatusOK, resp)
	// checking that GET /test endpoint works
	bytesShouldBeEqual(t, read(GET(server.URL, "/test", domain)), test_response)
	// checking that GET /test doesn't affect POST
	resp = POST(server.URL, "/test", domain, []byte(""))
	intShouldBeEqual(t, 404, resp.StatusCode)

	// testing POST endpoint
	resp = createEndpoint(server, &Endpoint{Site: site, Path: join(prefix, "/test"), Response: test_post_response, Method: "POST",
		Delay: time.Duration(100) * time.Millisecond})
	shouldHaveStatusCode(t, http.StatusOK, resp)
	// checking that POST endpoint doesn't affect GET
	bytesShouldBeEqual(t, read(GET(server.URL, "/test", domain)), test_response)
	// checking that POST /test endpoint works
	bytesShouldBeEqual(t, read(POST(server.URL, "/test", domain, empty_payload)), test_post_response)
	shouldRespondInTimeInterval(t, 0.1, 0.15, createPOST(server.URL, "/test", domain, empty_payload))
}

func newGoSlowServer(testCase *TestCase) *Server {
	config := DEFAULT_CONFIG // copies DEFAULT_CONFIG
	config.deployedOn = TEST_DEPLOYED_ON
	config.createDefaultEndpoints = testCase.createDefaultEndpoints
	config.adminPathPrefix = testCase.adminPathPrefix
	config.driver = testCase.driver
	config.dataSource = testCase.dataSource
	return NewServer(&config)
}

func GET(url, path, host string) *http.Response {
	req := createGET(url, path, host)
	return do(req)
}

func do(req *http.Request) *http.Response {
	resp, err := new(http.Client).Do(req)
	if err != nil {
		log.Fatal(err)
	}
	return resp
}

func createGET(url, path, host string) *http.Request {
	return createRequest("GET", url, path, host, nil)
}

func createRequest(method, url, path, host string, body io.Reader) *http.Request {
	req, err := http.NewRequest(method, url+path, body)
	if err != nil {
		log.Fatal(err)
	}
	req.Host = host
	return req
}

func read(resp *http.Response) []byte {
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	return body
}

func makeFullDomain(site string) string {
	return fmt.Sprintf("%s.%s", site, TEST_DEPLOYED_ON)
}

func bytesShouldBeEqual(t *testing.T, expected, actual []byte) {
	if !bytes.Equal(expected, actual) {
		t.Fatalf("<<%v>> != <<%v>>", string(expected), string(actual))
	}
}

func intShouldBeEqual(t *testing.T, expected, actual int) {
	if expected != actual {
		t.Fatalf("<<%v>> != <<%v>>", expected, actual)
	}
}

func shouldRespondInTimeInterval(t *testing.T, minSeconds, maxSeconds float64, req *http.Request) {
	start := time.Now()
	resp := do(req)
	read(resp)
	duration := time.Since(start)
	minDuration := toDuration(minSeconds)
	maxDuration := toDuration(maxSeconds)
	if duration < minDuration || duration > maxDuration {
		t.Fatalf("%s%s answered in %v. Not in the interval [%v; %v]",
			req.Host, req.URL.Path, duration, minDuration, maxDuration)
	}
}

func shouldHaveStatusCode(t *testing.T, statusCode int, resp *http.Response) {
	intShouldBeEqual(t, statusCode, resp.StatusCode)
}

func toDuration(seconds float64) time.Duration {
	return time.Duration(seconds*1000) * time.Millisecond
}

func createDomain(server *httptest.Server, endpoint *Endpoint) string {
	resp := POST(server.URL, fmt.Sprintf("%s?output=short&method=GET", endpoint.Path),
		makeFullDomain("create"), endpoint.Response)
	return string(read(resp))
}

func POST(url, path, host string, payload []byte) *http.Response {
	req := createPOST(url, path, host, payload)
	return do(req)
}

func createPOST(url, path, host string, payload []byte) *http.Request {
	return createRequest("POST", url, path, host, bytes.NewReader(payload))
}

func getSite(domain string) string {
	return strings.Split(domain, ".")[0]
}

func createEndpoint(server *httptest.Server, endpoint *Endpoint) *http.Response {
	req := createPOST(server.URL, endpoint.Path, makeFullDomain("admin-"+endpoint.Site),
		endpoint.Response)
	req.URL.RawQuery = getQueryString(endpoint)
	return do(req)
}

func getQueryString(endpoint *Endpoint) string {
	params := url.Values{}
	params.Set("method", endpoint.Method)
	params.Set("delay", fmt.Sprintf("%f", endpoint.Delay.Seconds()))
	return params.Encode()
}

// Wrapper around path.Join. Preserves trailing slash.
func join(elem ...string) string {
	lastElem := elem[len(elem)-1]
	shouldEndWithSlash := strings.HasSuffix(lastElem, "/")
	joined := path.Join(elem...)
	if shouldEndWithSlash && !strings.HasSuffix(joined, "/") {
		joined += "/"
	}
	return joined
}

func createDb(name string) {
	cmd := exec.Command("createdb", name)
	err := cmd.Run()
	if err != nil {
		log.Fatalf("createdb error: %s", err)
	}
}

func dropDb(name string) {
	cmd := exec.Command("dropdb", name)
	err := cmd.Run()
	if err != nil {
		log.Fatalf("dropdb error: %s", err)
	}
}
<|endoftext|>


<commit_before>package reverseproxy

import (
	"net/http"
	"net/url"
	pathlib "path"
	"strings"
)

type Rule struct {
	SourceHost string `json:source_host`
	SourcePath string `json:source_path`
	DestHost   string `json:dest_host`
	DestPath   string `json:dest_path`
	DestScheme string `json:dest_scheme`

	CaseSensitivePath bool `json:case_sensitive_path`
	CaseSensitiveHost bool `json:case_sensitive_host`
	CleanRequestPath  bool `json:clean_request_path`
}

func (r Rule) MatchesRequest(req *http.Request) bool {
	if !r.CaseSensitiveHost {
		if strings.ToLower(r.SourceHost) != strings.ToLower(req.Host) {
			return false
		}
	} else if r.SourceHost != req.Host {
		return false
	}

	// If the source path is not absolute, anything should match. If the
	// destination is relative but the source is absolute, it should not match.
	reqPath := r.reqPath(req)
	if !pathlib.IsAbs(r.SourcePath) {
		return true
	} else if !pathlib.IsAbs(reqPath) {
		return false
	}
	return PathContains(r.SourcePath, reqPath, r.CaseSensitivePath)
}

func (r Rule) DestinationURL(req *http.Request) url.URL {
	newURL := *req.URL
	newURL.Scheme = r.DestScheme
	newURL.Host = r.DestHost

	// Compute the new path if needed
	if pathlib.IsAbs(r.SourcePath) {
		rel := RelativePath(r.SourcePath, r.reqPath(req), r.CaseSensitivePath)
		newURL.Path = pathlib.Join(r.DestPath, rel)
	}

	return newURL
}

func (r Rule) reqPath(req *http.Request) string {
	if r.CleanRequestPath {
		return pathlib.Clean(req.URL.Path)
	} else {
		return req.URL.Path
	}
}
<commit_msg>added fix to DestinationURL<commit_after>package reverseproxy

import (
	"net/http"
	"net/url"
	pathlib "path"
	"strings"
)

type Rule struct {
	SourceHost string `json:source_host`
	SourcePath string `json:source_path`
	DestHost   string `json:dest_host`
	DestPath   string `json:dest_path`
	DestScheme string `json:dest_scheme`

	CaseSensitivePath bool `json:case_sensitive_path`
	CaseSensitiveHost bool `json:case_sensitive_host`
	CleanRequestPath  bool `json:clean_request_path`
}

func (r Rule) MatchesRequest(req *http.Request) bool {
	if !r.CaseSensitiveHost {
		if strings.ToLower(r.SourceHost) != strings.ToLower(req.Host) {
			return false
		}
	} else if r.SourceHost != req.Host {
		return false
	}

	// If the source path is not absolute, anything should match. If the
	// destination is relative but the source is absolute, it should not match.
	reqPath := r.reqPath(req)
	if !pathlib.IsAbs(r.SourcePath) {
		return true
	} else if !pathlib.IsAbs(reqPath) {
		return false
	}
	return PathContains(r.SourcePath, reqPath, r.CaseSensitivePath)
}

func (r Rule) DestinationURL(req *http.Request) url.URL {
	newURL := *req.URL
	newURL.Scheme = r.DestScheme
	newURL.Host = r.DestHost

	// Compute the new path if needed
	if pathlib.IsAbs(r.SourcePath) {
		rel := RelativePath(r.SourcePath, r.reqPath(req), r.CaseSensitivePath)
		if len(r.DestPath) == 0 {
			newURL.Path = "/" + rel
		} else {
			newURL.Path = pathlib.Join(r.DestPath, rel)
		}
	}

	return newURL
}

func (r Rule) reqPath(req *http.Request) string {
	if r.CleanRequestPath {
		return pathlib.Clean(req.URL.Path)
	} else {
		return req.URL.Path
	}
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

func TestExpandPath(t *testing.T) {
	expected := opts.DataPath + "/foobar"
	actual := expandPath("foobar")
	if expected != actual {
		t.Errorf("Expected: '%s' Got: '%s'\n", expected, actual)
	}
}

func TestPutKeyWithoutNamespace(t *testing.T) {
	testPath := expandPath("foobar")
	testContent := "foobar"
	err := putKey(testPath, testContent)
	if err != nil {
		t.Fail()
	}
	if content, err := ioutil.ReadFile(testPath); err != nil || string(content) != testContent {
		t.Fail()
	}
}

func TestPutKeyWithNamespace(t *testing.T) {
	testPathDirectory := expandPath("foo/")
	testPathFile := expandPath("foo/bar")
	testContent := "foobar"
	err := putKey(testPathFile, testContent)
	if err != nil {
		t.Fail()
	}
	if fileInfo, err := os.Stat(testPathDirectory); err != nil || !fileInfo.IsDir() {
		t.Fail()
	}
	if content, err := ioutil.ReadFile(testPathFile); err != nil || string(content) != testContent {
		t.Fail()
	}
}

func TestMain(m *testing.M) {
	opts.DataPath, _ = filepath.Abs("./data-test")
	exit := m.Run()
	os.RemoveAll(opts.DataPath)
	os.Exit(exit)
}
<commit_msg>add delete test<commit_after>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

func TestExpandPath(t *testing.T) {
	expected := opts.DataPath + "/foobar"
	actual := expandPath("foobar")
	if expected != actual {
		t.Errorf("Expected: '%s' Got: '%s'\n", expected, actual)
	}
}

func TestPutKeyWithoutNamespace(t *testing.T) {
	testPath := expandPath("foobar")
	testContent := "foobar"
	err := putKey(testPath, testContent)
	if err != nil {
		t.Fail()
	}
	if content, err := ioutil.ReadFile(testPath); err != nil || string(content) != testContent {
		t.Fail()
	}
}

func TestPutKeyWithNamespace(t *testing.T) {
	testPathDirectory := expandPath("foo/")
	testPathFile := expandPath("foo/bar")
	testContent := "foobar"
	err := putKey(testPathFile, testContent)
	if err != nil {
		t.Fail()
	}
	if fileInfo, err := os.Stat(testPathDirectory); err != nil || !fileInfo.IsDir() {
		t.Fail()
	}
	if content, err := ioutil.ReadFile(testPathFile); err != nil || string(content) != testContent {
		t.Fail()
	}
}

func TestDeleteKey(t *testing.T) {
	path := expandPath("foobar")
	content := "foobar"
	if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
		t.Errorf("Could not create key '%s'\n", path)
	}
	if err := ioutil.WriteFile(path, []byte(content), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s'\n", path, content)
	}
	deleteKey(path)
	if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
		t.Error(err)
	}
}

func TestMain(m *testing.M) {
	opts.DataPath, _ = filepath.Abs("./data-test")
	exit := m.Run()
	os.RemoveAll(opts.DataPath)
	os.Exit(exit)
}
<|endoftext|>


<commit_before>package main

import "testing"

func TestParseHexColor(t *testing.T) {
	empty := ""
	color, err := parseHexColor(empty)
	if err == nil {
		t.Fatalf("Empty color string should return error, but did not")
	}

	tooLong := "#1234567"
	color, err = parseHexColor(tooLong)
	if err == nil {
		t.Fatalf("Invalid color string %s should return error, but did not",
			tooLong)
	}

	invalidFormat := "$123456"
	color, err = parseHexColor(invalidFormat)
	if err == nil {
		t.Fatalf("Invalid color string %s should return error, but did not",
			invalidFormat)
	}

	valid := "#C0FfeE"
	color, err = parseHexColor(valid)
	if err != nil {
		t.Fatalf("Color %s valid to parse: %s", valid, err)
	}
	if color.R != 0xc0 || color.G != 0xff || color.B != 0xee {
		t.Fatalf("Color %s incorrectly parsed as %v", valid, color)
	}
}
<commit_msg>server test: add !rpctest build flag<commit_after>// +build !rpctest

package main

import "testing"

func TestParseHexColor(t *testing.T) {
	empty := ""
	color, err := parseHexColor(empty)
	if err == nil {
		t.Fatalf("Empty color string should return error, but did not")
	}

	tooLong := "#1234567"
	color, err = parseHexColor(tooLong)
	if err == nil {
		t.Fatalf("Invalid color string %s should return error, but did not",
			tooLong)
	}

	invalidFormat := "$123456"
	color, err = parseHexColor(invalidFormat)
	if err == nil {
		t.Fatalf("Invalid color string %s should return error, but did not",
			invalidFormat)
	}

	valid := "#C0FfeE"
	color, err = parseHexColor(valid)
	if err != nil {
		t.Fatalf("Color %s valid to parse: %s", valid, err)
	}
	if color.R != 0xc0 || color.G != 0xff || color.B != 0xee {
		t.Fatalf("Color %s incorrectly parsed as %v", valid, color)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 DG Lab
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

// fred project main.go
package main

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	"democonf"
	"rpc"
)

// URL for accessing RPC
var rpcurl = "http://127.0.0.1:10040"

// ID for accessing RPC
var rpcuser = "user"

// Password for accessing RPC
var rpcpass = "pass"

var rpcClient *rpc.Rpc

var interval = 3 * time.Second

var logger *log.Logger

var stop = false

func checkgenerate() error {
	var txs []string
	res, err := rpcClient.RequestAndUnmarshalResult(&txs, "getrawmempool")
	if err != nil {
		logger.Printf("Rpc#RequestAndUnmarshalResult error:%v res:%+v", err, res)
		return err
	}
	if len(txs) == 0 {
		return nil
	}
	rpcClient.View = true
	var hashs []string
	res, err = rpcClient.RequestAndUnmarshalResult(&hashs, "generate", 1)
	rpcClient.View = false
	if err != nil {
		logger.Printf("Rpc#RequestAndUnmarshalResult error:%v res:%+v", err, res)
		return err
	}
	return nil
}

func loop() {
	fmt.Println("Loop interval:", interval)
	for {
		time.Sleep(interval)
		err := checkgenerate()
		if err != nil {
			logger.Println("checkgenarate error:", err)
		}
		if stop {
			break
		}
	}
}

func loadConf() {
	conf := democonf.NewDemoConf("fred")
	rpcurl = conf.GetString("rpcurl", rpcurl)
	rpcuser = conf.GetString("rpcuser", rpcuser)
	rpcpass = conf.GetString("rpcpass", rpcpass)
}

func main() {
	logger = log.New(os.Stdout, "Fred:", log.LstdFlags+log.Lshortfile)
	fmt.Println("Fred start")

	loadConf()
	rpcClient = rpc.NewRpc(rpcurl, rpcuser, rpcpass)

	// signal handling (ctrl + c)
	sig := make(chan os.Signal)
	signal.Notify(sig, syscall.SIGINT)
	go func() {
		fmt.Println("signal:", <-sig)
		stop = true
	}()

	loop()

	fmt.Println("Fred stop")
}
<commit_msg>fred use cyclic<commit_after>// Copyright (c) 2017 DG Lab
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

// fred project main.go
package main

import (
	"fmt"
	"log"
	"os"

	"democonf"
	"lib"
	"rpc"
)

// URL for accessing RPC
var rpcurl = "http://127.0.0.1:10040"

// ID for accessing RPC
var rpcuser = "user"

// Password for accessing RPC
var rpcpass = "pass"

var rpcClient *rpc.Rpc

var logger *log.Logger

func checkgenerate() error {
	var txs []string
	res, err := rpcClient.RequestAndUnmarshalResult(&txs, "getrawmempool")
	if err != nil {
		logger.Printf("Rpc#RequestAndUnmarshalResult error:%v res:%+v", err, res)
		return err
	}
	if len(txs) == 0 {
		return nil
	}
	rpcClient.View = true
	var hashs []string
	res, err = rpcClient.RequestAndUnmarshalResult(&hashs, "generate", 1)
	rpcClient.View = false
	if err != nil {
		logger.Printf("Rpc#RequestAndUnmarshalResult error:%v res:%+v", err, res)
		return err
	}
	return nil
}

func callback() {
	err := checkgenerate()
	if err != nil {
		logger.Println("checkgenarate error:", err)
	}
}

func loadConf() {
	conf := democonf.NewDemoConf("fred")
	rpcurl = conf.GetString("rpcurl", rpcurl)
	rpcuser = conf.GetString("rpcuser", rpcuser)
	rpcpass = conf.GetString("rpcpass", rpcpass)
}

func main() {
	logger = log.New(os.Stdout, "Fred:", log.LstdFlags+log.Lshortfile)
	fmt.Println("Fred start")

	loadConf()
	rpcClient = rpc.NewRpc(rpcurl, rpcuser, rpcpass)

	lib.SetLogger(logger)
	lib.StartCyclic(callback, 3, true)

	fmt.Println("Fred stop")
}
<|endoftext|>


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

package dns

import (
	"runtime"
	"testing"
	"time"
)

func HelloServer(w ResponseWriter, req *Msg) {
	m := new(Msg)
	m.SetReply(req)

	m.Extra = make([]RR, 1)
	m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
	w.WriteMsg(m)
}

func AnotherHelloServer(w ResponseWriter, req *Msg) {
	m := new(Msg)
	m.SetReply(req)

	m.Extra = make([]RR, 1)
	m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello example"}}
	w.WriteMsg(m)
}

func TestServing(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	HandleFunc("example.com.", AnotherHelloServer)
	go func() {
		err := ListenAndServe(":8053", "udp", nil)
		if err != nil {
			t.Log("ListenAndServe: ", err.Error())
			t.Fail()
		}
	}()
	time.Sleep(4e8)
	c := new(Client)
	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeTXT)
	r, _, _ := c.Exchange(m, "127.0.0.1:8053")
	txt := r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello world" {
		t.Log("Unexpected result for miek.nl", txt, "!= Hello world")
		t.Fail()
	}
	m.SetQuestion("example.com.", TypeTXT)
	r, _, _ = c.Exchange(m, "127.0.0.1:8053")
	txt = r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello example" {
		t.Log("Unexpected result for example.com", txt, "!= Hello example")
		t.Fail()
	}
}

func BenchmarkServing(b *testing.B) {
	b.StopTimer()
	HandleFunc("miek.nl.", HelloServer)
	a := runtime.GOMAXPROCS(4)
	go func() {
		ListenAndServe("127.0.0.1:8053", "udp", nil)
	}()
	c := new(Client)
	m := new(Msg)
	m.SetQuestion("miek.nl", TypeSOA)

	b.StartTimer()
	for i := 0; i < b.N; i++ {
		c.Exchange(m, "127.0.0.1:8053")
	}
	runtime.GOMAXPROCS(a)
}

func HelloServerCompress(w ResponseWriter, req *Msg) {
	m := new(Msg)
	m.SetReply(req)
	m.Extra = make([]RR, 1)
	m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
	m.Compress = true
	w.WriteMsg(m)
}

func BenchmarkServingCompress(b *testing.B) {
	b.StopTimer()
	HandleFunc("miek.nl.", HelloServerCompress)
	a := runtime.GOMAXPROCS(4)
	go func() {
		ListenAndServe("127.0.0.1:8053", "udp", nil)
	}()

	c := new(Client)
	m := new(Msg)
	m.SetQuestion("miek.nl", TypeSOA)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		c.Exchange(m, "127.0.0.1:8053")
	}
	runtime.GOMAXPROCS(a)
}

func TestDotAsCatchAllWildcard(t *testing.T) {
	mux := NewServeMux()
	mux.Handle(".", HandlerFunc(HelloServer))
	mux.Handle("example.com.", HandlerFunc(AnotherHelloServer))

	handler := mux.match("www.miek.nl.", TypeTXT)
	if handler == nil {
		t.Error("wildcard match failed")
	}

	handler = mux.match("www.example.com.", TypeTXT)
	if handler == nil {
		t.Error("example.com match failed")
	}

	handler = mux.match("a.www.example.com.", TypeTXT)
	if handler == nil {
		t.Error("a.www.example.com match failed")
	}

	handler = mux.match("boe.", TypeTXT)
	if handler == nil {
		t.Error("boe. match failed")
	}
}

func TestRootServer(t *testing.T) {
	mux := NewServeMux()
	mux.Handle(".", HandlerFunc(HelloServer))

	handler := mux.match(".", TypeNS)
	if handler == nil {
		t.Error("root match failed")
	}
}
<commit_msg>Add MixCase query test<commit_after>// Copyright 2011 Miek Gieben. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package dns

import (
	"runtime"
	"testing"
	"time"
)

func HelloServer(w ResponseWriter, req *Msg) {
	m := new(Msg)
	m.SetReply(req)

	m.Extra = make([]RR, 1)
	m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
	w.WriteMsg(m)
}

func AnotherHelloServer(w ResponseWriter, req *Msg) {
	m := new(Msg)
	m.SetReply(req)

	m.Extra = make([]RR, 1)
	m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello example"}}
	w.WriteMsg(m)
}

func TestServing(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	HandleFunc("example.com.", AnotherHelloServer)
	go func() {
		err := ListenAndServe(":8053", "udp", nil)
		if err != nil {
			t.Log("ListenAndServe: ", err.Error())
			t.Fail()
		}
	}()
	time.Sleep(4e8)
	c := new(Client)
	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeTXT)
	r, _, _ := c.Exchange(m, "127.0.0.1:8053")
	txt := r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello world" {
		t.Log("Unexpected result for miek.nl", txt, "!= Hello world")
		t.Fail()
	}
	m.SetQuestion("example.com.", TypeTXT)
	r, _, _ = c.Exchange(m, "127.0.0.1:8053")
	txt = r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello example" {
		t.Log("Unexpected result for example.com", txt, "!= Hello example")
		t.Fail()
	}
	// Test Mixes cased as notices by Ask.
	m.SetQuestion("eXaMplE.cOm.", TypeTXT)
	r, _, _ = c.Exchange(m, "127.0.0.1:8053")
	txt = r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello example" {
		t.Log("Unexpected result for example.com", txt, "!= Hello example")
		t.Fail()
	}
}

func BenchmarkServing(b *testing.B) {
	b.StopTimer()
	HandleFunc("miek.nl.", HelloServer)
	a := runtime.GOMAXPROCS(4)
	go func() {
		ListenAndServe("127.0.0.1:8053", "udp", nil)
	}()
	c := new(Client)
	m := new(Msg)
	m.SetQuestion("miek.nl", TypeSOA)

	b.StartTimer()
	for i := 0; i < b.N; i++ {
		c.Exchange(m, "127.0.0.1:8053")
	}
	runtime.GOMAXPROCS(a)
}

func HelloServerCompress(w ResponseWriter, req *Msg) {
	m := new(Msg)
	m.SetReply(req)
	m.Extra = make([]RR, 1)
	m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
	m.Compress = true
	w.WriteMsg(m)
}

func BenchmarkServingCompress(b *testing.B) {
	b.StopTimer()
	HandleFunc("miek.nl.", HelloServerCompress)
	a := runtime.GOMAXPROCS(4)
	go func() {
		ListenAndServe("127.0.0.1:8053", "udp", nil)
	}()

	c := new(Client)
	m := new(Msg)
	m.SetQuestion("miek.nl", TypeSOA)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		c.Exchange(m, "127.0.0.1:8053")
	}
	runtime.GOMAXPROCS(a)
}

func TestDotAsCatchAllWildcard(t *testing.T) {
	mux := NewServeMux()
	mux.Handle(".", HandlerFunc(HelloServer))
	mux.Handle("example.com.", HandlerFunc(AnotherHelloServer))

	handler := mux.match("www.miek.nl.", TypeTXT)
	if handler == nil {
		t.Error("wildcard match failed")
	}

	handler = mux.match("www.example.com.", TypeTXT)
	if handler == nil {
		t.Error("example.com match failed")
	}

	handler = mux.match("a.www.example.com.", TypeTXT)
	if handler == nil {
		t.Error("a.www.example.com match failed")
	}

	handler = mux.match("boe.", TypeTXT)
	if handler == nil {
		t.Error("boe. match failed")
	}
}

func TestRootServer(t *testing.T) {
	mux := NewServeMux()
	mux.Handle(".", HandlerFunc(HelloServer))

	handler := mux.match(".", TypeNS)
	if handler == nil {
		t.Error("root match failed")
	}
}
<|endoftext|>


<commit_before>/*
 *   Copyright 2016 Manik Surtani
 *
 *   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 quotaservice

import (
	"testing"
	"github.com/maniksurtani/quotaservice/configs"
	"github.com/maniksurtani/quotaservice/buckets/memory"
	"github.com/maniksurtani/quotaservice/test"
)

func TestWithNoRpcs(t *testing.T) {
	defer
	test.ExpectingPanic(t, func() {
		New(configs.DefaultBucketConfig(), &memory.BucketFactory{})
	})
}
<commit_msg>Fix correct config type<commit_after>/*
 *   Copyright 2016 Manik Surtani
 *
 *   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 quotaservice

import (
	"testing"
	"github.com/maniksurtani/quotaservice/configs"
	"github.com/maniksurtani/quotaservice/buckets/memory"
	"github.com/maniksurtani/quotaservice/test"
)

func TestWithNoRpcs(t *testing.T) {
	defer
	test.ExpectingPanic(t, func() {
		New(configs.NewDefaultConfig(), &memory.BucketFactory{})
	})
}
<|endoftext|>