<commit_before>// Copyright © 2017 The Kubicorn Authors
//
// 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 cmd

import (
	//"github.com/spf13/pflag"
	"fmt"
	"os"
	"os/user"

	"math"

	"github.com/kris-nova/kubicorn/apis/cluster"
	"github.com/kris-nova/kubicorn/cutil/logger"
	"github.com/kris-nova/kubicorn/cutil/namer"
	"github.com/kris-nova/kubicorn/profiles"
	"github.com/kris-nova/kubicorn/state"
	"github.com/kris-nova/kubicorn/state/fs"
	"github.com/spf13/cobra"
)

type CreateOptions struct {
	Options
	Profile string
}

var co = &CreateOptions{}

var createCmd = &cobra.Command{
	Use:   "create [NAME] [-p|--profile PROFILENAME] [-c|--cloudid CLOUDID]",
	Short: "Create a Kubicorn API model from a profile",
	Long: `Use this command to create a Kubicorn API model in a defined state store.

This command will create a cluster API model as a YAML manifest in a state store.
Once the API model has been created, a user can optionally change the model to their liking.
After a model is defined and configured properly, the user can then apply the model.`,
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			co.Name = strEnvDef("KUBICORN_NAME", namer.RandomName())
		} else if len(args) > 1 {
			logger.Critical("Too many arguments.")
			os.Exit(1)
		} else {
			co.Name = args[0]
		}

		err := RunCreate(co)
		if err != nil {
			logger.Critical(err.Error())
			os.Exit(1)
		}

	},
}

func init() {
	createCmd.Flags().StringVarP(&co.StateStore, "state-store", "s", strEnvDef("KUBICORN_STATE_STORE", "fs"), "The state store type to use for the cluster")
	createCmd.Flags().StringVarP(&co.StateStorePath, "state-store-path", "S", strEnvDef("KUBICORN_STATE_STORE_PATH", "./_state"), "The state store path to use")
	createCmd.Flags().StringVarP(&co.Profile, "profile", "p", strEnvDef("KUBICORN_PROFILE", "azure"), "The cluster profile to use")
	createCmd.Flags().StringVarP(&co.CloudId, "cloudid", "c", strEnvDef("KUBICORN_CLOUDID", ""), "The cloud id")

	flagApplyAnnotations(createCmd, "profile", "__kubicorn_parse_profiles")
	flagApplyAnnotations(createCmd, "cloudid", "__kubicorn_parse_cloudid")

	RootCmd.SetUsageTemplate(usageTemplate)
	RootCmd.AddCommand(createCmd)
}

type profileFunc func(name string) *cluster.Cluster

type profileMap struct {
	profileFunc profileFunc
	description string
}

var profileMapIndexed = map[string]profileMap{
	"azure": {
		profileFunc: profiles.NewUbuntuAzureCluster,
		description: "Ubuntu on Azure",
	},
	"azure-ubuntu": {
		profileFunc: profiles.NewUbuntuAzureCluster,
		description: "Ubuntu on Azure",
	},
	"amazon": {
		profileFunc: profiles.NewUbuntuAmazonCluster,
		description: "Ubuntu on Amazon",
	},
	"aws": {
		profileFunc: profiles.NewUbuntuAmazonCluster,
		description: "Ubuntu on Amazon",
	},
	"do": {
		profileFunc: profiles.NewUbuntuDigitalOceanCluster,
		description: "Ubuntu on DigitalOcean",
	},
	"google": {
		profileFunc: profiles.NewUbuntuGoogleComputeCluster,
		description: "Ubuntu on Google Compute",
	},
	"digitalocean": {
		profileFunc: profiles.NewUbuntuDigitalOceanCluster,
		description: "Ubuntu on DigitalOcean",
	},
	"do-ubuntu": {
		profileFunc: profiles.NewUbuntuDigitalOceanCluster,
		description: "Ubuntu on DigitalOcean",
	},
	"aws-ubuntu": {
		profileFunc: profiles.NewUbuntuAmazonCluster,
		description: "Ubuntu on Amazon",
	},
	"do-centos": {
		profileFunc: profiles.NewCentosDigitalOceanCluster,
		description: "CentOS on DigitalOcean",
	},
	"aws-centos": {
		profileFunc: profiles.NewCentosAmazonCluster,
		description: "CentOS on Amazon",
	},
}

// RunCreate is the starting point when a user runs the create command.
func RunCreate(options *CreateOptions) error {

	// Create our cluster resource
	name := options.Name
	var newCluster *cluster.Cluster
	if _, ok := profileMapIndexed[options.Profile]; ok {
		newCluster = profileMapIndexed[options.Profile].profileFunc(name)
	} else {
		return fmt.Errorf("Invalid profile [%s]", options.Profile)
	}

	if newCluster.Cloud == cluster.CloudGoogle && options.CloudId == "" {
		return fmt.Errorf("CloudID is required for google cloud.")
	}
	newCluster.CloudId = options.CloudId
	// Expand state store path
	// Todo (@kris-nova) please pull this into a filepath package or something
	options.StateStorePath = expandPath(options.StateStorePath)

	// Register state store
	var stateStore state.ClusterStorer
	switch options.StateStore {
	case "fs":
		logger.Info("Selected [fs] state store")
		stateStore = fs.NewFileSystemStore(&fs.FileSystemStoreOptions{
			BasePath:    options.StateStorePath,
			ClusterName: name,
		})
	}

	// Check if state store exists
	if stateStore.Exists() {
		return fmt.Errorf("State store [%s] exists, will not overwrite", name)
	}

	// Init new state store with the cluster resource
	err := stateStore.Commit(newCluster)
	if err != nil {
		return fmt.Errorf("Unable to init state store: %v", err)
	}

	logger.Always("The state [%s/%s/cluster.yaml] has been created. You can edit the file, then run `kubicorn apply %s`", options.StateStorePath, name, name)
	return nil
}

func expandPath(path string) string {
	if path == "." {
		wd, err := os.Getwd()
		if err != nil {
			logger.Critical("Unable to get current working directory: %v", err)
			return ""
		}
		path = wd
	}
	if path == "~" {
		homeVar := os.Getenv("HOME")
		if homeVar == "" {
			homeUser, err := user.Current()
			if err != nil {
				logger.Critical("Unable to use user.Current() for user. Maybe a cross compile issue: %v", err)
				return ""
			}
			path = homeUser.HomeDir
		}
	}
	return path
}

var (
	p = func() string {
		str := ""
		spaces := ""
		maxLen := 0
		for shorthand := range profileMapIndexed {
			l := len(shorthand)
			if l > maxLen {
				maxLen = l
			}
		}
		for shorthand, pmap := range profileMapIndexed {
			spaces = ""
			k := math.Abs(float64(maxLen) - float64(len(shorthand)) + 3)
			for i := 0; i < int(k); i++ {
				spaces = fmt.Sprintf("%s%s", spaces, " ")
			}
			str = fmt.Sprintf("%s   %s%s %s\n", str, shorthand, spaces, pmap.description)
		}
		return str
	}()
	usageTemplate = fmt.Sprintf(`Usage:{{if .Runnable}}
  {{if .HasAvailableFlags}}{{appendIfNotPresent .UseLine "[flags]"}}{{else}}{{.UseLine}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
  {{ .CommandPath}} [command]{{end}}

Profiles:
%s{{if gt .Aliases 0}}
Aliases:
  {{.NameAndAliases}}
{{end}}{{if .HasExample}}
Examples:
{{ .Example }}{{end}}{{ if .HasAvailableSubCommands}}
Available Commands:{{range .Commands}}{{if .IsAvailableCommand}}
  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableLocalFlags}}
Flags:
{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{ if .HasAvailableInheritedFlags}}

Global Flags:
{{.InheritedFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasHelpSubCommands}}
Additional help topics:{{range .Commands}}{{if .IsHelpCommand}}
  {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableSubCommands }}
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
`, p)
)
<commit_msg>fixes existing file create error #32<commit_after>// Copyright © 2017 The Kubicorn Authors
//
// 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 cmd

import (
	//"github.com/spf13/pflag"
	"fmt"
	"os"
	"os/user"

	"math"

	"github.com/kris-nova/kubicorn/apis/cluster"
	"github.com/kris-nova/kubicorn/cutil/logger"
	"github.com/kris-nova/kubicorn/cutil/namer"
	"github.com/kris-nova/kubicorn/profiles"
	"github.com/kris-nova/kubicorn/state"
	"github.com/kris-nova/kubicorn/state/fs"
	"github.com/spf13/cobra"
)

type CreateOptions struct {
	Options
	Profile string
}

var co = &CreateOptions{}

var createCmd = &cobra.Command{
	Use:   "create [NAME] [-p|--profile PROFILENAME] [-c|--cloudid CLOUDID]",
	Short: "Create a Kubicorn API model from a profile",
	Long: `Use this command to create a Kubicorn API model in a defined state store.

This command will create a cluster API model as a YAML manifest in a state store.
Once the API model has been created, a user can optionally change the model to their liking.
After a model is defined and configured properly, the user can then apply the model.`,
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			co.Name = strEnvDef("KUBICORN_NAME", namer.RandomName())
		} else if len(args) > 1 {
			logger.Critical("Too many arguments.")
			os.Exit(1)
		} else {
			co.Name = args[0]
		}

		err := RunCreate(co)
		if err != nil {
			logger.Critical(err.Error())
			os.Exit(1)
		}

	},
}

func init() {
	createCmd.Flags().StringVarP(&co.StateStore, "state-store", "s", strEnvDef("KUBICORN_STATE_STORE", "fs"), "The state store type to use for the cluster")
	createCmd.Flags().StringVarP(&co.StateStorePath, "state-store-path", "S", strEnvDef("KUBICORN_STATE_STORE_PATH", "./_state"), "The state store path to use")
	createCmd.Flags().StringVarP(&co.Profile, "profile", "p", strEnvDef("KUBICORN_PROFILE", "azure"), "The cluster profile to use")
	createCmd.Flags().StringVarP(&co.CloudId, "cloudid", "c", strEnvDef("KUBICORN_CLOUDID", ""), "The cloud id")

	flagApplyAnnotations(createCmd, "profile", "__kubicorn_parse_profiles")
	flagApplyAnnotations(createCmd, "cloudid", "__kubicorn_parse_cloudid")

	RootCmd.SetUsageTemplate(usageTemplate)
	RootCmd.AddCommand(createCmd)
}

type profileFunc func(name string) *cluster.Cluster

type profileMap struct {
	profileFunc profileFunc
	description string
}

var profileMapIndexed = map[string]profileMap{
	"azure": {
		profileFunc: profiles.NewUbuntuAzureCluster,
		description: "Ubuntu on Azure",
	},
	"azure-ubuntu": {
		profileFunc: profiles.NewUbuntuAzureCluster,
		description: "Ubuntu on Azure",
	},
	"amazon": {
		profileFunc: profiles.NewUbuntuAmazonCluster,
		description: "Ubuntu on Amazon",
	},
	"aws": {
		profileFunc: profiles.NewUbuntuAmazonCluster,
		description: "Ubuntu on Amazon",
	},
	"do": {
		profileFunc: profiles.NewUbuntuDigitalOceanCluster,
		description: "Ubuntu on DigitalOcean",
	},
	"google": {
		profileFunc: profiles.NewUbuntuGoogleComputeCluster,
		description: "Ubuntu on Google Compute",
	},
	"digitalocean": {
		profileFunc: profiles.NewUbuntuDigitalOceanCluster,
		description: "Ubuntu on DigitalOcean",
	},
	"do-ubuntu": {
		profileFunc: profiles.NewUbuntuDigitalOceanCluster,
		description: "Ubuntu on DigitalOcean",
	},
	"aws-ubuntu": {
		profileFunc: profiles.NewUbuntuAmazonCluster,
		description: "Ubuntu on Amazon",
	},
	"do-centos": {
		profileFunc: profiles.NewCentosDigitalOceanCluster,
		description: "CentOS on DigitalOcean",
	},
	"aws-centos": {
		profileFunc: profiles.NewCentosAmazonCluster,
		description: "CentOS on Amazon",
	},
}

