<commit_before>package etcd

import (
	"context"

	g "github.com/onsi/ginkgo"
	o "github.com/onsi/gomega"

	machineclient "github.com/openshift/client-go/machine/clientset/versioned"
	testlibraryapi "github.com/openshift/library-go/test/library/apiserver"
	scalingtestinglibrary "github.com/openshift/origin/test/extended/etcd/helpers"
	exutil "github.com/openshift/origin/test/extended/util"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/test/e2e/framework"
)

var _ = g.Describe("[sig-etcd][Serial] etcd", func() {
	defer g.GinkgoRecover()
	oc := exutil.NewCLIWithoutNamespace("etcd-scaling").AsAdmin()

	cleanupPlatformSpecificConfiguration := func() { /*noop*/ }

	g.BeforeEach(func() {
		cleanupPlatformSpecificConfiguration = scalingtestinglibrary.InitPlatformSpecificConfiguration(oc)
	})

	g.AfterEach(func() {
		cleanupPlatformSpecificConfiguration()
	})

	// The following test covers a basic vertical scaling scenario.
	// It starts by adding a new master machine to the cluster
	// next it validates the size of etcd cluster and makes sure the new member is healthy.
	// The test ends by removing the newly added machine and validating the size of the cluster
	// and asserting the member was removed from the etcd cluster by contacting MemberList API.
	g.It("is able to vertically scale up and down with a single node", func() {
		// set up
		ctx := context.TODO()
		etcdClientFactory := scalingtestinglibrary.NewEtcdClientFactory(oc.KubeClient())
		machineClientSet, err := machineclient.NewForConfig(oc.KubeFramework().ClientConfig())
		o.Expect(err).ToNot(o.HaveOccurred())
		machineClient := machineClientSet.MachineV1beta1().Machines("openshift-machine-api")
		kubeClient := oc.KubeClient()

		// make sure it can be run on the current platform
		scalingtestinglibrary.SkipIfUnsupportedPlatform(ctx, oc)

		// assert the cluster state before we run the test
		err = scalingtestinglibrary.EnsureInitialClusterState(ctx, g.GinkgoT(), etcdClientFactory, machineClient, kubeClient)
		o.Expect(err).ToNot(o.HaveOccurred())

		// step 0: ensure clean state after the test
		defer func() {
			// since the deletion triggers a new rollout
			// we need to make sure that the API is stable after the test
			// so that other e2e test won't hit an API that undergoes a termination (write request might fail)
			g.GinkgoT().Log("cleaning routine: ensuring initial cluster state and waiting for api servers to stabilize on the same revision")
			err = scalingtestinglibrary.EnsureInitialClusterState(ctx, g.GinkgoT(), etcdClientFactory, machineClient, kubeClient)
			o.Expect(err).ToNot(o.HaveOccurred())
			err = testlibraryapi.WaitForAPIServerToStabilizeOnTheSameRevision(g.GinkgoT(), oc.KubeClient().CoreV1().Pods("openshift-kube-apiserver"))
			o.Expect(err).ToNot(o.HaveOccurred())
		}()

		// step 1: add a new master node and wait until it is in Running state
		machineName, err := scalingtestinglibrary.CreateNewMasterMachine(ctx, g.GinkgoT(), machineClient)
		o.Expect(err).ToNot(o.HaveOccurred())
		err = scalingtestinglibrary.EnsureMasterMachine(ctx, g.GinkgoT(), machineName, machineClient)
		o.Expect(err).ToNot(o.HaveOccurred())

		// step 2: wait until a new member shows up and check if it is healthy
		//         and until all kube-api servers have reached the same revision
		//         this additional step is the best-effort of ensuring they
		//         have observed the new member before disruption
		err = scalingtestinglibrary.EnsureVotingMembersCount(ctx, g.GinkgoT(), etcdClientFactory, kubeClient, 4)
		o.Expect(err).ToNot(o.HaveOccurred())
		memberName, err := scalingtestinglibrary.MachineNameToEtcdMemberName(ctx, oc.KubeClient(), machineClient, machineName)
		o.Expect(err).ToNot(o.HaveOccurred())
		err = scalingtestinglibrary.EnsureHealthyMember(g.GinkgoT(), etcdClientFactory, memberName)
		o.Expect(err).ToNot(o.HaveOccurred())
		g.GinkgoT().Log("waiting for api servers to stabilize on the same revision")
		err = testlibraryapi.WaitForAPIServerToStabilizeOnTheSameRevision(g.GinkgoT(), oc.KubeClient().CoreV1().Pods("openshift-kube-apiserver"))
		o.Expect(err).ToNot(o.HaveOccurred())

		// step 3: clean-up: delete the machine and wait until etcd member is removed from the etcd cluster
		err = machineClient.Delete(ctx, machineName, metav1.DeleteOptions{})
		o.Expect(err).ToNot(o.HaveOccurred())
		framework.Logf("successfully deleted the machine %q from the API", machineName)
		err = scalingtestinglibrary.EnsureVotingMembersCount(ctx, g.GinkgoT(), etcdClientFactory, kubeClient, 3)
		o.Expect(err).ToNot(o.HaveOccurred())
		err = scalingtestinglibrary.EnsureMemberRemoved(g.GinkgoT(), etcdClientFactory, memberName)
		o.Expect(err).ToNot(o.HaveOccurred())
		err = scalingtestinglibrary.EnsureMasterMachinesAndCount(ctx, g.GinkgoT(), machineClient)
		o.Expect(err).ToNot(o.HaveOccurred())
	})
})
<commit_msg>set explicit timeout for the etcd scaling test<commit_after>package etcd

import (
	"context"

	g "github.com/onsi/ginkgo"
	o "github.com/onsi/gomega"

	machineclient "github.com/openshift/client-go/machine/clientset/versioned"
	testlibraryapi "github.com/openshift/library-go/test/library/apiserver"
	scalingtestinglibrary "github.com/openshift/origin/test/extended/etcd/helpers"
	exutil "github.com/openshift/origin/test/extended/util"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/test/e2e/framework"
)

var _ = g.Describe("[sig-etcd][Serial] etcd", func() {
	defer g.GinkgoRecover()
	oc := exutil.NewCLIWithoutNamespace("etcd-scaling").AsAdmin()

	cleanupPlatformSpecificConfiguration := func() { /*noop*/ }

	g.BeforeEach(func() {
		cleanupPlatformSpecificConfiguration = scalingtestinglibrary.InitPlatformSpecificConfiguration(oc)
	})

	g.AfterEach(func() {
		cleanupPlatformSpecificConfiguration()
	})

	// The following test covers a basic vertical scaling scenario.
	// It starts by adding a new master machine to the cluster
	// next it validates the size of etcd cluster and makes sure the new member is healthy.
	// The test ends by removing the newly added machine and validating the size of the cluster
	// and asserting the member was removed from the etcd cluster by contacting MemberList API.
	g.It("is able to vertically scale up and down with a single node [Timeout:60m]", func() {
		// set up
		ctx := context.TODO()
		etcdClientFactory := scalingtestinglibrary.NewEtcdClientFactory(oc.KubeClient())
		machineClientSet, err := machineclient.NewForConfig(oc.KubeFramework().ClientConfig())
		o.Expect(err).ToNot(o.HaveOccurred())
		machineClient := machineClientSet.MachineV1beta1().Machines("openshift-machine-api")
		kubeClient := oc.KubeClient()

		// make sure it can be run on the current platform
		scalingtestinglibrary.SkipIfUnsupportedPlatform(ctx, oc)

		// assert the cluster state before we run the test
		err = scalingtestinglibrary.EnsureInitialClusterState(ctx, g.GinkgoT(), etcdClientFactory, machineClient, kubeClient)
		o.Expect(err).ToNot(o.HaveOccurred())

		// step 0: ensure clean state after the test
		defer func() {
			// since the deletion triggers a new rollout
			// we need to make sure that the API is stable after the test
			// so that other e2e test won't hit an API that undergoes a termination (write request might fail)
			g.GinkgoT().Log("cleaning routine: ensuring initial cluster state and waiting for api servers to stabilize on the same revision")
			err = scalingtestinglibrary.EnsureInitialClusterState(ctx, g.GinkgoT(), etcdClientFactory, machineClient, kubeClient)
			o.Expect(err).ToNot(o.HaveOccurred())
			err = testlibraryapi.WaitForAPIServerToStabilizeOnTheSameRevision(g.GinkgoT(), oc.KubeClient().CoreV1().Pods("openshift-kube-apiserver"))
			o.Expect(err).ToNot(o.HaveOccurred())
		}()

		// step 1: add a new master node and wait until it is in Running state
		machineName, err := scalingtestinglibrary.CreateNewMasterMachine(ctx, g.GinkgoT(), machineClient)
		o.Expect(err).ToNot(o.HaveOccurred())
		err = scalingtestinglibrary.EnsureMasterMachine(ctx, g.GinkgoT(), machineName, machineClient)
		o.Expect(err).ToNot(o.HaveOccurred())

		// step 2: wait until a new member shows up and check if it is healthy
		//         and until all kube-api servers have reached the same revision
		//         this additional step is the best-effort of ensuring they
		//         have observed the new member before disruption
		err = scalingtestinglibrary.EnsureVotingMembersCount(ctx, g.GinkgoT(), etcdClientFactory, kubeClient, 4)
		o.Expect(err).ToNot(o.HaveOccurred())
		memberName, err := scalingtestinglibrary.MachineNameToEtcdMemberName(ctx, oc.KubeClient(), machineClient, machineName)
		o.Expect(err).ToNot(o.HaveOccurred())
		err = scalingtestinglibrary.EnsureHealthyMember(g.GinkgoT(), etcdClientFactory, memberName)
		o.Expect(err).ToNot(o.HaveOccurred())
		g.GinkgoT().Log("waiting for api servers to stabilize on the same revision")
		err = testlibraryapi.WaitForAPIServerToStabilizeOnTheSameRevision(g.GinkgoT(), oc.KubeClient().CoreV1().Pods("openshift-kube-apiserver"))
		o.Expect(err).ToNot(o.HaveOccurred())

		// step 3: clean-up: delete the machine and wait until etcd member is removed from the etcd cluster
		err = machineClient.Delete(ctx, machineName, metav1.DeleteOptions{})
		o.Expect(err).ToNot(o.HaveOccurred())
		framework.Logf("successfully deleted the machine %q from the API", machineName)
		err = scalingtestinglibrary.EnsureVotingMembersCount(ctx, g.GinkgoT(), etcdClientFactory, kubeClient, 3)
		o.Expect(err).ToNot(o.HaveOccurred())
		err = scalingtestinglibrary.EnsureMemberRemoved(g.GinkgoT(), etcdClientFactory, memberName)
		o.Expect(err).ToNot(o.HaveOccurred())
		err = scalingtestinglibrary.EnsureMasterMachinesAndCount(ctx, g.GinkgoT(), machineClient)
		o.Expect(err).ToNot(o.HaveOccurred())
	})
})
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"

	yaml "gopkg.in/yaml.v2"

	stks "github.com/daidokoro/qaz/stacks"

	"github.com/daidokoro/qaz/bucket"
	"github.com/daidokoro/qaz/repo"
	"github.com/daidokoro/qaz/utils"

	"github.com/CrowdSurge/banner"
	"github.com/spf13/cobra"
)

// initialise - adds, logging and repo vars to dependecny functions
var initialise = func(cmd *cobra.Command, args []string) {
	log.Debug(fmt.Sprintf("Initialising Command [%s]", cmd.Name()))
	// add logging
	stks.Log = &log
	bucket.Log = &log
	repo.Log = &log
	utils.Log = &log

	// add repo
	stks.Git = &gitrepo
}

var (
	// RootCmd command (calls all other commands)
	RootCmd = &cobra.Command{
		Use:   "qaz",
		Short: version,
		Run: func(cmd *cobra.Command, args []string) {

			if run.version {
				fmt.Printf("qaz - Version %s"+"\n", version)
				return
			}

			cmd.Help()
		},
	}

	// initCmd used to initial project
	initCmd = &cobra.Command{
		Use:    "init [target directory]",
		Short:  "Creates an initial Qaz config file",
		PreRun: initialise,
		Run: func(cmd *cobra.Command, args []string) {

			// Print Banner
			banner.Print("qaz")
			fmt.Printf("\n--\n")

			var target string
			switch len(args) {
			case 0:
				target, _ = os.Getwd()
			default:
				target = args[0]
			}

			// Get Project & AWS Region
			arrow := log.ColorString("->", "magenta")
			project = utils.GetInput(fmt.Sprintf("%s Enter your Project name", arrow), "qaz-project")
			region = utils.GetInput(fmt.Sprintf("%s Enter AWS Region", arrow), "eu-west-1")

			// set target paths
			c := filepath.Join(target, "config.yml")

			// Check if config file exists
			var overwrite string
			if _, err := os.Stat(c); err == nil {
				overwrite = utils.GetInput(
					fmt.Sprintf("%s [%s] already exist, Do you want to %s?(Y/N) ", log.ColorString("->", "yellow"), c, log.ColorString("Overwrite", "red")),
					"N",
				)

				if overwrite == "Y" {
					fmt.Println(fmt.Sprintf("%s Overwriting: [%s]..", log.ColorString("->", "yellow"), c))
				}
			}

			// Create template file
			if overwrite != "N" {
				if err := ioutil.WriteFile(c, utils.ConfigTemplate(project, region), 0644); err != nil {
					fmt.Printf("%s Error, unable to create config.yml file: %s"+"\n", err, log.ColorString("->", "red"))
					return
				}
			}

			fmt.Println("--")
		},
	}

	// set stack policy
	policyCmd = &cobra.Command{
		Use:     "set-policy",
		Short:   "Set Stack Policies based on configured value",
		Example: "qaz set-policy <stack name>",
		PreRun:  initialise,
		Run: func(cmd *cobra.Command, args []string) {

			if len(args) == 0 {
				utils.HandleError(fmt.Errorf("please specify stack name"))
			}

			err := Configure(run.cfgSource, run.cfgRaw)
			utils.HandleError(err)

			for _, s := range args {
				wg.Add(1)
				go func(s string) {
					if _, ok := stacks[s]; !ok {
						utils.HandleError(fmt.Errorf("Stack [%s] not found in config", s))
					}

					err := stacks[s].StackPolicy()
					utils.HandleError(err)

					wg.Done()
					return

				}(s)
			}

			wg.Wait()

		},
	}

	// Values - print json config values for a stack
	valuesCmd = &cobra.Command{
		Use:     "values [stack]",
		Short:   "Print stack values from config in YAML format",
		Example: "qaz values stack",
		PreRun:  initialise,
		Run: func(cmd *cobra.Command, args []string) {

			if len(args) == 0 {
				utils.HandleError(fmt.Errorf("please specify stack name"))
				return
			}

			// set stack value based on argument
			s := args[0]

			err := Configure(run.cfgSource, run.cfgRaw)
			utils.HandleError(err)

			if _, ok := stacks[s]; !ok {
				utils.HandleError(fmt.Errorf("Stack [%s] not found in config", s))
			}

			values := stacks[s].TemplateValues[s].(map[string]interface{})

			log.Debug(fmt.Sprintln("Converting stack outputs to JSON from:", values))
			output, err := yaml.Marshal(values)
			utils.HandleError(err)

			reg, err := regexp.Compile(stks.OutputRegex)
			utils.HandleError(err)

			resp := reg.ReplaceAllStringFunc(string(output), func(s string) string {
				return log.ColorString(s, "cyan")
			})

			fmt.Printf("\n%s\n", resp)
		},
	}
)
<commit_msg>updated regex var<commit_after>package commands

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"

	yaml "gopkg.in/yaml.v2"

	stks "github.com/daidokoro/qaz/stacks"

	"github.com/daidokoro/qaz/bucket"
	"github.com/daidokoro/qaz/repo"
	"github.com/daidokoro/qaz/utils"

	"github.com/CrowdSurge/banner"
	"github.com/spf13/cobra"
)

// initialise - adds, logging and repo vars to dependecny functions
var initialise = func(cmd *cobra.Command, args []string) {
	log.Debug(fmt.Sprintf("Initialising Command [%s]", cmd.Name()))
	// add logging
	stks.Log = &log
	bucket.Log = &log
	repo.Log = &log
	utils.Log = &log

	// add repo
	stks.Git = &gitrepo
}

var (
	// RootCmd command (calls all other commands)
	RootCmd = &cobra.Command{
		Use:   "qaz",
		Short: version,
		Run: func(cmd *cobra.Command, args []string) {

			if run.version {
				fmt.Printf("qaz - Version %s"+"\n", version)
				return
			}

			cmd.Help()
		},
	}

	// initCmd used to initial project
	initCmd = &cobra.Command{
		Use:    "init [target directory]",
		Short:  "Creates an initial Qaz config file",
		PreRun: initialise,
		Run: func(cmd *cobra.Command, args []string) {

			// Print Banner
			banner.Print("qaz")
			fmt.Printf("\n--\n")

			var target string
			switch len(args) {
			case 0:
				target, _ = os.Getwd()
			default:
				target = args[0]
			}

			// Get Project & AWS Region
			arrow := log.ColorString("->", "magenta")
			project = utils.GetInput(fmt.Sprintf("%s Enter your Project name", arrow), "qaz-project")
			region = utils.GetInput(fmt.Sprintf("%s Enter AWS Region", arrow), "eu-west-1")

			// set target paths
			c := filepath.Join(target, "config.yml")

			// Check if config file exists
			var overwrite string
			if _, err := os.Stat(c); err == nil {
				overwrite = utils.GetInput(
					fmt.Sprintf("%s [%s] already exist, Do you want to %s?(Y/N) ", log.ColorString("->", "yellow"), c, log.ColorString("Overwrite", "red")),
					"N",
				)

				if overwrite == "Y" {
					fmt.Println(fmt.Sprintf("%s Overwriting: [%s]..", log.ColorString("->", "yellow"), c))
				}
			}

			// Create template file
			if overwrite != "N" {
				if err := ioutil.WriteFile(c, utils.ConfigTemplate(project, region), 0644); err != nil {
					fmt.Printf("%s Error, unable to create config.yml file: %s"+"\n", err, log.ColorString("->", "red"))
					return
				}
			}

			fmt.Println("--")
		},
	}

	// set stack policy
	policyCmd = &cobra.Command{
		Use:     "set-policy",
		Short:   "Set Stack Policies based on configured value",
		Example: "qaz set-policy <stack name>",
		PreRun:  initialise,
		Run: func(cmd *cobra.Command, args []string) {

			if len(args) == 0 {
				utils.HandleError(fmt.Errorf("please specify stack name"))
			}

			err := Configure(run.cfgSource, run.cfgRaw)
			utils.HandleError(err)

			for _, s := range args {
				wg.Add(1)
				go func(s string) {
					if _, ok := stacks[s]; !ok {
						utils.HandleError(fmt.Errorf("Stack [%s] not found in config", s))
					}

					err := stacks[s].StackPolicy()
					utils.HandleError(err)

					wg.Done()
					return

				}(s)
			}

			wg.Wait()

		},
	}

	// Values - print json config values for a stack
	valuesCmd = &cobra.Command{
		Use:     "values [stack]",
		Short:   "Print stack values from config in YAML format",
		Example: "qaz values stack",
		PreRun:  initialise,
		Run: func(cmd *cobra.Command, args []string) {

			if len(args) == 0 {
				utils.HandleError(fmt.Errorf("please specify stack name"))
				return
			}

			// set stack value based on argument
			s := args[0]

			err := Configure(run.cfgSource, run.cfgRaw)
			utils.HandleError(err)

			if _, ok := stacks[s]; !ok {
				utils.HandleError(fmt.Errorf("Stack [%s] not found in config", s))
			}

			values := stacks[s].TemplateValues[s].(map[string]interface{})

			log.Debug(fmt.Sprintln("Converting stack outputs to JSON from:", values))
			output, err := yaml.Marshal(values)
			utils.HandleError(err)

			reg, err := regexp.Compile(OutputRegex)
			utils.HandleError(err)

			resp := reg.ReplaceAllStringFunc(string(output), func(s string) string {
				return log.ColorString(s, "cyan")
			})

			fmt.Printf("\n%s\n", resp)
		},
	}
)
<|endoftext|>


<commit_before>package client

import (
	"bufio"
	"log"
	"os"
	"os/exec"
	"time"
)

// ServiceManager is the default implementation of the Service interface.
type ServiceManager struct {
	Cmd                 string
	processes           map[int]*exec.Cmd
	Args                []string
	Env                 []string
	commandCompleteChan chan *exec.Cmd
	commandCreatedChan  chan *exec.Cmd
}

// Setup the Management services.
func (s *ServiceManager) Setup() {
	log.Println("[DEBUG] setting up a service manager")

	s.commandCreatedChan = make(chan *exec.Cmd)
	s.commandCompleteChan = make(chan *exec.Cmd)
	s.processes = make(map[int]*exec.Cmd)

	// Listen for service create/kill
	go s.addServiceMonitor()
	go s.removeServiceMonitor()
}

// addServiceMonitor watches a channel to add services into operation.
func (s *ServiceManager) addServiceMonitor() {
	log.Println("[DEBUG] starting service creation monitor")
	for {
		select {
		case p := <-s.commandCreatedChan:
			if p != nil && p.Process != nil {
				s.processes[p.Process.Pid] = p
			}
		}
	}
}

// removeServiceMonitor watches a channel to remove services from operation.
func (s *ServiceManager) removeServiceMonitor() {
	log.Println("[DEBUG] starting service removal monitor")
	var p *exec.Cmd
	for {
		select {
		case p = <-s.commandCompleteChan:
			if p != nil && p.Process != nil {
				p.Process.Signal(os.Interrupt)
				delete(s.processes, p.Process.Pid)
			}
		}
	}
}

// Stop a Service and returns the exit status.
func (s *ServiceManager) Stop(pid int) (bool, error) {
	log.Println("[DEBUG] stopping service with pid", pid)
	cmd := s.processes[pid]

	// Remove service from registry
	go func() {
		s.commandCompleteChan <- cmd
	}()

	// Wait for error, kill if it takes too long
	var err error
	done := make(chan error, 1)
	go func() {
		done <- cmd.Wait()
	}()

	select {
	case <-time.After(3 * time.Second):
		if err = cmd.Process.Kill(); err != nil {
			log.Println("[ERROR] timeout reached, killing pid", pid)

			return false, err
		}
	case err = <-done:
		if err != nil {
			log.Println("[ERROR] error waiting for process to complete", err)
			return false, err
		}
	}

	return true, nil
}

// List all Service PIDs.
func (s *ServiceManager) List() map[int]*exec.Cmd {
	log.Println("[DEBUG] listing services")
	return s.processes
}