// RunCreate is the starting point when a user runs the create command.
func RunCreate(options *CreateOptions) error {

	// Create our cluster resource
	name := options.Name
	var newCluster *cluster.Cluster
	if _, ok := profileMapIndexed[options.Profile]; ok {
		newCluster = profileMapIndexed[options.Profile].profileFunc(name)
	} else {
		return fmt.Errorf("Invalid profile [%s]", options.Profile)
	}

	if newCluster.Cloud == cluster.CloudGoogle && options.CloudId == "" {
		return fmt.Errorf("CloudID is required for google cloud.")
	}
	newCluster.CloudId = options.CloudId
	// Expand state store path
	// Todo (@kris-nova) please pull this into a filepath package or something
	options.StateStorePath = expandPath(options.StateStorePath)

	// Register state store
	var stateStore state.ClusterStorer
	switch options.StateStore {
	case "fs":
		logger.Info("Selected [fs] state store")
		stateStore = fs.NewFileSystemStore(&fs.FileSystemStoreOptions{
			BasePath:    options.StateStorePath,
			ClusterName: name,
		})
	}

	// Check if state store exists
	if stateStore.Exists() {
		return fmt.Errorf("State store [%s] exists, will not overwrite. Delete existing profile [%s] and retry", name, options.StateStorePath+"/"+name)
	}

	// Init new state store with the cluster resource
	err := stateStore.Commit(newCluster)
	if err != nil {
		return fmt.Errorf("Unable to init state store: %v", err)
	}

	logger.Always("The state [%s/%s/cluster.yaml] has been created. You can edit the file, then run `kubicorn apply %s`", options.StateStorePath, name, name)
	return nil
}

func expandPath(path string) string {
	if path == "." {
		wd, err := os.Getwd()
		if err != nil {
			logger.Critical("Unable to get current working directory: %v", err)
			return ""
		}
		path = wd
	}
	if path == "~" {
		homeVar := os.Getenv("HOME")
		if homeVar == "" {
			homeUser, err := user.Current()
			if err != nil {
				logger.Critical("Unable to use user.Current() for user. Maybe a cross compile issue: %v", err)
				return ""
			}
			path = homeUser.HomeDir
		}
	}
	return path
}

var (
	p = func() string {
		str := ""
		spaces := ""
		maxLen := 0
		for shorthand := range profileMapIndexed {
			l := len(shorthand)
			if l > maxLen {
				maxLen = l
			}
		}
		for shorthand, pmap := range profileMapIndexed {
			spaces = ""
			k := math.Abs(float64(maxLen) - float64(len(shorthand)) + 3)
			for i := 0; i < int(k); i++ {
				spaces = fmt.Sprintf("%s%s", spaces, " ")
			}
			str = fmt.Sprintf("%s   %s%s %s\n", str, shorthand, spaces, pmap.description)
		}
		return str
	}()
	usageTemplate = fmt.Sprintf(`Usage:{{if .Runnable}}
  {{if .HasAvailableFlags}}{{appendIfNotPresent .UseLine "[flags]"}}{{else}}{{.UseLine}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
  {{ .CommandPath}} [command]{{end}}

Profiles:
%s{{if gt .Aliases 0}}
Aliases:
  {{.NameAndAliases}}
{{end}}{{if .HasExample}}
Examples:
{{ .Example }}{{end}}{{ if .HasAvailableSubCommands}}
Available Commands:{{range .Commands}}{{if .IsAvailableCommand}}
  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableLocalFlags}}
Flags:
{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{ if .HasAvailableInheritedFlags}}

Global Flags:
{{.InheritedFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasHelpSubCommands}}
Additional help topics:{{range .Commands}}{{if .IsHelpCommand}}
  {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableSubCommands }}
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
`, p)
)
<|endoftext|>


<commit_before>// Copyright © 2017 Sam Elliott <me@sam-e.co.uk>
//
// 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 cmd