// Command executes the command
func (s *ServiceManager) Command() *exec.Cmd {
	cmd := exec.Command(s.Cmd, s.Args...)
	env := os.Environ()
	env = append(env, s.Env...)
	cmd.Env = env

	return cmd
}

// Start a Service and log its output.
func (s *ServiceManager) Start() *exec.Cmd {
	log.Println("[DEBUG] starting service")
	cmd := exec.Command(s.Cmd, s.Args...)
	env := os.Environ()
	env = append(env, s.Env...)
	cmd.Env = env

	cmdReader, err := cmd.StdoutPipe()
	if err != nil {
		log.Printf("[ERROR] unable to create output pipe for cmd: %s\n", err.Error())
		os.Exit(1)
	}

	cmdReaderErr, err := cmd.StderrPipe()
	if err != nil {
		log.Printf("[ERROR] unable to create error pipe for cmd: %s\n", err.Error())
		os.Exit(1)
	}

	scanner := bufio.NewScanner(cmdReader)
	go func() {
		for scanner.Scan() {
			log.Printf("[INFO] %s\n", scanner.Text())
		}
	}()

	scanner2 := bufio.NewScanner(cmdReaderErr)
	go func() {
		for scanner2.Scan() {
			log.Printf("[ERROR] service: %s\n", scanner2.Text())
		}
	}()

	err = cmd.Start()
	if err != nil {
		log.Println("[ERROR] service", err.Error())
		os.Exit(1)
	}

	// Add service to registry
	s.commandCreatedChan <- cmd

	return cmd
}
<commit_msg>fix(os-exit): remove  calls. See #46<commit_after>package client

import (
	"bufio"
	"log"
	"os"
	"os/exec"
	"time"
)

// ServiceManager is the default implementation of the Service interface.
type ServiceManager struct {
	Cmd                 string
	processes           map[int]*exec.Cmd
	Args                []string
	Env                 []string
	commandCompleteChan chan *exec.Cmd
	commandCreatedChan  chan *exec.Cmd
}

// Setup the Management services.
func (s *ServiceManager) Setup() {
	log.Println("[DEBUG] setting up a service manager")

	s.commandCreatedChan = make(chan *exec.Cmd)
	s.commandCompleteChan = make(chan *exec.Cmd)
	s.processes = make(map[int]*exec.Cmd)

	// Listen for service create/kill
	go s.addServiceMonitor()
	go s.removeServiceMonitor()
}

// addServiceMonitor watches a channel to add services into operation.
func (s *ServiceManager) addServiceMonitor() {
	log.Println("[DEBUG] starting service creation monitor")
	for {
		select {
		case p := <-s.commandCreatedChan:
			if p != nil && p.Process != nil {
				s.processes[p.Process.Pid] = p
			}
		}
	}
}

// removeServiceMonitor watches a channel to remove services from operation.
func (s *ServiceManager) removeServiceMonitor() {
	log.Println("[DEBUG] starting service removal monitor")
	var p *exec.Cmd
	for {
		select {
		case p = <-s.commandCompleteChan:
			if p != nil && p.Process != nil {
				p.Process.Signal(os.Interrupt)
				delete(s.processes, p.Process.Pid)
			}
		}
	}
}

// Stop a Service and returns the exit status.
func (s *ServiceManager) Stop(pid int) (bool, error) {
	log.Println("[DEBUG] stopping service with pid", pid)
	cmd := s.processes[pid]

	// Remove service from registry
	go func() {
		s.commandCompleteChan <- cmd
	}()

	// Wait for error, kill if it takes too long
	var err error
	done := make(chan error, 1)
	go func() {
		done <- cmd.Wait()
	}()

	select {
	case <-time.After(3 * time.Second):
		if err = cmd.Process.Kill(); err != nil {
			log.Println("[ERROR] timeout reached, killing pid", pid)

			return false, err
		}
	case err = <-done:
		if err != nil {
			log.Println("[ERROR] error waiting for process to complete", err)
			return false, err
		}
	}

	return true, nil
}

// List all Service PIDs.
func (s *ServiceManager) List() map[int]*exec.Cmd {
	log.Println("[DEBUG] listing services")
	return s.processes
}

// Command executes the command
func (s *ServiceManager) Command() *exec.Cmd {
	cmd := exec.Command(s.Cmd, s.Args...)
	env := os.Environ()
	env = append(env, s.Env...)
	cmd.Env = env

	return cmd
}

// Start a Service and log its output.
func (s *ServiceManager) Start() *exec.Cmd {
	log.Println("[DEBUG] starting service")
	cmd := exec.Command(s.Cmd, s.Args...)
	env := os.Environ()
	env = append(env, s.Env...)
	cmd.Env = env

	cmdReader, err := cmd.StdoutPipe()
	if err != nil {
		log.Printf("[ERROR] unable to create output pipe for cmd: %s\n", err.Error())
	}

	cmdReaderErr, err := cmd.StderrPipe()
	if err != nil {
		log.Printf("[ERROR] unable to create error pipe for cmd: %s\n", err.Error())
	}

	scanner := bufio.NewScanner(cmdReader)
	go func() {
		for scanner.Scan() {
			log.Printf("[INFO] %s\n", scanner.Text())
		}
	}()

	scanner2 := bufio.NewScanner(cmdReaderErr)
	go func() {
		for scanner2.Scan() {
			log.Printf("[ERROR] service: %s\n", scanner2.Text())
		}
	}()

	err = cmd.Start()
	if err != nil {
		log.Println("[ERROR] service", err.Error())
	}

	// Add service to registry
	s.commandCreatedChan <- cmd

	return cmd
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"testing"

	"github.com/stretchr/testify/require"
)

// These tests ensure that the code generator generates valid code that can be built
// in combination with Thrift's autogenerated code.

func TestAllThrift(t *testing.T) {
	files, err := ioutil.ReadDir("test_files")
	require.NoError(t, err, "Cannot read test_files directory: %v", err)

	for _, f := range files {
		fname := f.Name()
		if f.IsDir() || filepath.Ext(fname) != ".thrift" {
			continue
		}

		if err := runBuildTest(t, filepath.Join("test_files", fname)); err != nil {
			t.Errorf("Thrift file %v failed: %v", fname, err)
		}
	}
}

func TestIncludeThrift(t *testing.T) {
	dirs, err := ioutil.ReadDir("test_files/include_test")
	require.NoError(t, err, "Cannot read test_files/include_test directory: %v", err)

	for _, d := range dirs {
		dname := d.Name()
		if !d.IsDir() {
			continue
		}

		thriftFile := filepath.Join(dname, path.Base(dname)+".thrift")
		if err := runBuildTest(t, filepath.Join("test_files/include_test/", thriftFile)); err != nil {
			t.Errorf("Thrift test %v failed: %v", dname, err)
		}
	}
}

func TestMultipleFiles(t *testing.T) {
	if err := runBuildTest(t, filepath.Join("test_files", "multi_test", "file1.thrift")); err != nil {
		t.Errorf("Multiple file test failed: %v", err)
	}
}

func TestExternalTemplate(t *testing.T) {
	template1 := `package {{ .Package }}

{{ range .AST.Services }}
// Service {{ .Name }} has {{ len .Methods }} methods.
{{ range .Methods }}
// func {{ .Name | goPublicName }} ({{ range .Arguments }}{{ .Type | goType }}, {{ end }}) ({{ if .ReturnType }}{{ .ReturnType | goType }}{{ end }}){{ end }}
{{ end }}
	`
	templateFile := writeTempFile(t, template1)
	defer os.Remove(templateFile)

	expected := `package service_extend

// Service S1 has 1 methods.

// func M1 ([]byte, ) ([]byte)

// Service S2 has 1 methods.

// func M2 (*S, int32, ) (*S)

// Service S3 has 1 methods.

// func M3 () ()
`

	opts := processOptions{
		InputFile:     "test_files/service_extend.thrift",
		TemplateFiles: []string{templateFile},
	}
	checks := func(dir string) error {
		dir = filepath.Join(dir, "service_extend")
		if err := checkDirectoryFiles(dir, 6); err != nil {
			return err
		}

		// Verify the contents of the extra file.
		outFile := filepath.Join(dir, packageName(templateFile)+"-service_extend.go")
		return verifyFileContents(outFile, expected)
	}
	if err := runTest(t, opts, checks); err != nil {
		t.Errorf("Failed to run test: %v", err)
	}
}

func writeTempFile(t *testing.T, contents string) string {
	tempFile, err := ioutil.TempFile("", "temp")
	require.NoError(t, err, "Failed to create temp file")
	tempFile.Close()
	require.NoError(t, ioutil.WriteFile(tempFile.Name(), []byte(contents), 0666),
		"Write temp file failed")
	return tempFile.Name()
}

func verifyFileContents(filename, expected string) error {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}

	bytesStr := string(bytes)
	if bytesStr != expected {
		return fmt.Errorf("file contents mismatch. got:\n%vexpected:\n%v", bytesStr, expected)
	}

	return nil
}

func copyFile(src, dst string) error {
	f, err := os.Open(src)
	if err != nil {
		return err
	}
	defer f.Close()

	writeF, err := os.OpenFile(dst, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
	if err != nil {
		return err
	}
	defer writeF.Close()

	_, err = io.Copy(writeF, f)
	return err
}

// setupDirectory creates a temporary directory.
func setupDirectory(thriftFile string) (string, error) {
	tempDir, err := ioutil.TempDir("", "thrift-gen")
	if err != nil {
		return "", err
	}

	return tempDir, nil
}

func createAdditionalTestFile(thriftFile, tempDir string) error {
	f, err := os.Open(thriftFile)
	if err != nil {
		return err
	}

	var writer io.Writer
	rdr := bufio.NewReader(f)
	for {
		line, err := rdr.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				return nil
			}
		}

		if strings.HasPrefix(line, "//Go code:") {
			fileName := strings.TrimSpace(strings.TrimPrefix(line, "//Go code:"))
			outFile := filepath.Join(tempDir, fileName)
			f, err := os.OpenFile(outFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
			if err != nil {
				return err
			}
			defer f.Close()
			writer = f
		} else if writer != nil {
			if strings.HasPrefix(line, "//") {
				writer.Write([]byte(strings.TrimPrefix(line, "//")))
			} else {
				return nil
			}
		}
	}
}

func checkDirectoryFiles(dir string, n int) error {
	dirContents, err := ioutil.ReadDir(dir)
	if err != nil {
		return err
	}

	if len(dirContents) < n {
		return fmt.Errorf("expected to generate at least %v files, but found: %v", n, len(dirContents))
	}

	return nil
}

func runBuildTest(t *testing.T, thriftFile string) error {
	extraChecks := func(dir string) error {
		return checkDirectoryFiles(filepath.Join(dir, packageName(thriftFile)), 4)
	}

	opts := processOptions{InputFile: thriftFile}
	return runTest(t, opts, extraChecks)
}

func runTest(t *testing.T, opts processOptions, extraChecks func(string) error) error {
	tempDir, err := ioutil.TempDir("", "thrift-gen")
	if err != nil {
		return err
	}

	// Generate code from the Thrift file.
	*packagePrefix = "../"
	opts.GenerateThrift = true
	opts.OutputDir = tempDir
	if err := processFile(opts); err != nil {
		return fmt.Errorf("processFile(%s) in %q failed: %v", opts.InputFile, tempDir, err)
	}

	// Create any extra Go files as specified in the Thrift file.
	if err := createAdditionalTestFile(opts.InputFile, tempDir); err != nil {
		return fmt.Errorf("failed creating additional test files for %s in %q: %v", opts.InputFile, tempDir, err)
	}

	// Run go build to ensure that the generated code builds.
	cmd := exec.Command("go", "build", "./...")
	cmd.Dir = tempDir
	// NOTE: we check output, since go build ./... returns 0 status code on failure:
	// https://github.com/golang/go/issues/11407
	if output, err := cmd.CombinedOutput(); err != nil || len(output) > 0 {
		return fmt.Errorf("Build in %q failed.\nError: %v Output:\n%v\n", tempDir, err, string(output))
	}

	// Run any extra checks the user may want.
	if err := extraChecks(tempDir); err != nil {
		return err
	}

	// Only delete the temp directory on success.
	os.RemoveAll(tempDir)
	return nil
}
<commit_msg>Fix lint failure in compile_test (#536)<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"testing"

	"github.com/stretchr/testify/require"
)

// These tests ensure that the code generator generates valid code that can be built
// in combination with Thrift's autogenerated code.

func TestAllThrift(t *testing.T) {
	files, err := ioutil.ReadDir("test_files")
	require.NoError(t, err, "Cannot read test_files directory: %v", err)

	for _, f := range files {
		fname := f.Name()
		if f.IsDir() || filepath.Ext(fname) != ".thrift" {
			continue
		}

		if err := runBuildTest(t, filepath.Join("test_files", fname)); err != nil {
			t.Errorf("Thrift file %v failed: %v", fname, err)
		}
	}
}

func TestIncludeThrift(t *testing.T) {
	dirs, err := ioutil.ReadDir("test_files/include_test")
	require.NoError(t, err, "Cannot read test_files/include_test directory: %v", err)

	for _, d := range dirs {
		dname := d.Name()
		if !d.IsDir() {
			continue
		}

		thriftFile := filepath.Join(dname, path.Base(dname)+".thrift")
		if err := runBuildTest(t, filepath.Join("test_files/include_test/", thriftFile)); err != nil {
			t.Errorf("Thrift test %v failed: %v", dname, err)
		}
	}
}

func TestMultipleFiles(t *testing.T) {
	if err := runBuildTest(t, filepath.Join("test_files", "multi_test", "file1.thrift")); err != nil {
		t.Errorf("Multiple file test failed: %v", err)
	}
}

func TestExternalTemplate(t *testing.T) {
	template1 := `package {{ .Package }}

{{ range .AST.Services }}
// Service {{ .Name }} has {{ len .Methods }} methods.
{{ range .Methods }}
// func {{ .Name | goPublicName }} ({{ range .Arguments }}{{ .Type | goType }}, {{ end }}) ({{ if .ReturnType }}{{ .ReturnType | goType }}{{ end }}){{ end }}
{{ end }}
	`
	templateFile := writeTempFile(t, template1)
	defer os.Remove(templateFile)

	expected := `package service_extend

// Service S1 has 1 methods.

// func M1 ([]byte, ) ([]byte)

// Service S2 has 1 methods.

// func M2 (*S, int32, ) (*S)

// Service S3 has 1 methods.

// func M3 () ()
`

	opts := processOptions{
		InputFile:     "test_files/service_extend.thrift",
		TemplateFiles: []string{templateFile},
	}
	checks := func(dir string) error {
		dir = filepath.Join(dir, "service_extend")
		if err := checkDirectoryFiles(dir, 6); err != nil {
			return err
		}

		// Verify the contents of the extra file.
		outFile := filepath.Join(dir, packageName(templateFile)+"-service_extend.go")
		return verifyFileContents(outFile, expected)
	}
	if err := runTest(t, opts, checks); err != nil {
		t.Errorf("Failed to run test: %v", err)
	}
}

func writeTempFile(t *testing.T, contents string) string {
	tempFile, err := ioutil.TempFile("", "temp")
	require.NoError(t, err, "Failed to create temp file")
	tempFile.Close()
	require.NoError(t, ioutil.WriteFile(tempFile.Name(), []byte(contents), 0666),
		"Write temp file failed")
	return tempFile.Name()
}

func verifyFileContents(filename, expected string) error {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}

	bytesStr := string(bytes)
	if bytesStr != expected {
		return fmt.Errorf("file contents mismatch. got:\n%vexpected:\n%v", bytesStr, expected)
	}

	return nil
}

func copyFile(src, dst string) error {
	f, err := os.Open(src)
	if err != nil {
		return err
	}
	defer f.Close()

	writeF, err := os.OpenFile(dst, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
	if err != nil {
		return err
	}
	defer writeF.Close()

	_, err = io.Copy(writeF, f)
	return err
}

// setupDirectory creates a temporary directory.
func setupDirectory(thriftFile string) (string, error) {
	tempDir, err := ioutil.TempDir("", "thrift-gen")
	if err != nil {
		return "", err
	}

	return tempDir, nil
}

func createAdditionalTestFile(thriftFile, tempDir string) error {
	f, err := os.Open(thriftFile)
	if err != nil {
		return err
	}

	var writer io.Writer
	rdr := bufio.NewReader(f)
	for {
		line, err := rdr.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				return nil
			}
		}

		if strings.HasPrefix(line, "//Go code:") {
			fileName := strings.TrimSpace(strings.TrimPrefix(line, "//Go code:"))
			outFile := filepath.Join(tempDir, fileName)
			f, err := os.OpenFile(outFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
			if err != nil {
				return err
			}
			defer f.Close()
			writer = f
		} else if writer != nil {
			if strings.HasPrefix(line, "//") {
				writer.Write([]byte(strings.TrimPrefix(line, "//")))
			} else {
				return nil
			}
		}
	}
}

func checkDirectoryFiles(dir string, n int) error {
	dirContents, err := ioutil.ReadDir(dir)
	if err != nil {
		return err
	}

	if len(dirContents) < n {
		return fmt.Errorf("expected to generate at least %v files, but found: %v", n, len(dirContents))
	}

	return nil
}

func runBuildTest(t *testing.T, thriftFile string) error {
	extraChecks := func(dir string) error {
		return checkDirectoryFiles(filepath.Join(dir, packageName(thriftFile)), 4)
	}

	opts := processOptions{InputFile: thriftFile}
	return runTest(t, opts, extraChecks)
}

func runTest(t *testing.T, opts processOptions, extraChecks func(string) error) error {
	tempDir, err := ioutil.TempDir("", "thrift-gen")
	if err != nil {
		return err
	}

	// Generate code from the Thrift file.
	*packagePrefix = "../"
	opts.GenerateThrift = true
	opts.OutputDir = tempDir
	if err := processFile(opts); err != nil {
		return fmt.Errorf("processFile(%s) in %q failed: %v", opts.InputFile, tempDir, err)
	}

	// Create any extra Go files as specified in the Thrift file.
	if err := createAdditionalTestFile(opts.InputFile, tempDir); err != nil {
		return fmt.Errorf("failed creating additional test files for %s in %q: %v", opts.InputFile, tempDir, err)
	}

	// Run go build to ensure that the generated code builds.
	cmd := exec.Command("go", "build", "./...")
	cmd.Dir = tempDir
	// NOTE: we check output, since go build ./... returns 0 status code on failure:
	// https://github.com/golang/go/issues/11407
	if output, err := cmd.CombinedOutput(); err != nil || len(output) > 0 {
		return fmt.Errorf("build in %q failed.\nError: %v Output:\n%v", tempDir, err, string(output))
	}

	// Run any extra checks the user may want.
	if err := extraChecks(tempDir); err != nil {
		return err
	}

	// Only delete the temp directory on success.
	os.RemoveAll(tempDir)
	return nil
}
<|endoftext|>


<commit_before>package tris

import (
	"bytes"
	"errors"
	"fmt"
	zmq "github.com/alecthomas/gozmq"
	"github.com/fvbock/trie"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"sync"
	"time"
)

const (
	VERSION = "0.0.2"

	DEFAULT_DB = "0"
)

func init() {
}

type Client struct {
	Id           []byte
	Msg          []byte
	ActiveDbName string
	ActiveDb     *trie.RefCountTrie
	ShowExecTime bool
	// Cmds         []Command
	// Args         [][]interface{}
	// Response     []byte
}

func (c *Client) String() string {
	return fmt.Sprintf("Client ID: %v\nActive Db: %v\n", c.Id, c.ActiveDbName)
}

func NewClient(s *Server, id []byte) *Client {
	return &Client{
		Id:           id,
		ActiveDbName: DEFAULT_DB,
		ActiveDb:     s.Databases[DEFAULT_DB],
		ShowExecTime: false,
	}
}

type Command interface {
	Name() string
	Function(s *Server, c *Client, args ...interface{}) (reply *Reply)
	Flags() int
	ResponseType() int
}

const (
	STATE_STOP    = 1
	STATE_STOPPED = 2
	STATE_RUNNING = 3

	COMMAND_FLAG_READ  = 1
	COMMAND_FLAG_WRITE = 2
	COMMAND_FLAG_ADMIN = 4

	COMMAND_REPLY_EMPTY  = 0
	COMMAND_REPLY_SINGLE = 1
	COMMAND_REPLY_MULTI  = 2
	COMMAND_REPLY_NONE   = 3

	COMMAND_OK   = 0
	COMMAND_FAIL = 1
)

type Server struct {
	sync.RWMutex
	Log              *log.Logger
	Config           *ServerConfig
	Commands         map[string]Command
	Databases        map[string]*trie.RefCountTrie
	DatabaseOpCount  map[string]int
	State            int
	Stateswitch      chan int
	CycleLength      int64
	cycleTicker      <-chan time.Time
	CheckStateChange time.Duration

	// zeromq
	Context   *zmq.Context
	Socket    *zmq.Socket
	pollItems zmq.PollItems

	// CommandQueue  chan *Client
	ActiveClients     map[string]*Client
	InactiveClientIds chan string
	RequestsRunning   int
	CommandsProcessed int
}

func New(config *ServerConfig) (s *Server, err error) {
	s = &Server{
		Config: config,
		// server
		Commands:          make(map[string]Command),
		Databases:         make(map[string]*trie.RefCountTrie),
		Stateswitch:       make(chan int, 1),
		CycleLength:       int64(time.Microsecond) * 500,
		CheckStateChange:  time.Second * 1,
		ActiveClients:     make(map[string]*Client),
		InactiveClientIds: make(chan string),
		Log:               log.New(os.Stderr, "", log.LstdFlags),
		// stats
		RequestsRunning:   0,
		CommandsProcessed: 0,
	}
	s.Initialize()
	return
}

func (s *Server) Initialize() {
	// register commands
	TrisCommands = append(TrisCommands, &CommandInfo{})
	TrisCommands = append(TrisCommands, &CommandExit{})
	TrisCommands = append(TrisCommands, &CommandPing{})
	TrisCommands = append(TrisCommands, &CommandSave{})
	TrisCommands = append(TrisCommands, &CommandImportDb{})
	TrisCommands = append(TrisCommands, &CommandSelect{})
	TrisCommands = append(TrisCommands, &CommandCreateTrie{})
	// TrisCommands = append(TrisCommands, &CommandFlushTrie{})
	// TrisCommands = append(TrisCommands, &CommandDropTrie{})
	TrisCommands = append(TrisCommands, &CommandAdd{})
	TrisCommands = append(TrisCommands, &CommandDel{})
	TrisCommands = append(TrisCommands, &CommandHas{})
	TrisCommands = append(TrisCommands, &CommandHasCount{})
	TrisCommands = append(TrisCommands, &CommandHasPrefix{})
	TrisCommands = append(TrisCommands, &CommandMembers{})
	TrisCommands = append(TrisCommands, &CommandPrefixMembers{})
	TrisCommands = append(TrisCommands, &CommandTree{})
	TrisCommands = append(TrisCommands, &CommandTiming{})
	s.RegisterCommands(TrisCommands...)

	//

	dataFiles, err := ioutil.ReadDir(s.Config.DataDir)
	if err != nil {

	}
	for _, f := range dataFiles {
		if !f.IsDir() {
			err := s.loadDataFile(f.Name())
			if err != nil {
				s.Log.Printf("Error loading trie file %s: %v\n", f.Name(), err)
			}
		}

	}

	s.Databases[DEFAULT_DB] = trie.NewRefCountTrie()
}