import (
	"fmt"
	"log"
	"os"

	"github.com/elliottsam/winrm-dns-client/dns"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// createCmd represents the create command
var createCmd = &cobra.Command{
	Use:   "create",
	Short: "A brief description of your command",
	Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
	Run: func(cmd *cobra.Command, args []string) {
		if dnsZone == "" {
			fmt.Println("DnsZone is a required parameter")
			os.Exit(1)
		}

		rec := dns.Record{
			Dnszone: dnsZone,
			Name:    name,
			Type:    recordType,
			Value:   value,
			TTL:     ttl,
		}
		ClientConfig := dns.GenerateClient(viper.GetString("servername"), viper.GetString("username"), viper.GetString("password"))
		ClientConfig.ConfigureWinRMClient()

		record, err := dns.CreateRecord(&ClientConfig, rec)
		if err != nil {
			log.Fatalln("Error creating DNS record:", err)
		}
		dns.OutputTable(record)
	},
}

func init() {
	RootCmd.AddCommand(createCmd)

	createCmd.PersistentFlags().StringVarP(&dnsZone, "DnsZone", "d", "", "DNS Zone to create record for, this is required")
	createCmd.PersistentFlags().StringVarP(&name, "Name", "n", "", "Name of record to create, this is required")
	createCmd.PersistentFlags().StringVarP(&recordType, "Type", "t", "", "Type of DNS record to create, this is required")
	createCmd.PersistentFlags().StringVarP(&value, "Value", "v", "", "Value of DNS record, this is required")
	createCmd.PersistentFlags().Float64VarP(&ttl, "TTL", "l", 900, "TTL for record in seconds")
	createCmd.MarkPersistentFlagRequired("DnsZone")
}
<commit_msg>Updating help for create command<commit_after>// Copyright © 2017 Sam Elliott <me@sam-e.co.uk>
//
// 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 cmd

import (
	"fmt"
	"log"
	"os"

	"github.com/elliottsam/winrm-dns-client/dns"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// createCmd represents the create command
var createCmd = &cobra.Command{
	Use:   "create",
	Short: "Creates a DNS record on Windows server",
	Long: `Creates a DNS record on Windows server
	configured in the configuration file, all flags except
	TTL are required.`,
	Run: func(cmd *cobra.Command, args []string) {
		if dnsZone == "" {
			fmt.Println("DnsZone is a required parameter")
			os.Exit(1)
		}

		rec := dns.Record{
			Dnszone: dnsZone,
			Name:    name,
			Type:    recordType,
			Value:   value,
			TTL:     ttl,
		}
		ClientConfig := dns.GenerateClient(viper.GetString("servername"), viper.GetString("username"), viper.GetString("password"))
		ClientConfig.ConfigureWinRMClient()

		record, err := dns.CreateRecord(&ClientConfig, rec)
		if err != nil {
			log.Fatalln("Error creating DNS record:", err)
		}
		dns.OutputTable(record)
	},
}

func init() {
	RootCmd.AddCommand(createCmd)

	createCmd.PersistentFlags().StringVarP(&dnsZone, "DnsZone", "d", "", "DNS Zone to create record for, this is required")
	createCmd.PersistentFlags().StringVarP(&name, "Name", "n", "", "Name of record to create, this is required")
	createCmd.PersistentFlags().StringVarP(&recordType, "Type", "t", "", "Type of DNS record to create, this is required")
	createCmd.PersistentFlags().StringVarP(&value, "Value", "v", "", "Value of DNS record, this is required")
	createCmd.PersistentFlags().Float64VarP(&ttl, "TTL", "l", 900, "TTL for record in seconds")
	createCmd.MarkPersistentFlagRequired("DnsZone")
}
<|endoftext|>


<commit_before>package syncer_test

import (
	"os"
	"time"

	"github.com/apcera/nats"
	"github.com/cloudfoundry-incubator/bbs/fake_bbs"
	"github.com/cloudfoundry-incubator/bbs/models"
	"github.com/cloudfoundry-incubator/route-emitter/routing_table"
	"github.com/cloudfoundry-incubator/route-emitter/syncer"
	"github.com/cloudfoundry-incubator/routing-info/cfroutes"
	fake_metrics_sender "github.com/cloudfoundry/dropsonde/metric_sender/fake"
	"github.com/cloudfoundry/dropsonde/metrics"
	"github.com/cloudfoundry/gunk/diegonats"
	"github.com/pivotal-golang/clock/fakeclock"
	"github.com/pivotal-golang/lager"
	"github.com/pivotal-golang/lager/lagertest"
	"github.com/tedsuo/ifrit"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

const logGuid = "some-log-guid"

var _ = Describe("Syncer", func() {
	const (
		processGuid   = "process-guid-1"
		containerPort = 8080
		instanceGuid  = "instance-guid-1"
		lrpHost       = "1.2.3.4"
	)

	var (
		bbsClient      *fake_bbs.FakeClient
		natsClient     *diegonats.FakeNATSClient
		syncerRunner   *syncer.Syncer
		process        ifrit.Process
		syncMessages   routing_table.MessagesToEmit
		messagesToEmit routing_table.MessagesToEmit
		clock          *fakeclock.FakeClock
		clockStep      time.Duration
		syncInterval   time.Duration

		shutdown chan struct{}

		schedulingInfoResponse *models.DesiredLRPSchedulingInfo
		actualResponses        []*models.ActualLRPGroup

		routerStartMessages chan<- *nats.Msg
		fakeMetricSender    *fake_metrics_sender.FakeMetricSender
	)

	BeforeEach(func() {
		bbsClient = new(fake_bbs.FakeClient)
		natsClient = diegonats.NewFakeClient()

		clock = fakeclock.NewFakeClock(time.Now())
		clockStep = 1 * time.Second
		syncInterval = 10 * time.Second

		startMessages := make(chan *nats.Msg)
		routerStartMessages = startMessages

		natsClient.WhenSubscribing("router.start", func(callback nats.MsgHandler) error {
			go func() {
				for msg := range startMessages {
					callback(msg)
				}
			}()

			return nil
		})

		//what follows is fake data to distinguish between
		//the "sync" and "emit" codepaths
		dummyEndpoint := routing_table.Endpoint{InstanceGuid: "instance-guid-1", Host: "1.1.1.1", Port: 11, ContainerPort: 1111}
		dummyMessage := routing_table.RegistryMessageFor(dummyEndpoint, routing_table.Routes{Hostnames: []string{"foo.com", "bar.com"}, LogGuid: logGuid})
		syncMessages = routing_table.MessagesToEmit{
			RegistrationMessages: []routing_table.RegistryMessage{dummyMessage},
		}

		dummyEndpoint = routing_table.Endpoint{InstanceGuid: "instance-guid-2", Host: "2.2.2.2", Port: 22, ContainerPort: 2222}
		dummyMessage = routing_table.RegistryMessageFor(dummyEndpoint, routing_table.Routes{Hostnames: []string{"baz.com"}, LogGuid: logGuid})
		messagesToEmit = routing_table.MessagesToEmit{
			RegistrationMessages: []routing_table.RegistryMessage{dummyMessage},
		}

		schedulingInfoResponse = &models.DesiredLRPSchedulingInfo{
			DesiredLRPKey: models.NewDesiredLRPKey(processGuid, "domain", logGuid),
			Routes:        cfroutes.CFRoutes{{Hostnames: []string{"route-1", "route-2"}, Port: containerPort}}.RoutingInfo(),
		}

		actualResponses = []*models.ActualLRPGroup{
			{
				Instance: &models.ActualLRP{
					ActualLRPKey:         models.NewActualLRPKey(processGuid, 1, "domain"),
					ActualLRPInstanceKey: models.NewActualLRPInstanceKey(instanceGuid, "cell-id"),
					ActualLRPNetInfo:     models.NewActualLRPNetInfo(lrpHost, models.NewPortMapping(1234, containerPort)),
					State:                models.ActualLRPStateRunning,
				},
			},
			{
				Instance: &models.ActualLRP{
					ActualLRPKey: models.NewActualLRPKey("", 1, ""),
					State:        models.ActualLRPStateUnclaimed,
				},
			},
		}

		bbsClient.DesiredLRPSchedulingInfosReturns([]*models.DesiredLRPSchedulingInfo{schedulingInfoResponse}, nil)
		bbsClient.ActualLRPGroupsReturns(actualResponses, nil)

		fakeMetricSender = fake_metrics_sender.NewFakeMetricSender()
		metrics.Initialize(fakeMetricSender, nil)
	})

	JustBeforeEach(func() {
		logger := lagertest.NewTestLogger("test")
		syncerRunner = syncer.NewSyncer(clock, syncInterval, natsClient, logger)

		shutdown = make(chan struct{})

		go func(clock *fakeclock.FakeClock, clockStep time.Duration, shutdown chan struct{}) {
			for {
				select {
				case <-time.After(100 * time.Millisecond):
					clock.Increment(clockStep)
				case <-shutdown:
					return
				}
			}
		}(clock, clockStep, shutdown)

		process = ifrit.Invoke(syncerRunner)
	})

	AfterEach(func() {
		process.Signal(os.Interrupt)
		Eventually(process.Wait()).Should(Receive(BeNil()))
		close(shutdown)
		close(routerStartMessages)
	})

	Describe("getting the heartbeat interval from the router", func() {
		var greetings chan *nats.Msg
		BeforeEach(func() {
			greetings = make(chan *nats.Msg, 3)
			natsClient.WhenPublishing("router.greet", func(msg *nats.Msg) error {
				greetings <- msg
				return nil
			})
		})

		Context("when the router emits a router.start", func() {
			Context("using an interval", func() {
				JustBeforeEach(func() {
					routerStartMessages <- &nats.Msg{
						Data: []byte(`{
						"minimumRegisterIntervalInSeconds":1,
						"pruneThresholdInSeconds": 3
						}`),
					}
				})

				It("should emit routes with the frequency of the passed-in-interval", func() {
					Eventually(syncerRunner.Events().Emit, 2).Should(Receive())
					t1 := clock.Now()

					Eventually(syncerRunner.Events().Emit, 2).Should(Receive())
					t2 := clock.Now()

					Expect(t2.Sub(t1)).To(BeNumerically("~", 1*time.Second, 200*time.Millisecond))
				})

				It("should only greet the router once", func() {
					Eventually(greetings).Should(Receive())
					Consistently(greetings, 1).ShouldNot(Receive())
				})
			})
		})

		Context("when the router does not emit a router.start", func() {
			It("should keep greeting the router until it gets an interval", func() {
				//get the first greeting
				Eventually(greetings, 2).Should(Receive())

				//get the second greeting, and respond
				var msg *nats.Msg
				Eventually(greetings, 2).Should(Receive(&msg))
				go natsClient.Publish(msg.Reply, []byte(`{"minimumRegisterIntervalInSeconds":1, "pruneThresholdInSeconds": 3}`))

				//should no longer be greeting the router
				Consistently(greetings).ShouldNot(Receive())
			})
		})

		Context("after getting the first interval, when a second interval arrives", func() {
			JustBeforeEach(func() {
				routerStartMessages <- &nats.Msg{
					Data: []byte(`{"minimumRegisterIntervalInSeconds":1, "pruneThresholdInSeconds": 3}`),
				}
			})

			It("should modify its update rate", func() {
				routerStartMessages <- &nats.Msg{
					Data: []byte(`{"minimumRegisterIntervalInSeconds":2, "pruneThresholdInSeconds": 6}`),
				}

				//first emit should be pretty quick, it is in response to the incoming heartbeat interval
				Eventually(syncerRunner.Events().Emit).Should(Receive())
				t1 := clock.Now()

				//subsequent emit should follow the interval
				Eventually(syncerRunner.Events().Emit).Should(Receive())
				t2 := clock.Now()

				Expect(t2.Sub(t1)).To(BeNumerically("~", 2*time.Second, 200*time.Millisecond))
			})
		})

		Context("if it never hears anything from a router anywhere", func() {
			It("should still be able to shutdown", func() {
				process.Signal(os.Interrupt)
				Eventually(process.Wait()).Should(Receive(BeNil()))
			})
		})
	})

	Describe("syncing", func() {
		BeforeEach(func() {
			bbsClient.ActualLRPGroupsStub = func(logger lager.Logger, f models.ActualLRPFilter) ([]*models.ActualLRPGroup, error) {
				return nil, nil
			}
			syncInterval = 500 * time.Millisecond

			clockStep = 250 * time.Millisecond
		})

		JustBeforeEach(func() {
			//we set the emit interval real high to avoid colliding with our sync interval
			routerStartMessages <- &nats.Msg{
				Data: []byte(`{"minimumRegisterIntervalInSeconds":10, "pruneThresholdInSeconds": 20}`),
			}
		})

		Context("after the router greets", func() {
			BeforeEach(func() {
				syncInterval = 10 * time.Minute
			})

			It("syncs", func() {
				Eventually(syncerRunner.Events().Sync).Should(Receive())
			})
		})

		Context("on a specified interval", func() {
			It("should sync", func() {
				var t1 time.Time
				var t2 time.Time

				select {
				case <-syncerRunner.Events().Sync:
					t1 = clock.Now()
				case <-time.After(500 * time.Millisecond):
					Fail("did not receive a sync event")
				}

				select {
				case <-syncerRunner.Events().Sync:
					t2 = clock.Now()
				case <-time.After(500 * time.Millisecond):
					Fail("did not receive a sync event")
				}

				Expect(t2.Sub(t1)).To(BeNumerically("~", syncInterval, 100*time.Millisecond))
			})
		})
	})
})
<commit_msg>Remove unused variables from test<commit_after>package syncer_test

import (
	"os"
	"time"

	"github.com/apcera/nats"
	"github.com/cloudfoundry-incubator/bbs/fake_bbs"
	"github.com/cloudfoundry-incubator/bbs/models"
	"github.com/cloudfoundry-incubator/route-emitter/syncer"
	"github.com/cloudfoundry-incubator/routing-info/cfroutes"
	fake_metrics_sender "github.com/cloudfoundry/dropsonde/metric_sender/fake"
	"github.com/cloudfoundry/dropsonde/metrics"
	"github.com/cloudfoundry/gunk/diegonats"
	"github.com/pivotal-golang/clock/fakeclock"
	"github.com/pivotal-golang/lager"
	"github.com/pivotal-golang/lager/lagertest"
	"github.com/tedsuo/ifrit"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

const logGuid = "some-log-guid"

var _ = Describe("Syncer", func() {
	const (
		processGuid   = "process-guid-1"
		containerPort = 8080
		instanceGuid  = "instance-guid-1"
		lrpHost       = "1.2.3.4"
	)

	var (
		bbsClient    *fake_bbs.FakeClient
		natsClient   *diegonats.FakeNATSClient
		syncerRunner *syncer.Syncer
		process      ifrit.Process
		clock        *fakeclock.FakeClock
		clockStep    time.Duration
		syncInterval time.Duration

		shutdown chan struct{}

		schedulingInfoResponse *models.DesiredLRPSchedulingInfo
		actualResponses        []*models.ActualLRPGroup

		routerStartMessages chan<- *nats.Msg
		fakeMetricSender    *fake_metrics_sender.FakeMetricSender
	)

	BeforeEach(func() {
		bbsClient = new(fake_bbs.FakeClient)
		natsClient = diegonats.NewFakeClient()

		clock = fakeclock.NewFakeClock(time.Now())
		clockStep = 1 * time.Second
		syncInterval = 10 * time.Second

		startMessages := make(chan *nats.Msg)
		routerStartMessages = startMessages

		natsClient.WhenSubscribing("router.start", func(callback nats.MsgHandler) error {
			go func() {
				for msg := range startMessages {
					callback(msg)
				}
			}()

			return nil
		})

		schedulingInfoResponse = &models.DesiredLRPSchedulingInfo{
			DesiredLRPKey: models.NewDesiredLRPKey(processGuid, "domain", logGuid),
			Routes:        cfroutes.CFRoutes{{Hostnames: []string{"route-1", "route-2"}, Port: containerPort}}.RoutingInfo(),
		}

		actualResponses = []*models.ActualLRPGroup{
			{
				Instance: &models.ActualLRP{
					ActualLRPKey:         models.NewActualLRPKey(processGuid, 1, "domain"),
					ActualLRPInstanceKey: models.NewActualLRPInstanceKey(instanceGuid, "cell-id"),
					ActualLRPNetInfo:     models.NewActualLRPNetInfo(lrpHost, models.NewPortMapping(1234, containerPort)),
					State:                models.ActualLRPStateRunning,
				},
			},
			{
				Instance: &models.ActualLRP{
					ActualLRPKey: models.NewActualLRPKey("", 1, ""),
					State:        models.ActualLRPStateUnclaimed,
				},
			},
		}

		bbsClient.DesiredLRPSchedulingInfosReturns([]*models.DesiredLRPSchedulingInfo{schedulingInfoResponse}, nil)
		bbsClient.ActualLRPGroupsReturns(actualResponses, nil)

		fakeMetricSender = fake_metrics_sender.NewFakeMetricSender()
		metrics.Initialize(fakeMetricSender, nil)
	})

	JustBeforeEach(func() {
		logger := lagertest.NewTestLogger("test")
		syncerRunner = syncer.NewSyncer(clock, syncInterval, natsClient, logger)

		shutdown = make(chan struct{})

		go func(clock *fakeclock.FakeClock, clockStep time.Duration, shutdown chan struct{}) {
			for {
				select {
				case <-time.After(100 * time.Millisecond):
					clock.Increment(clockStep)
				case <-shutdown:
					return
				}
			}
		}(clock, clockStep, shutdown)

		process = ifrit.Invoke(syncerRunner)
	})

	AfterEach(func() {
		process.Signal(os.Interrupt)
		Eventually(process.Wait()).Should(Receive(BeNil()))
		close(shutdown)
		close(routerStartMessages)
	})

	Describe("getting the heartbeat interval from the router", func() {
		var greetings chan *nats.Msg
		BeforeEach(func() {
			greetings = make(chan *nats.Msg, 3)
			natsClient.WhenPublishing("router.greet", func(msg *nats.Msg) error {
				greetings <- msg
				return nil
			})
		})

		Context("when the router emits a router.start", func() {
			Context("using an interval", func() {
				JustBeforeEach(func() {
					routerStartMessages <- &nats.Msg{
						Data: []byte(`{
						"minimumRegisterIntervalInSeconds":1,
						"pruneThresholdInSeconds": 3
						}`),
					}
				})

				It("should emit routes with the frequency of the passed-in-interval", func() {
					Eventually(syncerRunner.Events().Emit, 2).Should(Receive())
					t1 := clock.Now()

					Eventually(syncerRunner.Events().Emit, 2).Should(Receive())
					t2 := clock.Now()

					Expect(t2.Sub(t1)).To(BeNumerically("~", 1*time.Second, 200*time.Millisecond))
				})

				It("should only greet the router once", func() {
					Eventually(greetings).Should(Receive())
					Consistently(greetings, 1).ShouldNot(Receive())
				})
			})
		})

		Context("when the router does not emit a router.start", func() {
			It("should keep greeting the router until it gets an interval", func() {
				//get the first greeting
				Eventually(greetings, 2).Should(Receive())

				//get the second greeting, and respond
				var msg *nats.Msg
				Eventually(greetings, 2).Should(Receive(&msg))
				go natsClient.Publish(msg.Reply, []byte(`{"minimumRegisterIntervalInSeconds":1, "pruneThresholdInSeconds": 3}`))

				//should no longer be greeting the router
				Consistently(greetings).ShouldNot(Receive())
			})
		})

		Context("after getting the first interval, when a second interval arrives", func() {
			JustBeforeEach(func() {
				routerStartMessages <- &nats.Msg{
					Data: []byte(`{"minimumRegisterIntervalInSeconds":1, "pruneThresholdInSeconds": 3}`),
				}
			})

			It("should modify its update rate", func() {
				routerStartMessages <- &nats.Msg{
					Data: []byte(`{"minimumRegisterIntervalInSeconds":2, "pruneThresholdInSeconds": 6}`),
				}

				//first emit should be pretty quick, it is in response to the incoming heartbeat interval
				Eventually(syncerRunner.Events().Emit).Should(Receive())
				t1 := clock.Now()

				//subsequent emit should follow the interval
				Eventually(syncerRunner.Events().Emit).Should(Receive())
				t2 := clock.Now()

				Expect(t2.Sub(t1)).To(BeNumerically("~", 2*time.Second, 200*time.Millisecond))
			})
		})

		Context("if it never hears anything from a router anywhere", func() {
			It("should still be able to shutdown", func() {
				process.Signal(os.Interrupt)
				Eventually(process.Wait()).Should(Receive(BeNil()))
			})
		})
	})

	Describe("syncing", func() {
		BeforeEach(func() {
			bbsClient.ActualLRPGroupsStub = func(logger lager.Logger, f models.ActualLRPFilter) ([]*models.ActualLRPGroup, error) {
				return nil, nil
			}
			syncInterval = 500 * time.Millisecond

			clockStep = 250 * time.Millisecond
		})

		JustBeforeEach(func() {
			//we set the emit interval real high to avoid colliding with our sync interval
			routerStartMessages <- &nats.Msg{
				Data: []byte(`{"minimumRegisterIntervalInSeconds":10, "pruneThresholdInSeconds": 20}`),
			}
		})

		Context("after the router greets", func() {
			BeforeEach(func() {
				syncInterval = 10 * time.Minute
			})

			It("syncs", func() {
				Eventually(syncerRunner.Events().Sync).Should(Receive())
			})
		})

		Context("on a specified interval", func() {
			It("should sync", func() {
				var t1 time.Time
				var t2 time.Time

				select {
				case <-syncerRunner.Events().Sync:
					t1 = clock.Now()
				case <-time.After(500 * time.Millisecond):
					Fail("did not receive a sync event")
				}

				select {
				case <-syncerRunner.Events().Sync:
					t2 = clock.Now()
				case <-time.After(500 * time.Millisecond):
					Fail("did not receive a sync event")
				}

				Expect(t2.Sub(t1)).To(BeNumerically("~", syncInterval, 100*time.Millisecond))
			})
		})
	})
})
<|endoftext|>


<commit_before>package route

import (
	"net/http"
	. "github.com/SimonRichardson/wishful/useful"
	. "github.com/SimonRichardson/wishful/wishful"
)

type Server struct {
	server *http.Server
}

func Listen(address string, route func(x *Request) Promise) *Server {
	return &Server{
		server: &http.Server{
			Addr:    address,
			Handler: http.HandlerFunc(handle(route)),
		},
	}
}

func Serve(s *Server) Either {
	if err := s.server.ListenAndServe(); err != nil {
		return NewLeft(err)
	}
	return NewRight(s)
}

func handle(route func(x *Request) Promise) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		route(NewRequest(r)).Fork(func(x AnyVal) AnyVal {
			result := x.(Result)
			header := w.Header()
			for k, v := range result.Headers {
				header.Set(k, v)
			}
			w.WriteHeader(result.StatusCode)
			w.Write([]byte(result.Body))
			return x
		})
	}
}
<commit_msg>just handle routes, don't serve - appengine!<commit_after>package route

import (
	"net/http"
	. "github.com/SimonRichardson/wishful/useful"
	. "github.com/SimonRichardson/wishful/wishful"
)

type Server struct {
	server *http.Server
}

func Listen(address string, route func(x *Request) Promise) *Server {
	return &Server{
		server: &http.Server{
			Addr:    address,
			Handler: http.HandlerFunc(handle(route)),
		},
	}
}

func Serve(s *Server) Either {
	if err := s.server.ListenAndServe(); err != nil {
		return NewLeft(err)
	}
	return NewRight(s)
}

func Handle(route func(x *Request) Promise) IO {
	return IO{}.Of(http.HandlerFunc(handle(route))).(IO)
}

func handle(route func(x *Request) Promise) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		route(NewRequest(r)).Fork(func(x AnyVal) AnyVal {
			result := x.(Result)
			header := w.Header()
			for k, v := range result.Headers {
				header.Set(k, v)
			}
			w.WriteHeader(result.StatusCode)
			w.Write([]byte(result.Body))
			return x
		})
	}
}
<|endoftext|>