func (s *Server) loadDataFile(fname string) (err error) {
	if len(fname) > len(s.Config.StorageFilePrefix) && fname[0:len(s.Config.StorageFilePrefix)] == s.Config.StorageFilePrefix {
		id := strings.Split(fname, s.Config.StorageFilePrefix)[1]
		s.Log.Printf("Loading Trie %s\n", id)
		var tr *trie.RefCountTrie
		tr, err = trie.RCTLoadFromFile(fmt.Sprintf("%s/%s%s", s.Config.DataDir, s.Config.StorageFilePrefix, id))
		if err != nil {
			return
		}
		s.Databases[id] = tr
	} else {
		err = errors.New("")
	}
	return
}

func (s *Server) RegisterCommands(cmds ...Command) (err error) {
	for _, c := range cmds {
		if _, exists := s.Commands[c.Name()]; exists {
			err = errors.New(fmt.Sprintf("Command %s has already been registered.", c.Name()))
			return
		}
		// s.Log.Println("Registering command", c.Name())
		s.Commands[c.Name()] = c
	}
	return
}

func (s *Server) Start() (err error) {
	s.Stateswitch <- STATE_RUNNING
	go func(s *Server) {
		s.Log.Println("Starting server...")
		s.Context, err = zmq.NewContext()
		if err != nil {

		}
		s.Socket, err = s.Context.NewSocket(zmq.ROUTER)
		if err != nil {

		}
		s.Socket.SetSockOptInt(zmq.LINGER, 0)
		s.Log.Println(fmt.Sprintf("Binding to %s://%s:%v", s.Config.Protocol, s.Config.Host, s.Config.Port))
		s.Socket.Bind(fmt.Sprintf("%s://%s:%v", s.Config.Protocol, s.Config.Host, s.Config.Port))
		s.Log.Println("Server started...")

		s.pollItems = zmq.PollItems{
			zmq.PollItem{Socket: s.Socket, Events: zmq.POLLIN},
		}

		var cycleLength int64
		var cycleStart time.Time
		s.cycleTicker = time.Tick(time.Duration(s.CycleLength) * time.Nanosecond)
		stateTicker := time.Tick(s.CheckStateChange)
	mainLoop:
		for {
			cycleStart = time.Now()

			// make the poller run in a sep goroutine and push to a channel?
			if s.RequestsRunning > 0 {
				_, _ = zmq.Poll(s.pollItems, 1)
			} else {
				// _, _ = zmq.Poll(s.pollItems, -1)
				_, _ = zmq.Poll(s.pollItems, 1000000)
			}
			switch {
			case s.pollItems[0].REvents&zmq.POLLIN != 0:
				s.Lock()
				msgParts, _ := s.pollItems[0].Socket.RecvMultipart(0)
				s.RequestsRunning++
				s.Unlock()
				go s.HandleRequest(msgParts)
			default:
				select {
				case <-stateTicker:
					select {
					case s.State = <-s.Stateswitch:
						s.Log.Println("state changed:", s.State)
						if s.State == STATE_STOP {
							break mainLoop
						}
						if s.State == STATE_RUNNING {
						}
					default:
						time.Sleep(1)
					}
				default:
					// s.Log.Println(".")
				}
			}
			s.beforeSleep()
			cycleLength = time.Now().UnixNano() - cycleStart.UnixNano()
			if cycleLength < s.CycleLength {
				d := (s.CycleLength - cycleLength)
				time.Sleep(time.Duration(d) * time.Nanosecond)
			}
		}
		s.prepareShutdown()
		s.Log.Println("Server stopped running...")
		s.State = STATE_STOPPED
	}(s)
	s.Log.Println("Server starting...")
	return
}

func (s *Server) beforeSleep() {
beforeSleepCycle:
	for {
		select {
		case <-s.cycleTicker:
			break beforeSleepCycle
		case cId := <-s.InactiveClientIds:
			delete(s.ActiveClients, cId)
			continue
		default:
			break
		}
	}
	return
}

func (s *Server) dbExists(name string) bool {
	if _, exists := s.Databases[name]; !exists {
		return false
	}
	return true
}

func splitMsgs(payload []byte) (cmds []string, args [][]interface{}, err error) {
	msgs := bytes.Split(bytes.Trim(payload, " "), []byte("\n"))
	for n, msg := range msgs {
		parts := bytes.Split(bytes.Trim(msg, " "), []byte(" "))
		for i, p := range parts {
			if len(p) == 0 {
				continue
			}
			if i == 0 {
				cmds = append(cmds, string(p))
				args = append(args, make([]interface{}, 0))
			} else {
				args[n] = append(args[n], string(p))
			}
		}
	}
	return
}

func (s *Server) HandleRequest(msgParts [][]byte) {
	clientKey := string(msgParts[0])
	var c *Client
	var unknown bool
	if c, unknown = s.ActiveClients[clientKey]; !unknown {
		s.ActiveClients[clientKey] = NewClient(s, msgParts[0])
		c = s.ActiveClients[clientKey]
	}
	var execStart time.Time
	if c.ShowExecTime {
		execStart = time.Now()
	}

	cmds, args, err := splitMsgs(msgParts[2])
	if err != nil {
		// TODO
	}

	// var retCode int
	var reply *Reply
	var replies []*Reply

	for i, cmd := range cmds {
		var cmdName string = strings.ToUpper(cmd)
		if _, exists := s.Commands[cmdName]; !exists {
			// handle non existing command call
			reply = NewReply(
				[][]byte{[]byte(fmt.Sprintf("Unknown Command %s.", cmd))},
				COMMAND_FAIL)
		} else {
			reply = s.Commands[cmdName].Function(s, c, args[i]...)
			if reply.ReturnCode != COMMAND_OK {
				s.Log.Println(string(reply.Payload[0]))
			}
		}
		replies = append(replies, reply)
		s.Lock()
		s.CommandsProcessed += 1
		s.Unlock()
	}

	var response []byte
	for rn, rep := range replies {
		response = append(response, rep.Serialize()...)
		if rn > 0 {
			response = append(response, []byte("\n")...)
		}
	}
	s.Lock()
	s.pollItems[0].Socket.SendMultipart([][]byte{c.Id, []byte(""), response}, 0)
	// stats
	s.RequestsRunning--
	s.Unlock()
	if c.ShowExecTime {
		s.Log.Printf("%s %v took %v\n", cmds, args, time.Since(execStart))
	}
	// TODO: count db write operations
}

/*
Take care of stuff...
*/
func (s *Server) prepareShutdown() {
	s.Log.Println("Preparing server shutdown...")
}

func (s *Server) Stop() {
	s.Log.Println("Stopping server.")
	s.Stateswitch <- STATE_STOP
	for s.State != STATE_STOPPED {
		time.Sleep(100 * time.Millisecond)
	}
	s.Log.Println("Server teardown.")
	s.Socket.Close()
	s.Log.Println("Socket closed.")
	s.Context.Close()
	s.Log.Println("Context closed.")
	s.Log.Println("Stopped server.")
}
<commit_msg>add dbinfo command<commit_after>package tris

import (
	"bytes"
	"errors"
	"fmt"
	zmq "github.com/alecthomas/gozmq"
	"github.com/fvbock/trie"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"sync"
	"time"
)

const (
	VERSION = "0.0.2"

	DEFAULT_DB = "0"
)

func init() {
}

type Client struct {
	Id           []byte
	Msg          []byte
	ActiveDbName string
	ActiveDb     *trie.RefCountTrie
	ShowExecTime bool
	// Cmds         []Command
	// Args         [][]interface{}
	// Response     []byte
}

func (c *Client) String() string {
	return fmt.Sprintf("Client ID: %v\nActive Db: %v\n", c.Id, c.ActiveDbName)
}

func NewClient(s *Server, id []byte) *Client {
	return &Client{
		Id:           id,
		ActiveDbName: DEFAULT_DB,
		ActiveDb:     s.Databases[DEFAULT_DB],
		ShowExecTime: false,
	}
}

type Command interface {
	Name() string
	Function(s *Server, c *Client, args ...interface{}) (reply *Reply)
	Flags() int
	ResponseType() int
}

const (
	STATE_STOP    = 1
	STATE_STOPPED = 2
	STATE_RUNNING = 3

	COMMAND_FLAG_READ  = 1
	COMMAND_FLAG_WRITE = 2
	COMMAND_FLAG_ADMIN = 4

	COMMAND_REPLY_EMPTY  = 0
	COMMAND_REPLY_SINGLE = 1
	COMMAND_REPLY_MULTI  = 2
	COMMAND_REPLY_NONE   = 3

	COMMAND_OK   = 0
	COMMAND_FAIL = 1
)

type Server struct {
	sync.RWMutex
	Log              *log.Logger
	Config           *ServerConfig
	Commands         map[string]Command
	Databases        map[string]*trie.RefCountTrie
	DatabaseOpCount  map[string]int
	State            int
	Stateswitch      chan int
	CycleLength      int64
	cycleTicker      <-chan time.Time
	CheckStateChange time.Duration

	// zeromq
	Context   *zmq.Context
	Socket    *zmq.Socket
	pollItems zmq.PollItems

	// CommandQueue  chan *Client
	ActiveClients     map[string]*Client
	InactiveClientIds chan string
	RequestsRunning   int
	CommandsProcessed int
}

func New(config *ServerConfig) (s *Server, err error) {
	s = &Server{
		Config: config,
		// server
		Commands:          make(map[string]Command),
		Databases:         make(map[string]*trie.RefCountTrie),
		Stateswitch:       make(chan int, 1),
		CycleLength:       int64(time.Microsecond) * 500,
		CheckStateChange:  time.Second * 1,
		ActiveClients:     make(map[string]*Client),
		InactiveClientIds: make(chan string),
		Log:               log.New(os.Stderr, "", log.LstdFlags),
		// stats
		RequestsRunning:   0,
		CommandsProcessed: 0,
	}
	s.Initialize()
	return
}

func (s *Server) Initialize() {
	// register commands
	TrisCommands = append(TrisCommands, &CommandInfo{})
	TrisCommands = append(TrisCommands, &CommandDbInfo{})
	TrisCommands = append(TrisCommands, &CommandExit{})
	TrisCommands = append(TrisCommands, &CommandPing{})
	TrisCommands = append(TrisCommands, &CommandSave{})
	TrisCommands = append(TrisCommands, &CommandImportDb{})
	TrisCommands = append(TrisCommands, &CommandSelect{})
	TrisCommands = append(TrisCommands, &CommandCreateTrie{})
	// TrisCommands = append(TrisCommands, &CommandFlushTrie{})
	// TrisCommands = append(TrisCommands, &CommandDropTrie{})
	TrisCommands = append(TrisCommands, &CommandAdd{})
	TrisCommands = append(TrisCommands, &CommandDel{})
	TrisCommands = append(TrisCommands, &CommandHas{})
	TrisCommands = append(TrisCommands, &CommandHasCount{})
	TrisCommands = append(TrisCommands, &CommandHasPrefix{})
	TrisCommands = append(TrisCommands, &CommandMembers{})
	TrisCommands = append(TrisCommands, &CommandPrefixMembers{})
	TrisCommands = append(TrisCommands, &CommandTree{})
	TrisCommands = append(TrisCommands, &CommandTiming{})
	s.RegisterCommands(TrisCommands...)

	//

	dataFiles, err := ioutil.ReadDir(s.Config.DataDir)
	if err != nil {

	}
	for _, f := range dataFiles {
		if !f.IsDir() {
			err := s.loadDataFile(f.Name())
			if err != nil {
				s.Log.Printf("Error loading trie file %s: %v\n", f.Name(), err)
			}
		}

	}

	s.Databases[DEFAULT_DB] = trie.NewRefCountTrie()
}

func (s *Server) loadDataFile(fname string) (err error) {
	if len(fname) > len(s.Config.StorageFilePrefix) && fname[0:len(s.Config.StorageFilePrefix)] == s.Config.StorageFilePrefix {
		id := strings.Split(fname, s.Config.StorageFilePrefix)[1]
		s.Log.Printf("Loading Trie %s\n", id)
		var tr *trie.RefCountTrie
		tr, err = trie.RCTLoadFromFile(fmt.Sprintf("%s/%s%s", s.Config.DataDir, s.Config.StorageFilePrefix, id))
		if err != nil {
			return
		}
		s.Databases[id] = tr
	} else {
		err = errors.New("")
	}
	return
}

func (s *Server) RegisterCommands(cmds ...Command) (err error) {
	for _, c := range cmds {
		if _, exists := s.Commands[c.Name()]; exists {
			err = errors.New(fmt.Sprintf("Command %s has already been registered.", c.Name()))
			return
		}
		// s.Log.Println("Registering command", c.Name())
		s.Commands[c.Name()] = c
	}
	return
}

func (s *Server) Start() (err error) {
	s.Stateswitch <- STATE_RUNNING
	go func(s *Server) {
		s.Log.Println("Starting server...")
		s.Context, err = zmq.NewContext()
		if err != nil {

		}
		s.Socket, err = s.Context.NewSocket(zmq.ROUTER)
		if err != nil {

		}
		s.Socket.SetSockOptInt(zmq.LINGER, 0)
		s.Log.Println(fmt.Sprintf("Binding to %s://%s:%v", s.Config.Protocol, s.Config.Host, s.Config.Port))
		s.Socket.Bind(fmt.Sprintf("%s://%s:%v", s.Config.Protocol, s.Config.Host, s.Config.Port))
		s.Log.Println("Server started...")

		s.pollItems = zmq.PollItems{
			zmq.PollItem{Socket: s.Socket, Events: zmq.POLLIN},
		}

		var cycleLength int64
		var cycleStart time.Time
		s.cycleTicker = time.Tick(time.Duration(s.CycleLength) * time.Nanosecond)
		stateTicker := time.Tick(s.CheckStateChange)
	mainLoop:
		for {
			cycleStart = time.Now()

			// make the poller run in a sep goroutine and push to a channel?
			if s.RequestsRunning > 0 {
				_, _ = zmq.Poll(s.pollItems, 1)
			} else {
				// _, _ = zmq.Poll(s.pollItems, -1)
				_, _ = zmq.Poll(s.pollItems, 1000000)
			}
			switch {
			case s.pollItems[0].REvents&zmq.POLLIN != 0:
				s.Lock()
				msgParts, _ := s.pollItems[0].Socket.RecvMultipart(0)
				s.RequestsRunning++
				s.Unlock()
				go s.HandleRequest(msgParts)
			default:
				select {
				case <-stateTicker:
					select {
					case s.State = <-s.Stateswitch:
						s.Log.Println("state changed:", s.State)
						if s.State == STATE_STOP {
							break mainLoop
						}
						if s.State == STATE_RUNNING {
						}
					default:
						time.Sleep(1)
					}
				default:
					// s.Log.Println(".")
				}
			}
			s.beforeSleep()
			cycleLength = time.Now().UnixNano() - cycleStart.UnixNano()
			if cycleLength < s.CycleLength {
				d := (s.CycleLength - cycleLength)
				time.Sleep(time.Duration(d) * time.Nanosecond)
			}
		}
		s.prepareShutdown()
		s.Log.Println("Server stopped running...")
		s.State = STATE_STOPPED
	}(s)
	s.Log.Println("Server starting...")
	return
}

func (s *Server) beforeSleep() {
beforeSleepCycle:
	for {
		select {
		case <-s.cycleTicker:
			break beforeSleepCycle
		case cId := <-s.InactiveClientIds:
			delete(s.ActiveClients, cId)
			continue
		default:
			break
		}
	}
	return
}

func (s *Server) dbExists(name string) bool {
	if _, exists := s.Databases[name]; !exists {
		return false
	}
	return true
}

func splitMsgs(payload []byte) (cmds []string, args [][]interface{}, err error) {
	msgs := bytes.Split(bytes.Trim(payload, " "), []byte("\n"))
	for n, msg := range msgs {
		parts := bytes.Split(bytes.Trim(msg, " "), []byte(" "))
		for i, p := range parts {
			if len(p) == 0 {
				continue
			}
			if i == 0 {
				cmds = append(cmds, string(p))
				args = append(args, make([]interface{}, 0))
			} else {
				args[n] = append(args[n], string(p))
			}
		}
	}
	return
}

func (s *Server) HandleRequest(msgParts [][]byte) {
	clientKey := string(msgParts[0])
	var c *Client
	var unknown bool
	if c, unknown = s.ActiveClients[clientKey]; !unknown {
		s.ActiveClients[clientKey] = NewClient(s, msgParts[0])
		c = s.ActiveClients[clientKey]
	}
	var execStart time.Time
	if c.ShowExecTime {
		execStart = time.Now()
	}

	cmds, args, err := splitMsgs(msgParts[2])
	if err != nil {
		// TODO
	}

	// var retCode int
	var reply *Reply
	var replies []*Reply

	for i, cmd := range cmds {
		var cmdName string = strings.ToUpper(cmd)
		if _, exists := s.Commands[cmdName]; !exists {
			// handle non existing command call
			reply = NewReply(
				[][]byte{[]byte(fmt.Sprintf("Unknown Command %s.", cmd))},
				COMMAND_FAIL)
		} else {
			reply = s.Commands[cmdName].Function(s, c, args[i]...)
			if reply.ReturnCode != COMMAND_OK {
				s.Log.Println(string(reply.Payload[0]))
			}
		}
		replies = append(replies, reply)
		s.Lock()
		s.CommandsProcessed += 1
		s.Unlock()
	}

	var response []byte
	for rn, rep := range replies {
		response = append(response, rep.Serialize()...)
		if rn > 0 {
			response = append(response, []byte("\n")...)
		}
	}
	s.Lock()
	s.pollItems[0].Socket.SendMultipart([][]byte{c.Id, []byte(""), response}, 0)
	// stats
	s.RequestsRunning--
	s.Unlock()
	if c.ShowExecTime {
		s.Log.Printf("%s %v took %v\n", cmds, args, time.Since(execStart))
	}
	// TODO: count db write operations
}

/*
Take care of stuff...
*/
func (s *Server) prepareShutdown() {
	s.Log.Println("Preparing server shutdown...")
}

func (s *Server) Stop() {
	s.Log.Println("Stopping server.")
	s.Stateswitch <- STATE_STOP
	for s.State != STATE_STOPPED {
		time.Sleep(100 * time.Millisecond)
	}
	s.Log.Println("Server teardown.")
	s.Socket.Close()
	s.Log.Println("Socket closed.")
	s.Context.Close()
	s.Log.Println("Context closed.")
	s.Log.Println("Stopped server.")
}
<|endoftext|>


<commit_before>package mgo

import (
	. "launchpad.net/gocheck"
	"net"
        "runtime"
)

type ServerSuite struct {
}

var _ = Suite(&ServerSuite{})

func (s *ServerSuite) TestCloseDuringConnect(c *C) {
	var server *mongoServer
	closeDial := func(addr net.Addr) (net.Conn, error) {
		// The first call to this will be during newServer, and
		// server will be nil. Once it returns, the second call
		// will be with a valid server, and we will Close it.
		if server != nil {
			server.Close()
		}
		return net.DialTCP("tcp", nil, addr.(*net.TCPAddr))
	}
	localhostServer, err := net.Listen("tcp", "localhost:0")
	c.Assert(err, IsNil)
	defer localhostServer.Close()
	go func() {
		// Accept a connection but don't do anything with it
		for {
			conn, err := localhostServer.Accept()
			logf("got connection: %v", conn)
			if err != nil {
				return
			}
			conn.Close()
		}
	}()
	tcpaddr := localhostServer.Addr().(*net.TCPAddr)
	server = newServer(tcpaddr.String(), tcpaddr, make(chan bool), closeDial)
	c.Assert(server, NotNil)
	// It is possible for newServer to ping the remote host, and the
	// request returns immediately (because writing to the socket fails).
	// In which case pinger(loop=false) puts the closed socket back into
	// unused. We have to wait until readLoop gets a EOF and removes the
	// socket from the queue.
	for {
		server.RLock()
		count := len(server.unusedSockets)
		server.RUnlock()
		if count == 0 {
			break
		}
                runtime.Gosched()
	}
	conn, _, err := server.AcquireSocket(0)
	c.Check(err, Equals, errServerClosed)
	c.Assert(conn, IsNil)
}
<commit_msg>Remove the whitebox test of concurrency handling.<commit_after><|endoftext|>


<commit_before>package main

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

const (
	TEST_ENDPOINT = "localhost:9999"
	TEST_DB       = "goslow_test"
)

var DATA_SOURCE = map[string]string{
	"sqlite3":  ":memory:",
	"postgres": "postgres://localhost/" + TEST_DB,
}

type TestCase struct {
	createDefaultRules  bool
	singleDomainUrlPath string
	driver              string
	dataSource          string
}

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

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

type TestCases []*TestCase

type CheckFunc func(*testing.T, *httptest.Server, *TestCase)

var (
	defaultTestCases = TestCases{
		NewTestCase(true, "", "sqlite3"),
		NewTestCase(true, "", "postgres"),
	}

	// TODO: remove duplication
	ruleCreationTestCases = TestCases{
		NewTestCase(true, "", "sqlite3"),
		NewTestCase(true, "", "postgres"),

		NewTestCase(false, "/goslow", "sqlite3"),
		NewTestCase(false, "/goslow", "postgres"),

		NewTestCase(false, "/goslow/", "sqlite3"),
		NewTestCase(false, "/goslow/", "postgres"),

		NewTestCase(false, "/te", "sqlite3"),
		NewTestCase(false, "/te", "postgres"),

		NewTestCase(false, "/te/", "sqlite3"),
		NewTestCase(false, "/te/", "postgres"),

		NewTestCase(false, "/composite/path", "sqlite3"),
		NewTestCase(false, "/composite/path", "postgres"),
	}
)

func TestZeroSite(t *testing.T) {
	for _, testCase := range runnable(defaultTestCases) {
		run(t, checkZeroSite, testCase)
	}
}

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