<commit_before>package system

import (
	"errors"
	"runtime"
	"strings"
	"syscall"
	"time"

	"github.com/orfjackal/gospec"
	. "github.com/orfjackal/gospec"
)

func StartSpec(c gospec.Context) {
	sys := NewSystem()

	c.Specify("When initialising a system", func() {
		c.Specify("and Init() returns nil", func() {
			sys.initReturn = nil
			err := Start(sys, false)

			c.Specify("Start() does not return an error", func() {
				c.Expect(err, IsNil)
			})

			c.Specify("Update() is called until it exits", func() {
				c.Expect(sys.updateCount, Equals, sys.maxUpdates)
			})

			c.Specify("Exit() is called once", func() {
				c.Expect(sys.exitCount, Equals, 1)
			})
		})

		c.Specify("and Init() returns an error", func() {
			sys.initReturn = errors.New("a fake error")
			err := Start(sys, false)

			c.Specify("Start() returns that error", func() {
				c.Expect(err, Satisfies, strings.Contains(err.Error(), "a fake error"))
			})

			c.Specify("Update() is never called", func() {
				c.Expect(sys.updateCount, Equals, 0)
			})

			c.Specify("Exit() is never called", func() {
				c.Expect(sys.exitCount, Equals, 0)
			})
		})
	})

	c.Specify("When updating a system", func() {
		c.Specify("timestep is within 1ms of the defined Frequency()", func() {
			sys.maxUpdates = 100
			Start(sys, false)

			c.Expect(sys.avgTimestepMs(), IsWithin(1.0), float64(sys.Frequency().Nanoseconds()/1000000))
		})

		c.Specify("and Update() returns true", func() {
			sys.maxUpdates = 2
			sys.updateReturnStop = true
			Start(sys, false)

			c.Specify("Update() is not called anymore after exit", func() {
				c.Expect(sys.updateCount, Equals, 1)
			})

			c.Specify("Exit() is called once", func() {
				c.Expect(sys.exitCount, Equals, 1)
			})
		})

		c.Specify("and Update() returns an error", func() {
			sys.maxUpdates = 2
			sys.updateReturnErr = errors.New("a fake error")
			err := Start(sys, false)

			c.Specify("Update() is not called anymore after exit", func() {
				c.Expect(sys.updateCount, Equals, 1)
			})

			c.Specify("Exit() is called once", func() {
				c.Expect(sys.exitCount, Equals, 1)
			})

			c.Specify("Start() returns that error", func() {
				c.Expect(err, Satisfies, strings.Contains(err.Error(), "a fake error"))
			})
		})
	})

	c.Specify("When \"lockthread\" param", func() {
		// we need lots of threads for this test to word
		prevprocs := runtime.GOMAXPROCS(runtime.NumCPU()*10)
		// start other yielding routines
		go func() { for { runtime.Gosched() }}()
		go func() { for { runtime.Gosched() }}()
		go func() { for { runtime.Gosched() }}()

		sys.maxUpdates = 1000

		c.Specify("is TRUE then Init(), Update() and Exit() only ever ran on one and the same thread", func() {
			Start(sys, true)

			c.Assume(len(sys.initTids), Equals, 1)
			c.Assume(len(sys.updateTids), Equals, 1)
			c.Assume(len(sys.exitTids), Equals, 1)

			c.Specify("Init() thread equal to Update() thread", func() {
				c.Expect(sys.initTids[0], Equals, sys.updateTids[0])
			})

			c.Specify("Update() thread equal to Exit() thread", func() {
				c.Expect(sys.updateTids[0], Equals, sys.exitTids[0])
			})

		})

		c.Specify("is FALSE then Init(), Update() and Exit() only ever ran on one and the same thread", func() {

			Start(sys, false)

			c.Specify("either Init(), Update() or Exit() ran on more than one thread", func() {
				allTids := len(sys.initTids) + len(sys.updateTids) + len(sys.exitTids)
				c.Expect(allTids, Satisfies, allTids > 3)
			})
		})

		// reset to original thread number
		runtime.GOMAXPROCS(prevprocs)

	})
}

type FakeSystem struct {
	initTids, updateTids, exitTids []int
	initReturn                     error
	updateReturnStop               bool
	updateReturnErr                error
	maxUpdates, updateCount        int
	exitCount                      int
	totalTimeMs                    float64
}

func NewSystem() *FakeSystem {
	return &FakeSystem{maxUpdates: 1}
}

func (f *FakeSystem) Frequency() time.Duration {
	return 1 * time.Millisecond
}

func (f *FakeSystem) Init() error {
	f.initTids = AppendTid(f.initTids, syscall.Gettid())

	return f.initReturn
}

func (f *FakeSystem) avgTimestepMs() float64 {
	return f.totalTimeMs / float64(f.updateCount)
}

func AppendTid(list []int, tid int) []int {
	found := false
	for _, id := range list {
		if id == tid {
			found = true
			break
		}
	}

	if !found {
		return append(list, tid)
	}

	return list
}

func (f *FakeSystem)Update(timestep time.Duration) (stop bool, err error) {
	f.updateTids = AppendTid(f.updateTids, syscall.Gettid())

	f.updateCount++
	if f.updateCount >= f.maxUpdates {
		stop = true
	}

	f.totalTimeMs += float64(timestep.Nanoseconds())/1000000

	runtime.Gosched()

	stop = stop || f.updateReturnStop
	err = f.updateReturnErr
	return
}

func (f *FakeSystem)Exit() {
	f.exitTids = AppendTid(f.exitTids, syscall.Gettid())

	f.exitCount++
}<commit_msg>fixed copy/paste mistake in system spec message<commit_after>package system

import (
	"errors"
	"runtime"
	"strings"
	"syscall"
	"time"

	"github.com/orfjackal/gospec"
	. "github.com/orfjackal/gospec"
)

func StartSpec(c gospec.Context) {
	sys := NewSystem()

	c.Specify("When initialising a system", func() {
		c.Specify("and Init() returns nil", func() {
			sys.initReturn = nil
			err := Start(sys, false)

			c.Specify("Start() does not return an error", func() {
				c.Expect(err, IsNil)
			})

			c.Specify("Update() is called until it exits", func() {
				c.Expect(sys.updateCount, Equals, sys.maxUpdates)
			})

			c.Specify("Exit() is called once", func() {
				c.Expect(sys.exitCount, Equals, 1)
			})
		})

		c.Specify("and Init() returns an error", func() {
			sys.initReturn = errors.New("a fake error")
			err := Start(sys, false)

			c.Specify("Start() returns that error", func() {
				c.Expect(err, Satisfies, strings.Contains(err.Error(), "a fake error"))
			})

			c.Specify("Update() is never called", func() {
				c.Expect(sys.updateCount, Equals, 0)
			})

			c.Specify("Exit() is never called", func() {
				c.Expect(sys.exitCount, Equals, 0)
			})
		})
	})

	c.Specify("When updating a system", func() {
		c.Specify("timestep is within 1ms of the defined Frequency()", func() {
			sys.maxUpdates = 100
			Start(sys, false)

			c.Expect(sys.avgTimestepMs(), IsWithin(1.0), float64(sys.Frequency().Nanoseconds()/1000000))
		})

		c.Specify("and Update() returns true", func() {
			sys.maxUpdates = 2
			sys.updateReturnStop = true
			Start(sys, false)

			c.Specify("Update() is not called anymore after exit", func() {
				c.Expect(sys.updateCount, Equals, 1)
			})

			c.Specify("Exit() is called once", func() {
				c.Expect(sys.exitCount, Equals, 1)
			})
		})

		c.Specify("and Update() returns an error", func() {
			sys.maxUpdates = 2
			sys.updateReturnErr = errors.New("a fake error")
			err := Start(sys, false)

			c.Specify("Update() is not called anymore after exit", func() {
				c.Expect(sys.updateCount, Equals, 1)
			})

			c.Specify("Exit() is called once", func() {
				c.Expect(sys.exitCount, Equals, 1)
			})

			c.Specify("Start() returns that error", func() {
				c.Expect(err, Satisfies, strings.Contains(err.Error(), "a fake error"))
			})
		})
	})

	c.Specify("When \"lockthread\" param", func() {
		// we need lots of threads for this test to word
		prevprocs := runtime.GOMAXPROCS(runtime.NumCPU()*10)
		// start other yielding routines
		go func() { for { runtime.Gosched() }}()
		go func() { for { runtime.Gosched() }}()
		go func() { for { runtime.Gosched() }}()

		sys.maxUpdates = 1000

		c.Specify("is TRUE then Init(), Update() and Exit() only ever ran on one and the same thread", func() {
			Start(sys, true)

			c.Assume(len(sys.initTids), Equals, 1)
			c.Assume(len(sys.updateTids), Equals, 1)
			c.Assume(len(sys.exitTids), Equals, 1)

			c.Specify("Init() thread equal to Update() thread", func() {
				c.Expect(sys.initTids[0], Equals, sys.updateTids[0])
			})

			c.Specify("Update() thread equal to Exit() thread", func() {
				c.Expect(sys.updateTids[0], Equals, sys.exitTids[0])
			})

		})

		c.Specify("is FALSE", func() {
			Start(sys, false)

			c.Specify("either Init(), Update() or Exit() ran on more than one thread", func() {
				allTids := len(sys.initTids) + len(sys.updateTids) + len(sys.exitTids)
				c.Expect(allTids, Satisfies, allTids > 3)
			})
		})

		// reset to original thread number
		runtime.GOMAXPROCS(prevprocs)

	})
}