func run(t *testing.T, checkFunc CheckFunc, testCase *TestCase) {
	if testCase.driver == "postgres" {
		createDb(TEST_DB)
		defer dropDb(TEST_DB)
	}
	server, goSlowServer := newSubDomainServer(testCase)
	defer goSlowServer.storage.db.Close()
	defer server.Close()
	checkFunc(t, server, testCase)
}

func checkZeroSite(t *testing.T, server *httptest.Server, testCase *TestCase) {
	shouldBeEqual(t, readBody(GET(server.URL, "/", makeHost("0", TEST_ENDPOINT))), DEFAULT_BODY)
}

func TestRedefineBuiltinSites(t *testing.T) {
	for _, testCase := range runnable(defaultTestCases) {
		run(t, checkRedefineBuiltinSites, testCase)
	}
}

func checkRedefineBuiltinSites(t *testing.T, server *httptest.Server, testCase *TestCase) {
	addRule(t, server, &Rule{Site: "0", Path: "/test", Body: []byte("hop"), Method: "GET"}, http.StatusForbidden)
}

func TestDelay(t *testing.T) {
	for _, testCase := range runnable(defaultTestCases) {
		run(t, checkDelay, testCase)
	}
}

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

func TestStatus(t *testing.T) {
	for _, testCase := range runnable(defaultTestCases) {
		run(t, checkStatus, testCase)
	}
}

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

func TestRuleCreation(t *testing.T) {
	for _, testCase := range runnable(ruleCreationTestCases) {
		run(t, checkRuleCreationTestCase, testCase)
	}
}

func checkRuleCreationTestCase(t *testing.T, server *httptest.Server, testCase *TestCase) {
	prefix := testCase.singleDomainUrlPath
	site := ""
	if prefix == "" {
		site = newSite(server, join(prefix, "/"), "haha")
	} else {
		addRule(t, server, &Rule{Path: join(prefix, "/"), Body: []byte("haha")}, 200)
	}
	shouldBeEqual(t, readBody(GET(server.URL, "/", site)), []byte("haha"))
	addRule(t, server, &Rule{Site: site, Path: join(prefix, "/test"), Body: []byte("hop"), Method: "GET"}, 200)
	shouldBeEqual(t, readBody(GET(server.URL, "/test", site)), []byte("hop"))
	resp := POST(server.URL, "/test", site, "")
	intShouldBeEqual(t, 404, resp.StatusCode)
	addRule(t, server, &Rule{Site: site, Path: join(prefix, "/test"), Body: []byte("for POST"), Method: "POST",
		Delay: time.Duration(100) * time.Millisecond}, 200)
	shouldBeEqual(t, readBody(GET(server.URL, "/test", site)), []byte("hop"))
	shouldBeEqual(t, readBody(POST(server.URL, "/test", site, "")), []byte("for POST"))
	shouldRespondIn(t, createPOST(server.URL, "/test", site, ""), 0.1, 0.15)
}