type FakeSystem struct {
	initTids, updateTids, exitTids []int
	initReturn                     error
	updateReturnStop               bool
	updateReturnErr                error
	maxUpdates, updateCount        int
	exitCount                      int
	totalTimeMs                    float64
}

func NewSystem() *FakeSystem {
	return &FakeSystem{maxUpdates: 1}
}

func (f *FakeSystem) Frequency() time.Duration {
	return 1 * time.Millisecond
}

func (f *FakeSystem) Init() error {
	f.initTids = AppendTid(f.initTids, syscall.Gettid())

	return f.initReturn
}

func (f *FakeSystem) avgTimestepMs() float64 {
	return f.totalTimeMs / float64(f.updateCount)
}

func AppendTid(list []int, tid int) []int {
	found := false
	for _, id := range list {
		if id == tid {
			found = true
			break
		}
	}

	if !found {
		return append(list, tid)
	}

	return list
}

func (f *FakeSystem)Update(timestep time.Duration) (stop bool, err error) {
	f.updateTids = AppendTid(f.updateTids, syscall.Gettid())

	f.updateCount++
	if f.updateCount >= f.maxUpdates {
		stop = true
	}

	f.totalTimeMs += float64(timestep.Nanoseconds())/1000000

	runtime.Gosched()

	stop = stop || f.updateReturnStop
	err = f.updateReturnErr
	return
}

func (f *FakeSystem)Exit() {
	f.exitTids = AppendTid(f.exitTids, syscall.Gettid())

	f.exitCount++
}<|endoftext|>


<commit_before>package main

package main

import "golang.org/x/tour/tree"

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int)

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool

func main() {
}

<commit_msg>Same implemented, figuring out how to do walk<commit_after>package main

import "golang.org/x/tour/tree"

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {

  // Do this somehow?
  ch <- t.Value
}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
  return t1.Value == t2.Value
}

func main() {
  ch := make(chan int)

  go Walk(tree.New(1), ch)
}

<|endoftext|>


<commit_before>package depsync

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/boltdb/bolt"
	"github.com/micromdm/dep"
	"github.com/micromdm/micromdm/pubsub"
	"github.com/pkg/errors"
)

const (
	SyncTopic    = "mdm.DepSync"
	ConfigBucket = "mdm.DEPConfig"
)

type Syncer interface {
	privateDEPSyncer() bool
}

type watcher struct {
	client    dep.Client
	publisher pubsub.Publisher
	conf      *config
}

type cursor struct {
	Value     string    `json:"value"`
	CreatedAt time.Time `json:"created_at"`
}

// A cursor is valid for a week.
func (c cursor) Valid() bool {
	expiration := time.Now().Add(24 * 7 * time.Hour)
	if c.CreatedAt.After(expiration) {
		return false
	}
	return true
}

func New(client dep.Client, pub pubsub.Publisher, db *bolt.DB) (Syncer, error) {
	conf, err := LoadConfig(db)
	if err != nil {
		return nil, err
	}
	if conf.Cursor.Valid() {
		fmt.Printf("loaded dep config with cursor: %s\n", conf.Cursor.Value)
	} else {
		conf.Cursor.Value = ""
	}
	sync := &watcher{
		publisher: pub,
		client:    client,
		conf:      conf,
	}

	saveCursor := func() {
		if err := conf.Save(); err != nil {
			log.Printf("saving cursor %s\n", err)
			return
		}
		log.Printf("saved DEP cursor at value %s\n", conf.Cursor.Value)
	}

	go func() {
		defer saveCursor()
		if err := sync.Run(); err != nil {
			log.Println("DEP watcher failed: ", err)
		}
	}()
	return sync, nil
}

// TODO this is private temporarily until the interface can be defined
func (w *watcher) privateDEPSyncer() bool {
	return true
}

// TODO this needs to be a proper error in the micromdm/dep package.
func isCursorExhausted(err error) bool {
	return strings.Contains(err.Error(), "EXHAUSTED_CURSOR")
}

func isCursorExpired(err error) bool {
	return strings.Contains(err.Error(), "EXPIRED_CURSOR")
}

func (w *watcher) Run() error {
	ticker := time.NewTicker(30 * time.Minute).C
FETCH:
	for {
		resp, err := w.client.FetchDevices(dep.Limit(100), dep.Cursor(w.conf.Cursor.Value))
		if err != nil && isCursorExhausted(err) {
			goto SYNC
		} else if err != nil {
			return err
		}
		fmt.Printf("more=%v, cursor=%s, fetched=%v\n", resp.MoreToFollow, resp.Cursor, resp.FetchedUntil)
		w.conf.Cursor = cursor{Value: resp.Cursor, CreatedAt: time.Now()}
		if err := w.conf.Save(); err != nil {
			return errors.Wrap(err, "saving cursor from fetch")
		}
		e := NewEvent(resp.Devices)
		data, err := MarshalEvent(e)
		if err != nil {
			return err
		}
		if err := w.publisher.Publish(SyncTopic, data); err != nil {
			return err
		}
		if !resp.MoreToFollow {
			goto SYNC
		}
	}

SYNC:
	for {
		resp, err := w.client.SyncDevices(w.conf.Cursor.Value, dep.Cursor(w.conf.Cursor.Value))
		if err != nil && isCursorExpired(err) {
			w.conf.Cursor.Value = ""
			goto FETCH
		} else if err != nil {
			return err
		}
		if len(resp.Devices) != 0 {
			fmt.Printf("more=%v, cursor=%s, synced=%v\n", resp.MoreToFollow, resp.Cursor, resp.FetchedUntil)
		}
		w.conf.Cursor = cursor{Value: resp.Cursor, CreatedAt: time.Now()}
		if err := w.conf.Save(); err != nil {
			return errors.Wrap(err, "saving cursor from sync")
		}

		// TODO handle sync response here.
		<-ticker
	}
}
<commit_msg>Issue DEP Sync Event on receiving devices from the DEP sync API (#177)<commit_after>package depsync

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/boltdb/bolt"
	"github.com/micromdm/dep"
	"github.com/micromdm/micromdm/pubsub"
	"github.com/pkg/errors"
)

const (
	SyncTopic    = "mdm.DepSync"
	ConfigBucket = "mdm.DEPConfig"
)

type Syncer interface {
	privateDEPSyncer() bool
}

type watcher struct {
	client    dep.Client
	publisher pubsub.Publisher
	conf      *config
}

type cursor struct {
	Value     string    `json:"value"`
	CreatedAt time.Time `json:"created_at"`
}

// A cursor is valid for a week.
func (c cursor) Valid() bool {
	expiration := time.Now().Add(24 * 7 * time.Hour)
	if c.CreatedAt.After(expiration) {
		return false
	}
	return true
}

func New(client dep.Client, pub pubsub.Publisher, db *bolt.DB) (Syncer, error) {
	conf, err := LoadConfig(db)
	if err != nil {
		return nil, err
	}
	if conf.Cursor.Valid() {
		fmt.Printf("loaded dep config with cursor: %s\n", conf.Cursor.Value)
	} else {
		conf.Cursor.Value = ""
	}
	sync := &watcher{
		publisher: pub,
		client:    client,
		conf:      conf,
	}

	saveCursor := func() {
		if err := conf.Save(); err != nil {
			log.Printf("saving cursor %s\n", err)
			return
		}
		log.Printf("saved DEP cursor at value %s\n", conf.Cursor.Value)
	}

	go func() {
		defer saveCursor()
		if err := sync.Run(); err != nil {
			log.Println("DEP watcher failed: ", err)
		}
	}()
	return sync, nil
}

// TODO this is private temporarily until the interface can be defined
func (w *watcher) privateDEPSyncer() bool {
	return true
}

// TODO this needs to be a proper error in the micromdm/dep package.
func isCursorExhausted(err error) bool {
	return strings.Contains(err.Error(), "EXHAUSTED_CURSOR")
}

func isCursorExpired(err error) bool {
	return strings.Contains(err.Error(), "EXPIRED_CURSOR")
}

func (w *watcher) Run() error {
	ticker := time.NewTicker(30 * time.Minute).C
FETCH:
	for {
		resp, err := w.client.FetchDevices(dep.Limit(100), dep.Cursor(w.conf.Cursor.Value))
		if err != nil && isCursorExhausted(err) {
			goto SYNC
		} else if err != nil {
			return err
		}
		fmt.Printf("more=%v, cursor=%s, fetched=%v\n", resp.MoreToFollow, resp.Cursor, resp.FetchedUntil)
		w.conf.Cursor = cursor{Value: resp.Cursor, CreatedAt: time.Now()}
		if err := w.conf.Save(); err != nil {
			return errors.Wrap(err, "saving cursor from fetch")
		}
		e := NewEvent(resp.Devices)
		data, err := MarshalEvent(e)
		if err != nil {
			return err
		}
		if err := w.publisher.Publish(SyncTopic, data); err != nil {
			return err
		}
		if !resp.MoreToFollow {
			goto SYNC
		}
	}

SYNC:
	for {
		resp, err := w.client.SyncDevices(w.conf.Cursor.Value, dep.Cursor(w.conf.Cursor.Value))
		if err != nil && isCursorExpired(err) {
			w.conf.Cursor.Value = ""
			goto FETCH
		} else if err != nil {
			return err
		}
		if len(resp.Devices) != 0 {
			fmt.Printf("more=%v, cursor=%s, synced=%v\n", resp.MoreToFollow, resp.Cursor, resp.FetchedUntil)
		}
		w.conf.Cursor = cursor{Value: resp.Cursor, CreatedAt: time.Now()}
		if err := w.conf.Save(); err != nil {
			return errors.Wrap(err, "saving cursor from sync")
		}
		if len(resp.Devices) > 0 {
			e := NewEvent(resp.Devices)
			data, err := MarshalEvent(e)
			if err != nil {
				return err
			}
			if err := w.publisher.Publish(SyncTopic, data); err != nil {
				return err
			}
		}
		if !resp.MoreToFollow {
			<-ticker
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/constabulary/gb"
	"github.com/constabulary/gb/cmd"
)

func init() {
	registerCommand(EnvCmd)
}

var EnvCmd = &cmd.Command{
	Name:      "env",
	UsageLine: `env [var ...]`,
	Short:     "print project environment variables",
	Long: `
Env prints project environment variables. If one or more variable names is
given as arguments, info prints the value of each named variable on its own line.
`,
	Run: info,
	ParseArgs: func(ctx *gb.Context, cwd string, args []string) []string {
		return args
	},
}
<commit_msg>cmd/gb: minor typo fix for env command help msg<commit_after>package main

import (
	"github.com/constabulary/gb"
	"github.com/constabulary/gb/cmd"
)

func init() {
	registerCommand(EnvCmd)
}

var EnvCmd = &cmd.Command{
	Name:      "env",
	UsageLine: `env [var ...]`,
	Short:     "print project environment variables",
	Long: `
Env prints project environment variables. If one or more variable names is
given as arguments, env prints the value of each named variable on its own line.
`,
	Run: info,
	ParseArgs: func(ctx *gb.Context, cwd string, args []string) []string {
		return args
	},
}
<|endoftext|>


<commit_before>package cmd

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"github.com/spf13/cobra"
)

type workerDone struct{}

type requestStat struct {
	duration int64 //nanoseconds
}
type requestStatSummary struct {
	avgDuration int64 //nanoseconds
	maxDuration int64 //nanoseconds
	minDuration int64 //nanoseconds
}

//verbose levels
const (
	VerboseNone = iota
	VerboseLow
	VerboseMedium
	VerboseHigh
)

//flags
var (
	numTests      int
	timeout       int
	concurrency   int
	requestMethod string
	verboseLevel  int
)

func init() {
	RootCmd.AddCommand(stressCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// stressCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// stressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

	stressCmd.Flags().IntVarP(&numTests, "num", "n", 100, "Number of requests to make")
	stressCmd.Flags().IntVarP(&concurrency, "concurrent", "c", 1, "Number of multiple requests to make")
	stressCmd.Flags().IntVarP(&timeout, "timeout", "t", 0, "Maximum seconds to wait for response. 0 means unlimited")
	stressCmd.Flags().StringVarP(&requestMethod, "requestMethod", "X", "GET", "Request type. GET, HEAD, POST, PUT, etc.")
	stressCmd.Flags().IntVarP(&verboseLevel, "verbose", "v", 0, "Level of verbosity ("+strconv.Itoa(VerboseNone)+"-"+strconv.Itoa(VerboseHigh)+")")
}

// stressCmd represents the stress command
var stressCmd = &cobra.Command{
	Use:   "stress http[s]://hostname[:port]/path",
	Short: "Run predefined load of requests",
	Long:  `Run predefined load of requests`,
	RunE:  runStress,
}

func runStress(cmd *cobra.Command, args []string) error {
	//checks
	if len(args) != 1 {
		return errors.New("needs URL")
	}
	if numTests <= 0 {
		return errors.New("number of requests must be one or more")
	}
	if concurrency <= 0 {
		return errors.New("concurrency must be one or more")
	}
	if timeout < 0 {
		return errors.New("timeout must be zero or more")
	}
	if concurrency > numTests {
		return errors.New("concurrency must be higher than number of requests")
	}
	if verboseLevel < VerboseNone || verboseLevel > VerboseHigh {
		return errors.New("verbose level must be between " + strconv.Itoa(VerboseNone) + " and " + strconv.Itoa(VerboseHigh))
	}

	url := args[0]

	fmt.Println("Stress testing " + url + "...")

	//setup the queue of requests
	requestChan := make(chan *http.Request, numTests)
	for i := 0; i < numTests; i++ {
		//TODO optimize by not creating a new http request each time since it's the same thing
		req, err := http.NewRequest(requestMethod, url, nil)
		if err != nil {
			return errors.New("failed to create request: " + err.Error())
		}
		requestChan <- req
	}
	close(requestChan)

	workerDoneChan := make(chan workerDone)   //workers use this to indicate they are done
	requestStatChan := make(chan requestStat) //workers communicate each requests' info

	//workers
	totalStartTime := time.Now()
	for i := 0; i < concurrency; i++ {
		//TODO handle the returned errors from this
		go func() error {
			client := &http.Client{Timeout: time.Duration(timeout) * time.Second}
			for {
				select {
				case req, ok := <-requestChan:
					if !ok {
						workerDoneChan <- workerDone{}
						return nil
					}
					//run the acutal request
					reqStartTime := time.Now()
					response, err := client.Do((*http.Request)(req))
					reqEndTime := time.Now()
					if err != nil {
						return errors.New("Failed to make request:" + err.Error())
					}
					reqTimeNs := (reqEndTime.UnixNano() - reqStartTime.UnixNano())

					var requestData string
					if verboseLevel >= VerboseLow {
						requestData = "--------\n\n"
					}
					if verboseLevel >= VerboseLow {
						//request timing
						requestData = requestData + fmt.Sprintf("Request took %dms\n\n", reqTimeNs/1000000)
					}
					if verboseLevel >= VerboseMedium {
						//reponse metadata
						requestData = requestData + fmt.Sprintf("Response:\n%+v\n\n", response)
					}
					if verboseLevel >= VerboseHigh {
						//reponse body
						defer response.Body.Close()
						body, err := ioutil.ReadAll(response.Body)
						if err != nil {
							return errors.New("Failed to read response body:" + err.Error())
						}
						requestData = requestData + fmt.Sprintf("Body:\n%s\n\n", body)
					}

					if requestData != "" {
						fmt.Print(requestData)
					}
					requestStatChan <- requestStat{duration: reqTimeNs}
				}
			}
		}()
	}

	allRequestStats := make([]requestStat, numTests)
	requestsCompleteCount := 0
	workersDoneCount := 0
	//wait for all workers to finish
	for {
		select {
		case <-workerDoneChan:
			workersDoneCount++
			if workersDoneCount == concurrency {
				//all workers are done
				totalEndTime := time.Now()

				reqStats := createRequestsStats(allRequestStats)
				totalTimeNs := totalEndTime.UnixNano() - totalStartTime.UnixNano()
				fmt.Println(createTextSummary(reqStats, totalTimeNs))
				return nil
			}
		case requestStat := <-requestStatChan:
			allRequestStats[requestsCompleteCount] = requestStat
			requestsCompleteCount++
		}
	}
}

func createRequestsStats(requestStats []requestStat) requestStatSummary {
	if len(requestStats) == 0 {
		return requestStatSummary{}
	}

	summary := requestStatSummary{maxDuration: requestStats[0].duration, minDuration: requestStats[0].duration}
	var totalDurations int64
	totalDurations = 0
	for i := 0; i < len(requestStats); i++ {
		if requestStats[i].duration > summary.maxDuration {
			summary.maxDuration = requestStats[i].duration
		}
		if requestStats[i].duration < summary.minDuration {
			summary.minDuration = requestStats[i].duration
		}
		totalDurations += requestStats[i].duration
	}
	summary.avgDuration = totalDurations / int64(len(requestStats))
	return summary
}

func createTextSummary(reqStatSummary requestStatSummary, totalTimeNs int64) string {
	summary := "\n"
	summary = summary + "Average:    " + strconv.Itoa(int(reqStatSummary.avgDuration/1000000)) + "ms\n"
	summary = summary + "Max:        " + strconv.Itoa(int(reqStatSummary.maxDuration/1000000)) + "ms\n"
	summary = summary + "Min:        " + strconv.Itoa(int(reqStatSummary.minDuration/1000000)) + "ms\n"
	summary = summary + "Total Time: " + strconv.Itoa(int(totalTimeNs/1000000)) + "ms"
	return summary
}
<commit_msg>Summary formatting and adding in qps calculation<commit_after>package cmd

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"github.com/spf13/cobra"
)

type workerDone struct{}

type requestStat struct {
	duration int64 //nanoseconds
}
type requestStatSummary struct {
	avgQps      float64 //per nanoseconds
	avgDuration int64   //nanoseconds
	maxDuration int64   //nanoseconds
	minDuration int64   //nanoseconds
}

//verbose levels
const (
	VerboseNone = iota
	VerboseLow
	VerboseMedium
	VerboseHigh
)

//flags
var (
	numTests      int
	timeout       int
	concurrency   int
	requestMethod string
	verboseLevel  int
)

func init() {
	RootCmd.AddCommand(stressCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// stressCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// stressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

	stressCmd.Flags().IntVarP(&numTests, "num", "n", 100, "Number of requests to make")
	stressCmd.Flags().IntVarP(&concurrency, "concurrent", "c", 1, "Number of multiple requests to make")
	stressCmd.Flags().IntVarP(&timeout, "timeout", "t", 0, "Maximum seconds to wait for response. 0 means unlimited")
	stressCmd.Flags().StringVarP(&requestMethod, "requestMethod", "X", "GET", "Request type. GET, HEAD, POST, PUT, etc.")
	stressCmd.Flags().IntVarP(&verboseLevel, "verbose", "v", 0, "Level of verbosity ("+strconv.Itoa(VerboseNone)+"-"+strconv.Itoa(VerboseHigh)+")")
}

// stressCmd represents the stress command
var stressCmd = &cobra.Command{
	Use:   "stress http[s]://hostname[:port]/path",
	Short: "Run predefined load of requests",
	Long:  `Run predefined load of requests`,
	RunE:  runStress,
}

func runStress(cmd *cobra.Command, args []string) error {
	//checks
	if len(args) != 1 {
		return errors.New("needs URL")
	}
	if numTests <= 0 {
		return errors.New("number of requests must be one or more")
	}
	if concurrency <= 0 {
		return errors.New("concurrency must be one or more")
	}
	if timeout < 0 {
		return errors.New("timeout must be zero or more")
	}
	if concurrency > numTests {
		return errors.New("concurrency must be higher than number of requests")
	}
	if verboseLevel < VerboseNone || verboseLevel > VerboseHigh {
		return errors.New("verbose level must be between " + strconv.Itoa(VerboseNone) + " and " + strconv.Itoa(VerboseHigh))
	}

	url := args[0]

	fmt.Println("Stress testing " + url + "...")

	//setup the queue of requests
	requestChan := make(chan *http.Request, numTests)
	for i := 0; i < numTests; i++ {
		//TODO optimize by not creating a new http request each time since it's the same thing
		req, err := http.NewRequest(requestMethod, url, nil)
		if err != nil {
			return errors.New("failed to create request: " + err.Error())
		}
		requestChan <- req
	}
	close(requestChan)

	workerDoneChan := make(chan workerDone)   //workers use this to indicate they are done
	requestStatChan := make(chan requestStat) //workers communicate each requests' info

	//workers
	totalStartTime := time.Now()
	for i := 0; i < concurrency; i++ {
		//TODO handle the returned errors from this
		go func() error {
			client := &http.Client{Timeout: time.Duration(timeout) * time.Second}
			for {
				select {
				case req, ok := <-requestChan:
					if !ok {
						workerDoneChan <- workerDone{}
						return nil
					}
					//run the acutal request
					reqStartTime := time.Now()
					response, err := client.Do((*http.Request)(req))
					reqEndTime := time.Now()
					if err != nil {
						return errors.New("Failed to make request:" + err.Error())
					}
					reqTimeNs := (reqEndTime.UnixNano() - reqStartTime.UnixNano())

					var requestData string
					if verboseLevel >= VerboseLow {
						requestData = "--------\n\n"
					}
					if verboseLevel >= VerboseLow {
						//request timing
						requestData = requestData + fmt.Sprintf("Request took %dms\n\n", reqTimeNs/1000000)
					}
					if verboseLevel >= VerboseMedium {
						//reponse metadata
						requestData = requestData + fmt.Sprintf("Response:\n%+v\n\n", response)
					}
					if verboseLevel >= VerboseHigh {
						//reponse body
						defer response.Body.Close()
						body, err := ioutil.ReadAll(response.Body)
						if err != nil {
							return errors.New("Failed to read response body:" + err.Error())
						}
						requestData = requestData + fmt.Sprintf("Body:\n%s\n\n", body)
					}

					if requestData != "" {
						fmt.Print(requestData)
					}
					requestStatChan <- requestStat{duration: reqTimeNs}
				}
			}
		}()
	}

	allRequestStats := make([]requestStat, numTests)
	requestsCompleteCount := 0
	workersDoneCount := 0
	//wait for all workers to finish
	for {
		select {
		case <-workerDoneChan:
			workersDoneCount++
			if workersDoneCount == concurrency {
				//all workers are done
				totalEndTime := time.Now()

				totalTimeNs := totalEndTime.UnixNano() - totalStartTime.UnixNano()
				reqStats := createRequestsStats(allRequestStats, totalTimeNs)
				fmt.Println(createTextSummary(reqStats, totalTimeNs))
				return nil
			}
		case requestStat := <-requestStatChan:
			allRequestStats[requestsCompleteCount] = requestStat
			requestsCompleteCount++
		}
	}
}

//create statistical summary of all requests
func createRequestsStats(requestStats []requestStat, totalTimeNs int64) requestStatSummary {
	if len(requestStats) == 0 {
		return requestStatSummary{}
	}

	summary := requestStatSummary{maxDuration: requestStats[0].duration, minDuration: requestStats[0].duration}
	var totalDurations int64
	totalDurations = 0 //total time of all requests (concurrent is counted)
	for i := 0; i < len(requestStats); i++ {
		if requestStats[i].duration > summary.maxDuration {
			summary.maxDuration = requestStats[i].duration
		}
		if requestStats[i].duration < summary.minDuration {
			summary.minDuration = requestStats[i].duration
		}
		totalDurations += requestStats[i].duration
	}
	summary.avgDuration = totalDurations / int64(len(requestStats))
	summary.avgQps = float64(len(requestStats)) / float64(totalTimeNs)
	return summary
}

//creates nice readable summary of entire stress test
func createTextSummary(reqStatSummary requestStatSummary, totalTimeNs int64) string {
	summary := "\n"

	summary = summary + "Runtime Statistics:\n"
	summary = summary + "Total time:  " + strconv.Itoa(int(totalTimeNs/1000000)) + " ms\n"
	summary = summary + "Mean QPS:    " + fmt.Sprintf("%.2f", reqStatSummary.avgQps*1000000000) + " req/sec\n"

	summary = summary + "\nQuery Statistics\n"
	summary = summary + "Mean query:     " + strconv.Itoa(int(reqStatSummary.avgDuration/1000000)) + " ms\n"
	summary = summary + "Fastest query:  " + strconv.Itoa(int(reqStatSummary.minDuration/1000000)) + " ms\n"
	summary = summary + "Slowest query:  " + strconv.Itoa(int(reqStatSummary.maxDuration/1000000)) + " ms\n"
	return summary
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"path/filepath"
	"sort"
	"strings"
)

// `direnv export $0`
var CmdExport = &Cmd{
	Name:    "export",
	Desc:    "loads an .envrc and prints the diff in terms of exports",
	Args:    []string{"SHELL"},
	Private: true,
	Fn: func(env Env, args []string) (err error) {
		var oldEnv Env = env.Copy()
		var newEnv Env
		var loadedRC *RC
		var foundRC *RC
		var config *Config
		var target string

		if len(args) > 1 {
			target = args[1]
		}

		shell := DetectShell(target)
		if shell == nil {
			return fmt.Errorf("Unknown target shell '%s'", target)
		}

		if config, err = LoadConfig(env); err != nil {
			return
		}

		loadedRC = config.LoadedRC()
		foundRC = config.FindRC()

		loadRC := func() {
			newEnv, err = foundRC.Load(config, oldEnv)
		}

		//fmt.Fprintf(os.Stderr, "%v %v\n", loadedRC, foundRC)

		if loadedRC == nil {
			if foundRC == nil {
				// We're done here.
				return nil
			}

			loadRC()
		} else {
			var backupDiff *EnvDiff
			if backupDiff, err = config.EnvDiff(); err != nil {
				err = fmt.Errorf("EnvDiff() failed: %q", err)
				goto error
			}
			oldEnv = backupDiff.Reverse().Patch(env)
			if foundRC == nil {
				log("unloading")
				newEnv = oldEnv.Copy()
				delete(newEnv, DIRENV_DIR)
				delete(newEnv, DIRENV_MTIME)
				delete(newEnv, DIRENV_DIFF)
			} else if loadedRC.path != foundRC.path {
				log("switching")
				loadRC()
			} else if loadedRC.mtime != foundRC.mtime {
				log("reloading")
				loadRC()
			} else {
				// Nothing to do. Env is loaded and hasn't changed
				return nil
			}
		}

	error:
		if err != nil {
			newEnv = oldEnv.Copy()
			delete(oldEnv, DIRENV_DIR)
			delete(oldEnv, DIRENV_MTIME)
			delete(oldEnv, DIRENV_DIFF)
			if foundRC != nil {
				delete(newEnv, DIRENV_DIFF)
				// This should be nearby rc.Load()'s similar statement
				newEnv[DIRENV_DIR] = "-" + filepath.Dir(foundRC.path)
				newEnv[DIRENV_MTIME] = fmt.Sprintf("%d", foundRC.mtime)
				newEnv[DIRENV_DIFF] = oldEnv.Diff(newEnv).Serialize()
			}
		}

		diff := env.Diff(newEnv)

		if diff.Any() {
			var out []string
			for key, _ := range diff.Prev {
				_, ok := diff.Next[key]
				if !ok {
					out = append(out, "-"+key)
				}
			}
			for key := range diff.Next {
				_, ok := diff.Prev[key]
				if ok {
					out = append(out, "~"+key)
				} else {
					out = append(out, "+"+key)
				}
			}
			sort.Strings(out)
			log("export %s", strings.Join(out, " "))
		}

		str := diff.ToShell(shell)
		fmt.Print(str)

		return
	},
}
<commit_msg>Hides the DIRENV_ variables in the output diff. Fixes #94<commit_after>package main

import (
	"fmt"
	"path/filepath"
	"sort"
	"strings"
)

// `direnv export $0`
var CmdExport = &Cmd{
	Name:    "export",
	Desc:    "loads an .envrc and prints the diff in terms of exports",
	Args:    []string{"SHELL"},
	Private: true,
	Fn: func(env Env, args []string) (err error) {
		var oldEnv Env = env.Copy()
		var newEnv Env
		var loadedRC *RC
		var foundRC *RC
		var config *Config
		var target string

		if len(args) > 1 {
			target = args[1]
		}

		shell := DetectShell(target)
		if shell == nil {
			return fmt.Errorf("Unknown target shell '%s'", target)
		}

		if config, err = LoadConfig(env); err != nil {
			return
		}

		loadedRC = config.LoadedRC()
		foundRC = config.FindRC()

		loadRC := func() {
			newEnv, err = foundRC.Load(config, oldEnv)
		}

		//fmt.Fprintf(os.Stderr, "%v %v\n", loadedRC, foundRC)

		if loadedRC == nil {
			if foundRC == nil {
				// We're done here.
				return nil
			}

			loadRC()
		} else {
			var backupDiff *EnvDiff
			if backupDiff, err = config.EnvDiff(); err != nil {
				err = fmt.Errorf("EnvDiff() failed: %q", err)
				goto error
			}
			oldEnv = backupDiff.Reverse().Patch(env)
			if foundRC == nil {
				log("unloading")
				newEnv = oldEnv.Copy()
				delete(newEnv, DIRENV_DIR)
				delete(newEnv, DIRENV_MTIME)
				delete(newEnv, DIRENV_DIFF)
			} else if loadedRC.path != foundRC.path {
				log("switching")
				loadRC()
			} else if loadedRC.mtime != foundRC.mtime {
				log("reloading")
				loadRC()
			} else {
				// Nothing to do. Env is loaded and hasn't changed
				return nil
			}
		}

	error:
		if err != nil {
			newEnv = oldEnv.Copy()
			delete(oldEnv, DIRENV_DIR)
			delete(oldEnv, DIRENV_MTIME)
			delete(oldEnv, DIRENV_DIFF)
			if foundRC != nil {
				delete(newEnv, DIRENV_DIFF)
				// This should be nearby rc.Load()'s similar statement
				newEnv[DIRENV_DIR] = "-" + filepath.Dir(foundRC.path)
				newEnv[DIRENV_MTIME] = fmt.Sprintf("%d", foundRC.mtime)
				newEnv[DIRENV_DIFF] = oldEnv.Diff(newEnv).Serialize()
			}
		}

		diff := env.Diff(newEnv)

		if diff.Any() {
			var out []string
			for key, _ := range diff.Prev {
				_, ok := diff.Next[key]
				if !ok && !direnvKey(key) {
					out = append(out, "-"+key)
				}
			}
			for key := range diff.Next {
				_, ok := diff.Prev[key]
				if direnvKey(key) {
					continue
				}
				if ok {
					out = append(out, "~"+key)
				} else {
					out = append(out, "+"+key)
				}
			}
			sort.Strings(out)
			log("export %s", strings.Join(out, " "))
		}

		str := diff.ToShell(shell)
		fmt.Print(str)

		return
	},
}

func direnvKey(key string) bool {
	return strings.HasPrefix(key, "DIRENV_")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

// `direnv stdlib`
var CmdStdlib = &Cmd{
	Name:    "stdlib",
	Desc:    "Outputs the stdlib that is available in the .envrc",
	Private: true,
	Fn: func(env Env, args []string) (err error) {
		var config *Config
		if config, err = LoadConfig(env); err != nil {
			return
		}

		fmt.Printf(STDLIB, config.SelfPath)
		return
	},
}

const STDLIB = `
# These are the commands available in an .envrc context
set -e
DIRENV_PATH="%s"

# Usage: has something
# determines if "something" is availabe as a command
has() {
	type "$1" &>/dev/null
}

# Usage: expand_path ./rel/path [RELATIVE_TO]
# RELATIVE_TO is $PWD by default
expand_path() {
	"$DIRENV_PATH" expand_path "$@"
}

# Usage: dotenv
# Loads a .env in the current environment
dotenv() {
	eval "$("$DIRENV_PATH" dotenv "$@")"
}

# Usage: user_rel_path /Users/you/some_path => ~/some_path
user_rel_path() {
	local path="${1#-}"

	if [ -z "$path" ]; then return; fi

	if [ -n "$HOME" ]; then
		local rel_path="${path#$HOME}"
		if [ "$rel_path" != "$path" ]; then
			path="~${rel_path}"
		fi
	fi

	echo $path
}

# Usage: find_up some_file
find_up() {
	(
		cd "$(pwd -P 2>/dev/null)"
		while true; do
			if [ -f "$1" ]; then
				echo $PWD/$1
				return 0
			fi
			if [ "$PWD" = "/" ] || [ "$PWD" = "//" ]; then
				return 1
			fi
			cd ..
		done
	)
}

direnv_find_rc() {
	local path="$(find_up .envrc)"
	if [ -n "$path" ]; then
		cd "$(dirname "$path")"
		return 0
	else
		return 1
	fi
}

# Safer PATH handling
#
# Usage: PATH_add PATH
# Example: PATH_add bin
PATH_add() {
	export PATH="$(expand_path "$1"):$PATH"
}

# Safer path handling
#
# Usage: path_add VARNAME PATH
# Example: path_add LD_LIBRARY_PATH ./lib
path_add() {
	local old_paths=${!1}
	local path="$(expand_path "$2")"

	if [ -z "$old_paths" ]; then
		old_paths="$path"
	else
		old_paths="$path:$old_paths"
	fi

	export $1="$old_paths"
}

# Usage: layout ruby
layout_ruby() {
	# TODO: ruby_version should be the ABI version
	local ruby_version="$(ruby -e"puts (defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby') + '-' + RUBY_VERSION")"

	export GEM_HOME="$PWD/.direnv/${ruby_version}"
	export BUNDLE_BIN="$PWD/.direnv/bin"

	PATH_add ".direnv/${ruby_version}/bin"
	PATH_add ".direnv/bin"
}

layout_python() {
	if ! [ -d .direnv/virtualenv ]; then
		virtualenv --no-site-packages --distribute .direnv/virtualenv
		virtualenv --relocatable .direnv/virtualenv
	fi
	source .direnv/virtualenv/bin/activate
}

layout_node() {
	PATH_add node_modules/.bin
}

layout() {
	eval "layout_$1"
}

# This folder contains a <program-name>/<version> structure
cellar_path=/usr/local/Cellar
set_cellar_path() {
	cellar_path="$1"
}

# Usage: use PROGRAM_NAME VERSION
# Example: use ruby 1.9.3
use() {
	local cmd="$1"
	if has use_$cmd ; then
		echo "Using $@"
		shift
		use_$cmd "$@"
		return $?
	fi

	local path="$cellar_path/$1/$2/bin"
	if [ -d "$path" ]; then
		echo "Using $1 v$2"
		PATH_add "$path"
		return
	fi

	echo "* Unable to load $path"
	return 1
}

use_rbenv() {
	eval "$(rbenv init -)"
}

# Inherit another .envrc
# Usage: source_env <FILE_OR_DIR_PATH>
source_env() {
	local rcfile="$1"
	if ! [ -f "$1" ]; then
		rcfile="$rcfile/.envrc"
	fi
	echo "direnv: loading $(user_rel_path "$rcfile")"
	pushd "$(dirname "$rcfile")" > /dev/null
	set +u
	. "./$(basename "$rcfile")"
	popd > /dev/null
}

# Inherits the first .envrc (or given FILE_NAME) it finds in the path
# Usage: source_up [FILE_NAME]
source_up() {
	local file="$1"
	if [ -z "$file" ]; then
		file=".envrc"
	fi
	local path="$(cd .. && find_up "$file")"
	if [ -n "$path" ]; then
		source_env "$path"
	fi
}

# Sources rvm on first call. Should work like the rvm command-line.
rvm() {
	unset rvm
	if [ -n "${rvm_scripts_path:-}" ]; then
		source "${rvm_scripts_path}/rvm"
	elif [ -n "${rvm_path:-}" ]; then
		source "${rvm_path}/scripts/rvm"
	else
		source "$HOME/.rvm/scripts/rvm"
	fi
	rvm "$@"
}

## Load the global ~/.direnvrc

if [ -f ~/.direnvrc ]; then
	source_env ~/.direnvrc >&2
fi
`
<commit_msg>First pass at the prefix-loading idea as described in #40<commit_after>package main

import (
	"fmt"
)

// `direnv stdlib`
var CmdStdlib = &Cmd{
	Name:    "stdlib",
	Desc:    "Outputs the stdlib that is available in the .envrc",
	Private: true,
	Fn: func(env Env, args []string) (err error) {
		var config *Config
		if config, err = LoadConfig(env); err != nil {
			return
		}

		fmt.Printf(STDLIB, config.SelfPath)
		return
	},
}

const STDLIB = `
# These are the commands available in an .envrc context
set -e
DIRENV_PATH="%s"

# Usage: has something
# determines if "something" is availabe as a command
has() {
	type "$1" &>/dev/null
}

# Usage: expand_path ./rel/path [RELATIVE_TO]
# RELATIVE_TO is $PWD by default
expand_path() {
	"$DIRENV_PATH" expand_path "$@"
}

# Usage: dotenv
# Loads a .env in the current environment
dotenv() {
	eval "$("$DIRENV_PATH" dotenv "$@")"
}

# Usage: user_rel_path /Users/you/some_path => ~/some_path
user_rel_path() {
	local path="${1#-}"

	if [ -z "$path" ]; then return; fi

	if [ -n "$HOME" ]; then
		local rel_path="${path#$HOME}"
		if [ "$rel_path" != "$path" ]; then
			path="~${rel_path}"
		fi
	fi

	echo $path
}

# Usage: find_up some_file
find_up() {
	(
		cd "$(pwd -P 2>/dev/null)"
		while true; do
			if [ -f "$1" ]; then
				echo $PWD/$1
				return 0
			fi
			if [ "$PWD" = "/" ] || [ "$PWD" = "//" ]; then
				return 1
			fi
			cd ..
		done
	)
}

direnv_find_rc() {
	local path="$(find_up .envrc)"
	if [ -n "$path" ]; then
		cd "$(dirname "$path")"
		return 0
	else
		return 1
	fi
}

# Safer PATH handling
#
# Usage: PATH_add PATH
# Example: PATH_add bin
PATH_add() {
	export PATH="$(expand_path "$1"):$PATH"
}

# Safer path handling
#
# Usage: path_add VARNAME PATH
# Example: path_add LD_LIBRARY_PATH ./lib
path_add() {
	local old_paths=${!1}
	local path="$(expand_path "$2")"

	if [ -z "$old_paths" ]; then
		old_paths="$path"
	else
		old_paths="$path:$old_paths"
	fi

	export $1="$old_paths"
}

# Usage: layout ruby
layout_ruby() {
	# TODO: ruby_version should be the ABI version
	local ruby_version="$(ruby -e"puts (defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby') + '-' + RUBY_VERSION")"

	export GEM_HOME="$PWD/.direnv/${ruby_version}"
	export BUNDLE_BIN="$PWD/.direnv/bin"

	PATH_add ".direnv/${ruby_version}/bin"
	PATH_add ".direnv/bin"
}

layout_python() {
	if ! [ -d .direnv/virtualenv ]; then
		virtualenv --no-site-packages --distribute .direnv/virtualenv
		virtualenv --relocatable .direnv/virtualenv
	fi
	source .direnv/virtualenv/bin/activate
}

layout_node() {
	PATH_add node_modules/.bin
}

layout() {
	eval "layout_$1"
}

# This folder contains a <program-name>/<version> structure
cellar_path=/usr/local/Cellar
set_cellar_path() {
	cellar_path="$1"
}

# Usage: use PROGRAM_NAME VERSION
# Example: use ruby 1.9.3
use() {
	local cmd="$1"
	if has use_$cmd ; then
		echo "Using $@"
		shift
		use_$cmd "$@"
		return $?
	fi

	local path="$cellar_path/$1/$2/bin"
	if [ -d "$path" ]; then
		echo "Using $1 v$2"
		PATH_add "$path"
		return
	fi

	echo "* Unable to load $path"
	return 1
}

use_rbenv() {
	eval "$(rbenv init -)"
}

# Inherit another .envrc
# Usage: source_env <FILE_OR_DIR_PATH>
source_env() {
	local rcfile="$1"
	if ! [ -f "$1" ]; then
		rcfile="$rcfile/.envrc"
	fi
	echo "direnv: loading $(user_rel_path "$rcfile")"
	pushd "$(dirname "$rcfile")" > /dev/null
	set +u
	. "./$(basename "$rcfile")"
	popd > /dev/null
}

# Inherits the first .envrc (or given FILE_NAME) it finds in the path
# Usage: source_up [FILE_NAME]
source_up() {
	local file="$1"
	if [ -z "$file" ]; then
		file=".envrc"
	fi
	local path="$(cd .. && find_up "$file")"
	if [ -n "$path" ]; then
		source_env "$path"
	fi
}

#
# Usage: load_prefix PATH
load_prefix() {
	local path="$(expand_path "$1")"
	path_add CPATH "$path/include"
	path_add LD_LIBRARY_PATH "$path/lib"
	path_add LIBRARY_PATH "$path/lib"
	path_add MANPATH "$path/man"
	path_add MANPATH "$path/share/man"
	path_add PATH "$path/bin"
	path_add PKG_CONFIG_PATH "$path/lib/pkgconfig"
}

# Sources rvm on first call. Should work like the rvm command-line.
rvm() {
	unset rvm
	if [ -n "${rvm_scripts_path:-}" ]; then
		source "${rvm_scripts_path}/rvm"
	elif [ -n "${rvm_path:-}" ]; then
		source "${rvm_path}/scripts/rvm"
	else
		source "$HOME/.rvm/scripts/rvm"
	fi
	rvm "$@"
}

## Load the global ~/.direnvrc

if [ -f ~/.direnvrc ]; then
	source_env ~/.direnvrc >&2
fi
`
<|endoftext|>


<commit_before>// Copyright 2013-2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Print process information.
//
// Synopsis:
//     id
//
// Description:
//     id displays the uid, guid and groups of the calling process
//
// Options:
package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"syscall"
)

var (
	GROUP_FILE  = "/etc/group"
	PASSWD_FILE = "/etc/passwd"
)

type Group struct {
	Name   string
	Number int
}

type User struct {
	Name   string
	Uid    int
	Euid   int
	Groups []*Group
}

func (u *User) getUid() {
	u.Uid = syscall.Getuid()
}

func (u *User) getEuid() {
	u.Uid = syscall.Getieuid()
}

func (u *User) getGroups() {
	groupsNumbers, err := syscall.Getgroups()
	if err != nil {
		log.Fatal(err)
	}

	groupsMap := readGroups()

	for _, groupNum := range groupsNumbers {
		u.Groups = append(u.Groups, Group{
			Name:   groupsMap[groupNum],
			Number: groupNum,
		})
	}

}

func readGroups() (map[int]string, error) {
	groupFile, err := os.Open(GROUP_FILE)
	if err != nil {
		return nil, err
	}

	var line string
	var groupInfo []string

	groupsMap := make(map[int]string)
	groupScanner := bufio.NewScanner(groupFile)

	for groupScanner.Scan() {
		groupInfo = strings.Split(groupScanner.Text(), ":")
		groupsMap[strconv.Atoi(groupInfo[2])] = groupInfo[0]
	}

	return groupMap, nil
}

func main() {
	uid := syscall.Getuid()
	gid := syscall.Getgid()
	groups, err := syscall.Getgroups()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("uid: %d\n", uid)
	fmt.Printf("gid: %d\n", gid)

	fmt.Print("groups: ")
	for _, group := range groups {
		fmt.Printf("%d ", group)
	}
	fmt.Println()

}
<commit_msg>Add creator methods for user and group<commit_after>// Copyright 2013-2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Print process information.
//
// Synopsis:
//     id
//
// Description:
//     id displays the uid, guid and groups of the calling process
//
// Options:
package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"syscall"
)

var (
	GROUP_FILE  = "/etc/group"
	PASSWD_FILE = "/etc/passwd"
)

type Group struct {
	Name   string
	Number int
}

type User struct {
	Name   string
	Uid    int
	Euid   int
	Groups []*Group
}

func (u *User) pullUid() {
	u.Uid = syscall.Getuid()
}

func (u *User) pullEuid() {
	u.Uid = syscall.Getieuid()
}

func (u *User) pullName() {
	passwdFile, err := os.Open(PASSWD_FILE)
	if err != nil {
		log.Fatal(err)
	}

	var passwdInfo []string

	passwdScanner = bufio.NewScanner(PASSWD_FILE)

	for passwdScanner.Scan() {
		passwdInfo = strings.Split(passwdScanner.Text(), ":")
		if passwdInfo[2] == u.getUid() {
			u.Name = passwdInfo[0]
			return
		}
	}

	log.Fatal()
}

func (u *User) pullGroups() {
	groupsNumbers, err := syscall.Getgroups()
	if err != nil {
		log.Fatal(err)
	}

	groupsMap, err := readGroups()
	if err != nil {
		log.Fatal(err)
	}

	for _, groupNum := range groupsNumbers {
		u.Groups = append(u.Groups, Group{
			Name:   groupsMap[groupNum],
			Number: groupNum,
		})
	}

}

func readGroups() (map[int]string, error) {
	groupFile, err := os.Open(GROUP_FILE)
	if err != nil {
		return nil, err
	}

	var groupInfo []string

	groupsMap := make(map[int]string)
	groupScanner := bufio.NewScanner(groupFile)

	for groupScanner.Scan() {
		groupInfo = strings.Split(groupScanner.Text(), ":")
		groupsMap[strconv.Atoi(groupInfo[2])] = groupInfo[0]
	}

	return groupMap, nil
}

func (u *User) Init() {
	u.pullUid()
	u.pullEuid()
	u.pullGroups()
	u.pullName()
}

func main() {
	uid := syscall.Getuid()
	gid := syscall.Getgid()
	groups, err := syscall.Getgroups()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("uid: %d\n", uid)
	fmt.Printf("gid: %d\n", gid)

	fmt.Print("groups: ")
	for _, group := range groups {
		fmt.Printf("%d ", group)
	}
	fmt.Println()

}
<|endoftext|>