func newSubDomainServer(testCase *TestCase) (*httptest.Server, *Server) {
	config := DEFAULT_CONFIG // copies DEFAULT_CONFIG
	config.endpoint = TEST_ENDPOINT
	config.createDefaultRules = testCase.createDefaultRules
	config.singleDomainUrlPath = testCase.singleDomainUrlPath
	if testCase.driver != "" {
		config.driver = testCase.driver
		config.dataSource = testCase.dataSource
	}
	handler := NewServer(&config)
	return httptest.NewServer(handler), handler
}

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 {
	req, err := http.NewRequest("GET", url+path, nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Host = host
	return req
}

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

func makeHost(subdomain, host string) string {
	return fmt.Sprintf("%s.%s", subdomain, host)
}

func shouldBeEqual(t *testing.T, expected, actual []byte) {
	if string(expected) != string(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, min, max float64) {
	start := time.Now()
	resp := do(req)
	readBody(resp)
	duration := time.Since(start)
	minDuration := toDuration(min)
	maxDuration := toDuration(max)
	if duration > maxDuration || minDuration > duration {
		t.Fatalf("%s%s answered in %v. Not in the interval [%v; %v]",
			req.Host, req.URL.Path, duration, minDuration, maxDuration)
	}
}

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

func newSite(server *httptest.Server, path, response string) string {
	resp := POST(server.URL, fmt.Sprintf("%s?output=short&method=GET", path),
		makeHost("create", TEST_ENDPOINT), response)
	return string(readBody(resp))
}

func POST(url, path, host, payload string) *http.Response {
	log.Printf("posting %s", path)
	req := createPOST(url, path, host, payload)
	return do(req)
}

func createPOST(url, path, host, payload string) *http.Request {
	req, err := http.NewRequest("POST", url+path, strings.NewReader(payload))
	if err != nil {
		log.Fatal(err)
	}
	req.Host = host
	return req
}

func addRule(t *testing.T, server *httptest.Server, rule *Rule, statusCode int) {
	path := rule.Path
	path += "?method=" + rule.Method
	path += fmt.Sprintf("&delay=%f", rule.Delay.Seconds())
	resp := POST(server.URL, path, makeHost("admin-"+rule.Site, TEST_ENDPOINT),
		string(rule.Body))
	intShouldBeEqual(t, statusCode, resp.StatusCode)
}

func join(elem ...string) string {
	shouldEndWithSlash := strings.HasSuffix(elem[len(elem)-1], "/")
	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>Refactor server_test.go<commit_after>package main

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

const (
	TEST_ENDPOINT = "localhost:9999"
	TEST_DB       = "goslow_test"
)

var DATA_SOURCE = map[string]string{
	"sqlite3":  ":memory:",
	"postgres": "postgres://localhost/" + TEST_DB,
}

type TestCase struct {
	createDefaultRules  bool
	singleDomainUrlPath string
	driver              string
	dataSource          string
}

type TestCases []*TestCase

type CheckFunc func(*testing.T, *httptest.Server, *TestCase)

var (
	defaultTestCases = TestCases{
		NewTestCase(true, "", "sqlite3"),
		NewTestCase(true, "", "postgres"),
	}

	// TODO: remove duplication
	ruleCreationTestCases = TestCases{
		NewTestCase(true, "", "sqlite3"),
		NewTestCase(true, "", "postgres"),

		NewTestCase(false, "/goslow", "sqlite3"),
		NewTestCase(false, "/goslow", "postgres"),

		NewTestCase(false, "/goslow/", "sqlite3"),
		NewTestCase(false, "/goslow/", "postgres"),

		NewTestCase(false, "/te", "sqlite3"),
		NewTestCase(false, "/te", "postgres"),

		NewTestCase(false, "/te/", "sqlite3"),
		NewTestCase(false, "/te/", "postgres"),

		NewTestCase(false, "/composite/path", "sqlite3"),
		NewTestCase(false, "/composite/path", "postgres"),
	}
)

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

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

func TestZeroSite(t *testing.T) {
	for _, testCase := range runnable(defaultTestCases) {
		run(t, checkZeroSite, testCase)
	}
}

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

func run(t *testing.T, checkFunc CheckFunc, testCase *TestCase) {
	if testCase.driver == "postgres" {
		createDb(TEST_DB)
		defer dropDb(TEST_DB)
	}
	goSlowServer := newSubDomainServer(testCase)
	server := httptest.NewServer(goSlowServer)
	defer server.Close()
	defer goSlowServer.storage.db.Close()
	checkFunc(t, server, testCase)
}

func checkZeroSite(t *testing.T, server *httptest.Server, testCase *TestCase) {
	bytesShouldBeEqual(t,
		readBody(GET(server.URL, "/", makeHost("0", TEST_ENDPOINT))),
		DEFAULT_BODY)
}

func TestRedefineBuiltinSites(t *testing.T) {
	for _, testCase := range runnable(defaultTestCases) {
		run(t, checkRedefineBuiltinSites, testCase)
	}
}

func checkRedefineBuiltinSites(t *testing.T, server *httptest.Server, testCase *TestCase) {
	for _, site := range []string{"0", "99", "500", "create"} {
		resp := addRule(server, &Rule{Site: site, Path: "/test", Body: []byte("hop"), Method: "GET"})
		shouldHaveStatusCode(t, http.StatusForbidden, resp)
	}
}

func TestDelay(t *testing.T) {
	for _, testCase := range runnable(defaultTestCases) {
		run(t, checkDelay, testCase)
	}
}

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

func TestStatus(t *testing.T) {
	for _, testCase := range runnable(defaultTestCases) {
		run(t, checkStatus, testCase)
	}
}

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

func TestRuleCreation(t *testing.T) {
	for _, testCase := range runnable(ruleCreationTestCases) {
		run(t, checkRuleCreationTestCase, testCase)
	}
}

// TODO: refactor
func checkRuleCreationTestCase(t *testing.T, server *httptest.Server, testCase *TestCase) {
	prefix := testCase.singleDomainUrlPath
	site := ""
	if prefix == "" {
		site = newSite(server, join(prefix, "/"), []byte("haha"))
	} else {
		resp := addRule(server, &Rule{Path: join(prefix, "/"), Body: []byte("haha")})
		shouldHaveStatusCode(t, http.StatusOK, resp)
	}
	bytesShouldBeEqual(t, readBody(GET(server.URL, "/", site)), []byte("haha"))
	resp := addRule(server, &Rule{Site: site, Path: join(prefix, "/test"), Body: []byte("hop"), Method: "GET"})
	shouldHaveStatusCode(t, http.StatusOK, resp)

	bytesShouldBeEqual(t, readBody(GET(server.URL, "/test", site)), []byte("hop"))
	resp = POST(server.URL, "/test", site, []byte(""))
	intShouldBeEqual(t, 404, resp.StatusCode)
	resp = addRule(server, &Rule{Site: site, Path: join(prefix, "/test"), Body: []byte("for POST"), Method: "POST",
		Delay: time.Duration(100) * time.Millisecond})
	shouldHaveStatusCode(t, http.StatusOK, resp)
	bytesShouldBeEqual(t, readBody(GET(server.URL, "/test", site)), []byte("hop"))
	bytesShouldBeEqual(t, readBody(POST(server.URL, "/test", site, []byte(""))), []byte("for POST"))
	shouldRespondIn(t, createPOST(server.URL, "/test", site, []byte("")), 0.1, 0.15)
}

func newSubDomainServer(testCase *TestCase) *Server {
	config := DEFAULT_CONFIG // copies DEFAULT_CONFIG
	config.endpoint = TEST_ENDPOINT
	config.createDefaultRules = testCase.createDefaultRules
	config.singleDomainUrlPath = testCase.singleDomainUrlPath
	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 {
	req, err := http.NewRequest("GET", url+path, nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Host = host
	return req
}

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

func makeHost(subdomain, host string) string {
	return fmt.Sprintf("%s.%s", subdomain, host)
}

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)
	readBody(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 newSite(server *httptest.Server, path string, response []byte) string {
	resp := POST(server.URL, fmt.Sprintf("%s?output=short&method=GET", path),
		makeHost("create", TEST_ENDPOINT), response)
	return string(readBody(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 {
	req, err := http.NewRequest("POST", url+path, bytes.NewReader(payload))
	if err != nil {
		log.Fatal(err)
	}
	req.Host = host
	return req
}

// TODO: use normal GET-parameters builder, not Sprintf and string concatenation
func addRule(server *httptest.Server, rule *Rule) *http.Response {
	path := rule.Path
	path += "?method=" + rule.Method
	path += fmt.Sprintf("&delay=%f", rule.Delay.Seconds())
	return POST(server.URL, path, makeHost("admin-"+rule.Site, TEST_ENDPOINT),
		rule.Body)
}

// 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><commit_msg>Made the leaktest find the leak.<commit_after><|endoftext|>


<commit_before>//===- ir_test.go - Tests for ir ------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file tests bindings for the ir component.
//
//===----------------------------------------------------------------------===//

package llvm

import (
	"strings"
	"testing"
)

func testAttribute(t *testing.T, name string) {
	mod := NewModule("")
	defer mod.Dispose()

	ftyp := FunctionType(VoidType(), nil, false)
	fn := AddFunction(mod, "foo", ftyp)

	kind := AttributeKindID(name)
	attr := mod.Context().CreateEnumAttribute(kind, 0)

	fn.AddFunctionAttr(attr)
	newattr := fn.GetEnumFunctionAttribute(kind)
	if attr != newattr {
		t.Errorf("got attribute mask %d, want %d", newattr, attr)
	}

	text := mod.String()
	if !strings.Contains(text, " "+name+" ") {
		t.Errorf("expected attribute '%s', got:\n%s", name, text)
	}

	fn.RemoveEnumFunctionAttribute(kind)
	newattr = fn.GetEnumFunctionAttribute(kind)
	if !newattr.IsNil() {
		t.Errorf("got attribute mask %d, want 0", newattr)
	}
}

func TestAttributes(t *testing.T) {
	// Tests that our attribute constants haven't drifted from LLVM's.
	attrTests := []string{
		"sanitize_address",
		"alwaysinline",
		"builtin",
		"byval",
		"convergent",
		"inalloca",
		"inlinehint",
		"inreg",
		"jumptable",
		"minsize",
		"naked",
		"nest",
		"noalias",
		"nobuiltin",
		"nocapture",
		"noduplicate",
		"noimplicitfloat",
		"noinline",
		"nonlazybind",
		"nonnull",
		"noredzone",
		"noreturn",
		"nounwind",
		"optnone",
		"optsize",
		"readnone",
		"readonly",
		"returned",
		"returns_twice",
		"signext",
		"safestack",
		"ssp",
		"sspreq",
		"sspstrong",
		"sret",
		"sanitize_thread",
		"sanitize_memory",
		"uwtable",
		"zeroext",
		"cold",
		"nocf_check",
	}

	for _, name := range attrTests {
		testAttribute(t, name)
	}
}

func TestDebugLoc(t *testing.T) {
	mod := NewModule("")
	defer mod.Dispose()

	ctx := mod.Context()

	b := ctx.NewBuilder()
	defer b.Dispose()

	d := NewDIBuilder(mod)
	defer func() {
		d.Destroy()
	}()
	file := d.CreateFile("dummy_file", "dummy_dir")
	voidInfo := d.CreateBasicType(DIBasicType{Name: "void"})
	typeInfo := d.CreateSubroutineType(DISubroutineType{file, []Metadata{voidInfo}})
	scope := d.CreateFunction(file, DIFunction{
		Name:         "foo",
		LinkageName:  "foo",
		Line:         10,
		ScopeLine:    10,
		Type:         typeInfo,
		File:         file,
		IsDefinition: true,
	})

	b.SetCurrentDebugLocation(10, 20, scope, Metadata{})
	loc := b.GetCurrentDebugLocation()
	if loc.Line != 10 {
		t.Errorf("Got line %d, though wanted 10", loc.Line)
	}
	if loc.Col != 20 {
		t.Errorf("Got column %d, though wanted 20", loc.Col)
	}
	if loc.Scope.C != scope.C {
		t.Errorf("Got metadata %v as scope, though wanted %v", loc.Scope.C, scope.C)
	}
}

func TestSubtypes(t *testing.T) {
	cont := NewContext()
	defer cont.Dispose()

	int_pointer := PointerType(cont.Int32Type(), 0)
	int_inner := int_pointer.Subtypes()
	if len(int_inner) != 1 {
		t.Errorf("Got size %d, though wanted 1", len(int_inner))
	}
	if int_inner[0] != cont.Int32Type() {
		t.Errorf("Expected int32 type")
	}

	st_pointer := cont.StructType([]Type{cont.Int32Type(), cont.Int8Type()}, false)
	st_inner := st_pointer.Subtypes()
	if len(st_inner) != 2 {
		t.Errorf("Got size %d, though wanted 2", len(int_inner))
	}
	if st_inner[0] != cont.Int32Type() {
		t.Errorf("Expected first struct field to be int32")
	}
	if st_inner[1] != cont.Int8Type() {
		t.Errorf("Expected second struct field to be int8")
	}
}
<commit_msg>Fix Go IR test for changes in DIBuilder API<commit_after>//===- ir_test.go - Tests for ir ------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file tests bindings for the ir component.
//
//===----------------------------------------------------------------------===//

package llvm

import (
	"strings"
	"testing"
)

func testAttribute(t *testing.T, name string) {
	mod := NewModule("")
	defer mod.Dispose()

	ftyp := FunctionType(VoidType(), nil, false)
	fn := AddFunction(mod, "foo", ftyp)

	kind := AttributeKindID(name)
	attr := mod.Context().CreateEnumAttribute(kind, 0)

	fn.AddFunctionAttr(attr)
	newattr := fn.GetEnumFunctionAttribute(kind)
	if attr != newattr {
		t.Errorf("got attribute mask %d, want %d", newattr, attr)
	}

	text := mod.String()
	if !strings.Contains(text, " "+name+" ") {
		t.Errorf("expected attribute '%s', got:\n%s", name, text)
	}

	fn.RemoveEnumFunctionAttribute(kind)
	newattr = fn.GetEnumFunctionAttribute(kind)
	if !newattr.IsNil() {
		t.Errorf("got attribute mask %d, want 0", newattr)
	}
}

func TestAttributes(t *testing.T) {
	// Tests that our attribute constants haven't drifted from LLVM's.
	attrTests := []string{
		"sanitize_address",
		"alwaysinline",
		"builtin",
		"byval",
		"convergent",
		"inalloca",
		"inlinehint",
		"inreg",
		"jumptable",
		"minsize",
		"naked",
		"nest",
		"noalias",
		"nobuiltin",
		"nocapture",
		"noduplicate",
		"noimplicitfloat",
		"noinline",
		"nonlazybind",
		"nonnull",
		"noredzone",
		"noreturn",
		"nounwind",
		"optnone",
		"optsize",
		"readnone",
		"readonly",
		"returned",
		"returns_twice",
		"signext",
		"safestack",
		"ssp",
		"sspreq",
		"sspstrong",
		"sret",
		"sanitize_thread",
		"sanitize_memory",
		"uwtable",
		"zeroext",
		"cold",
		"nocf_check",
	}

	for _, name := range attrTests {
		testAttribute(t, name)
	}
}

func TestDebugLoc(t *testing.T) {
	mod := NewModule("")
	defer mod.Dispose()

	ctx := mod.Context()

	b := ctx.NewBuilder()
	defer b.Dispose()

	d := NewDIBuilder(mod)
	defer func() {
		d.Destroy()
	}()
	file := d.CreateFile("dummy_file", "dummy_dir")
	voidInfo := d.CreateBasicType(DIBasicType{Name: "void"})
	typeInfo := d.CreateSubroutineType(DISubroutineType{
		File:       file,
		Parameters: []Metadata{voidInfo},
		Flags:      0,
	})
	scope := d.CreateFunction(file, DIFunction{
		Name:         "foo",
		LinkageName:  "foo",
		Line:         10,
		ScopeLine:    10,
		Type:         typeInfo,
		File:         file,
		IsDefinition: true,
	})

	b.SetCurrentDebugLocation(10, 20, scope, Metadata{})
	loc := b.GetCurrentDebugLocation()
	if loc.Line != 10 {
		t.Errorf("Got line %d, though wanted 10", loc.Line)
	}
	if loc.Col != 20 {
		t.Errorf("Got column %d, though wanted 20", loc.Col)
	}
	if loc.Scope.C != scope.C {
		t.Errorf("Got metadata %v as scope, though wanted %v", loc.Scope.C, scope.C)
	}
}

func TestSubtypes(t *testing.T) {
	cont := NewContext()
	defer cont.Dispose()

	int_pointer := PointerType(cont.Int32Type(), 0)
	int_inner := int_pointer.Subtypes()
	if len(int_inner) != 1 {
		t.Errorf("Got size %d, though wanted 1", len(int_inner))
	}
	if int_inner[0] != cont.Int32Type() {
		t.Errorf("Expected int32 type")
	}

	st_pointer := cont.StructType([]Type{cont.Int32Type(), cont.Int8Type()}, false)
	st_inner := st_pointer.Subtypes()
	if len(st_inner) != 2 {
		t.Errorf("Got size %d, though wanted 2", len(int_inner))
	}
	if st_inner[0] != cont.Int32Type() {
		t.Errorf("Expected first struct field to be int32")
	}
	if st_inner[1] != cont.Int8Type() {
		t.Errorf("Expected second struct field to be int8")
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2013 Google Inc.

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

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

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

package main

import (
	"encoding/json"
	"errors"
	"flag"
	"os"

	"camlistore.org/pkg/cmdmain"
	"camlistore.org/pkg/osutil"
	"camlistore.org/pkg/serverconfig"
)

type dumpconfigCmd struct{}

func init() {
	cmdmain.RegisterCommand("dumpconfig", func(flags *flag.FlagSet) cmdmain.CommandRunner {
		return new(dumpconfigCmd)
	})
}

func (c *dumpconfigCmd) Describe() string {
	return "Dump the low-level server config from its simple config."
}

func (c *dumpconfigCmd) Usage() {
}

func (c *dumpconfigCmd) RunCommand(args []string) error {
	var file string
	switch {
	case len(args) == 0:
		file = osutil.UserServerConfigPath()
	case len(args) == 1:
		file = args[0]
	default:
		return errors.New("More than 1 argument not allowed")
	}
	cfg, err := serverconfig.Load(file)
	if err != nil {
		return err
	}
	ll, err := json.MarshalIndent(cfg.Obj, "", "  ")
	if err != nil {
		return err
	}
	_, err = os.Stdout.Write(ll)
	return err
}
<commit_msg>camput: set handlerConfig=true when generating a config<commit_after>/*
Copyright 2013 Google Inc.

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

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

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

package main

import (
	"encoding/json"
	"errors"
	"flag"
	"os"

	"camlistore.org/pkg/cmdmain"
	"camlistore.org/pkg/osutil"
	"camlistore.org/pkg/serverconfig"
)

type dumpconfigCmd struct{}

func init() {
	cmdmain.RegisterCommand("dumpconfig", func(flags *flag.FlagSet) cmdmain.CommandRunner {
		return new(dumpconfigCmd)
	})
}

func (c *dumpconfigCmd) Describe() string {
	return "Dump the low-level server config from its simple config."
}

func (c *dumpconfigCmd) Usage() {
}

func (c *dumpconfigCmd) RunCommand(args []string) error {
	var file string
	switch {
	case len(args) == 0:
		file = osutil.UserServerConfigPath()
	case len(args) == 1:
		file = args[0]
	default:
		return errors.New("More than 1 argument not allowed")
	}
	cfg, err := serverconfig.Load(file)
	if err != nil {
		return err
	}
	cfg.Obj["handlerConfig"] = true
	ll, err := json.MarshalIndent(cfg.Obj, "", "  ")
	if err != nil {
		return err
	}
	_, err = os.Stdout.Write(ll)
	return err
}
<|endoftext|>