<commit_before>package main

import (
	"admin"
	"api/http"
	"configuration"
	"coordinator"
	"datastore"
	"engine"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"syscall"
	"time"
)

const (
	version = "dev"
	gitSha  = ""
)

func waitForSignals(stopped <-chan bool) {
	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT)
	for {
		sig := <-ch
		fmt.Printf("Received signal: %s\n", sig.String())
		switch sig {
		case syscall.SIGINT, syscall.SIGTERM:
			runtime.SetCPUProfileRate(0)
			<-stopped
			os.Exit(0)
		}
	}
}

func startProfiler(filename *string) error {
	if filename == nil || *filename == "" {
		return nil
	}

	cpuProfileFile, err := os.Create(*filename)
	if err != nil {
		return err
	}
	runtime.SetCPUProfileRate(500)
	stopped := make(chan bool)

	go waitForSignals(stopped)

	go func() {
		for {
			select {
			default:
				data := runtime.CPUProfile()
				if data == nil {
					cpuProfileFile.Close()
					stopped <- true
					break
				}
				cpuProfileFile.Write(data)
			}
		}
	}()
	return nil
}

func main() {
	fileName := flag.String("config", "config.json.sample", "Config file")
	wantsVersion := flag.Bool("v", false, "Get version number")
	resetRootPassword := flag.Bool("reset-root", false, fmt.Sprintf("Reset root password to %s", coordinator.DEFAULT_ROOT_PWD))
	pidFile := flag.String("pidfile", "", "the pid file")
	cpuProfiler := flag.String("cpuprofile", "", "filename where cpu profile data will be written")

	runtime.GOMAXPROCS(runtime.NumCPU())
	flag.Parse()

	startProfiler(cpuProfiler)

	if wantsVersion != nil && *wantsVersion {
		fmt.Printf("InfluxDB v%s (git: %s)\n", version, gitSha)
		return
	}
	config := configuration.LoadConfiguration(*fileName)

	if pidFile != nil && *pidFile != "" {
		pid := strconv.Itoa(os.Getpid())
		if err := ioutil.WriteFile(*pidFile, []byte(pid), 0644); err != nil {
			panic(err)
		}
	}

	log.Println("Starting Influx Server...")
	clusterConfig := coordinator.NewClusterConfiguration()
	os.MkdirAll(config.RaftDir, 0744)

	raftServer := coordinator.NewRaftServer(config.RaftDir, "localhost", config.RaftServerPort, clusterConfig)
	go func() {
		raftServer.ListenAndServe(config.SeedServers, false)
	}()

	if *resetRootPassword {
		time.Sleep(2 * time.Second) // wait for the raft server to join the cluster

		if err := raftServer.CreateRootUser(); err != nil {
			panic(err)
		}
	}
	os.MkdirAll(config.DataDir, 0744)
	log.Println("Opening database at ", config.DataDir)
	db, err := datastore.NewLevelDbDatastore(config.DataDir)
	if err != nil {
		panic(err)
	}
	coord := coordinator.NewCoordinatorImpl(db, raftServer, clusterConfig)
	eng, err := engine.NewQueryEngine(coord)
	if err != nil {
		panic(err)
	}
	log.Println()
	adminServer := admin.NewHttpServer(config.AdminAssetsDir, config.AdminHttpPortString())
	log.Println("Starting admin interface on port", config.AdminHttpPort)
	go func() {
		adminServer.ListenAndServe()
	}()
	log.Println("Starting Http Api server on port", config.ApiHttpPort)
	server := http.NewHttpServer(config.ApiHttpPortString(), eng, coord, coord)
	server.ListenAndServe()
}
<commit_msg>log a sentence when we reset the root password.<commit_after>package main

import (
	"admin"
	"api/http"
	"configuration"
	"coordinator"
	"datastore"
	"engine"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"syscall"
	"time"
)

const (
	version = "dev"
	gitSha  = ""
)

func waitForSignals(stopped <-chan bool) {
	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT)
	for {
		sig := <-ch
		fmt.Printf("Received signal: %s\n", sig.String())
		switch sig {
		case syscall.SIGINT, syscall.SIGTERM:
			runtime.SetCPUProfileRate(0)
			<-stopped
			os.Exit(0)
		}
	}
}

func startProfiler(filename *string) error {
	if filename == nil || *filename == "" {
		return nil
	}

	cpuProfileFile, err := os.Create(*filename)
	if err != nil {
		return err
	}
	runtime.SetCPUProfileRate(500)
	stopped := make(chan bool)

	go waitForSignals(stopped)

	go func() {
		for {
			select {
			default:
				data := runtime.CPUProfile()
				if data == nil {
					cpuProfileFile.Close()
					stopped <- true
					break
				}
				cpuProfileFile.Write(data)
			}
		}
	}()
	return nil
}

func main() {
	fileName := flag.String("config", "config.json.sample", "Config file")
	wantsVersion := flag.Bool("v", false, "Get version number")
	resetRootPassword := flag.Bool("reset-root", false, "Reset root password")
	pidFile := flag.String("pidfile", "", "the pid file")
	cpuProfiler := flag.String("cpuprofile", "", "filename where cpu profile data will be written")

	runtime.GOMAXPROCS(runtime.NumCPU())
	flag.Parse()

	startProfiler(cpuProfiler)

	if wantsVersion != nil && *wantsVersion {
		fmt.Printf("InfluxDB v%s (git: %s)\n", version, gitSha)
		return
	}
	config := configuration.LoadConfiguration(*fileName)

	if pidFile != nil && *pidFile != "" {
		pid := strconv.Itoa(os.Getpid())
		if err := ioutil.WriteFile(*pidFile, []byte(pid), 0644); err != nil {
			panic(err)
		}
	}

	log.Println("Starting Influx Server...")
	clusterConfig := coordinator.NewClusterConfiguration()
	os.MkdirAll(config.RaftDir, 0744)

	raftServer := coordinator.NewRaftServer(config.RaftDir, "localhost", config.RaftServerPort, clusterConfig)
	go func() {
		raftServer.ListenAndServe(config.SeedServers, false)
	}()

	if *resetRootPassword {
		time.Sleep(2 * time.Second) // wait for the raft server to join the cluster

		fmt.Printf("Resetting root's password to %s", coordinator.DEFAULT_ROOT_PWD)
		if err := raftServer.CreateRootUser(); err != nil {
			panic(err)
		}
	}
	os.MkdirAll(config.DataDir, 0744)
	log.Println("Opening database at ", config.DataDir)
	db, err := datastore.NewLevelDbDatastore(config.DataDir)
	if err != nil {
		panic(err)
	}
	coord := coordinator.NewCoordinatorImpl(db, raftServer, clusterConfig)
	eng, err := engine.NewQueryEngine(coord)
	if err != nil {
		panic(err)
	}
	log.Println()
	adminServer := admin.NewHttpServer(config.AdminAssetsDir, config.AdminHttpPortString())
	log.Println("Starting admin interface on port", config.AdminHttpPort)
	go func() {
		adminServer.ListenAndServe()
	}()
	log.Println("Starting Http Api server on port", config.ApiHttpPort)
	server := http.NewHttpServer(config.ApiHttpPortString(), eng, coord, coord)
	server.ListenAndServe()
}
<|endoftext|>


<commit_before>package definition_test

import (
	"bytes"
	"fmt"
	"io"

	"github.com/dekelund/unbrokenwing/compiler/definition"
)

func Example_NewDefinition() {

	buffer := bytes.NewBufferString(`
package step_definitions

Given("^I'm successfully logged in as an admin in users pane$", func(args Args) error {
	_ = ioutil.Discard
	return Pending("Not implemented")
})
And("^I fill in a new developer named hacker with password changeme$", func(args Args) error {
	_ = strings.Join([]string{}, "")
	return Pending("Not implemented")
})

import "strings"

	`)

	def := definition.NewDefinition(buffer)

	fmt.Println(def.Code())
	// Output:
	// package main
	//
	// import (
	// 	. "github.com/dekelund/unbrokenwing/unbrokenwing"
	// 	"github.com/dekelund/stdres"
	// 	"strconv"
	// 	"os"
	// 	"log"
	// 	"testing"
	// )
	//
	// import "strings"  // FIXME: This will not work with "import ("
	//
	// func setup() {
	// Given("^I'm successfully logged in as an admin in users pane$", func(args Args) error {
	// 	_ = ioutil.Discard
	// 	return Pending("Not implemented")
	// })
	// And("^I fill in a new developer named hacker with password changeme$", func(args Args) error {
	// 	_ = strings.Join([]string{}, "")
	// 	return Pending("Not implemented")
	// })
	// }
	//
	// func main() {
	// 	file := os.Args[1]
	// 	fd, err := os.Open(file)  // Open *.feature file
	// 	if err != nil {
	// 		log.Fatal("Error opening input file:", err)
	// 	}
	//
	// 	defer fd.Close()
	//
	// 	if pretty, err := strconv.ParseBool(os.Args[2]); err != nil {
	// 		log.Fatal("Error configuring pretty print: ", err)
	// 	} else if pretty {
	// 		stdres.EnableColor()
	// 	} else {
	// 		stdres.DisableColor()
	// 	}
	//
	// 	setup()
	// 	feature := NewFeature(fd)
	// 	suite := NewSuite()
	// 	t := testing.T{}
	// 	suite.Test(*feature, &t)
	// }

}

func Example_Run() {

	definitions := definition.NewDefinitions([]io.Reader{
		bytes.NewBufferString(`
package step_definitions

Given("^I'm successfully logged in as an admin in users pane$", func(args Args) error {
	_ = ioutil.Discard
	return Pending("Not implemented")
})
And("^I fill in a new developer named hacker with password changeme$", func(args Args) error {
	_ = strings.Join([]string{}, "")
	return Pending("Not implemented")
})

import "strings"

	`),
	}, false)

	features := bytes.NewBufferString(`
Feature: Manage users
    Administrators are able to manage all users.
    It's possible to add and remove users, but also
    change user kind, password and username.

    Following user kinds are supported by default
    setup:

    * Administrators:
        Setup new users and configures accessibility
        (Users and network interfaces)
    * Developers:
        Are able to setup new projects containing
        build and test configuration.
    * Applications:
        Rest and API systems, for instance external webpages.
    * Others:
        This category contains users with limited access.
        Project managers and field engineers are canonical users.
        Typical user scenario: tag release, download doployable
        build.

  Scenario: Create a new developer
    Given I'm successfully logged in as an admin in users pane
    And I fill in a new developer named hacker with password changeme
    When I press the create button
    Then only one user-record with name hacker should exist
    And user hacker should have password changeme
`)

	var pprint, debug bool

	definitions.Run(features, pprint, debug)

	// Output:
	// Feature: Manage users
	//
	//   Scenario: Create a new developer
	//
	//     Given I'm successfully logged in as an admin in users pane
	//
	//     And I fill in a new developer named hacker with password changeme
	//
	//     When I press the create button
	//
	//     Then only one user-record with name hacker should exist
	//
	//     And user hacker should have password changeme
	//
	//     1 scenario (0 undefined, 0 failures, 1 pending)
	//     5 steps (3 undefined, 0 failures, 1 pending, 1 optout)
	//
	//     You can implement step definition for undefined steps with these snippets:
	//
	//     And("^user hacker should have password changeme$", func(args Args) error {
	//         return Pending("Not implemented")
	//     })
	//
	//     Then("^only one user-record with name hacker should exist$", func(args Args) error {
	//         return Pending("Not implemented")
	//     })
	//
	//     When("^I press the create button$", func(args Args) error {
	//         return Pending("Not implemented")
	//     })
}
<commit_msg>TEST: Update definition test to latest API<commit_after>package definition_test

import (
	"bytes"
	"fmt"
	"io"

	"github.com/dekelund/unbrokenwing/compiler/definition"
)

func Example_NewDefinition() {

	buffer := bytes.NewBufferString(`
package step_definitions

Given("^I'm successfully logged in as an admin in users pane$", func(args Args) error {
	_ = ioutil.Discard
	return Pending("Not implemented")
})
And("^I fill in a new developer named hacker with password changeme$", func(args Args) error {
	_ = strings.Join([]string{}, "")
	return Pending("Not implemented")
})

import "strings"

	`)

	def := definition.NewDefinition(buffer)

	fmt.Println(def.Code())
	// Output:
	// package main
	//
	// import (
	// 	. "github.com/dekelund/unbrokenwing/unbrokenwing"
	// 	"github.com/dekelund/stdres"
	// 	"strconv"
	// 	"os"
	// 	"log"
	// 	"testing"
	// )
	//
	// import "strings"  // FIXME: This will not work with "import ("
	//
	// func setup() {
	// Given("^I'm successfully logged in as an admin in users pane$", func(args Args) error {
	// 	_ = ioutil.Discard
	// 	return Pending("Not implemented")
	// })
	// And("^I fill in a new developer named hacker with password changeme$", func(args Args) error {
	// 	_ = strings.Join([]string{}, "")
	// 	return Pending("Not implemented")
	// })
	// }
	//
	// func main() {
	// 	file := os.Args[1]
	// 	fd, err := os.Open(file)  // Open *.feature file
	// 	if err != nil {
	// 		log.Fatal("Error opening input file:", err)
	// 	}

	// 	defer fd.Close()

	// 	if pretty, err := strconv.ParseBool(os.Args[2]); err != nil {
	// 		log.Fatal("Error configuring pretty print: ", err)
	// 	} else if pretty {
	// 		stdres.EnableColor()
	// 	} else {
	// 		stdres.DisableColor()
	// 	}

	// 	setup()
	// 	feature := NewFeature(fd)
	// 	suite := NewSuite()
	// 	t := testing.T{}
	// 	suite.Test(*feature, &t)
	// }
}

func Example_Run() {

	definitions := definition.NewDefinitions([]io.Reader{
		bytes.NewBufferString(`
package step_definitions

Given("^I'm successfully logged in as an admin in users pane$", func(args Args) error {
	_ = ioutil.Discard
	return Pending("Not implemented")
})
And("^I fill in a new developer named hacker with password changeme$", func(args Args) error {
	_ = strings.Join([]string{}, "")
	return Pending("Not implemented")
})

import "strings"

	`),
	})

	features := bytes.NewBufferString(`
Feature: Manage users
    Administrators are able to manage all users.
    It's possible to add and remove users, but also
    change user kind, password and username.

    Following user kinds are supported by default
    setup:

    * Administrators:
        Setup new users and configures accessibility
        (Users and network interfaces)
    * Developers:
        Are able to setup new projects containing
        build and test configuration.
    * Applications:
        Rest and API systems, for instance external webpages.
    * Others:
        This category contains users with limited access.
        Project managers and field engineers are canonical users.
        Typical user scenario: tag release, download doployable
        build.

  Scenario: Create a new developer
    Given I'm successfully logged in as an admin in users pane
    And I fill in a new developer named hacker with password changeme
    When I press the create button
    Then only one user-record with name hacker should exist
    And user hacker should have password changeme
`)

	definitions.Run(features)

	// Output:
	// Feature: Manage users
	//
	//   Scenario: Create a new developer
	//
	//     Given I'm successfully logged in as an admin in users pane
	//
	//     And I fill in a new developer named hacker with password changeme
	//
	//     When I press the create button
	//
	//     Then only one user-record with name hacker should exist
	//
	//     And user hacker should have password changeme
	//
	//     1 scenario (0 undefined, 0 failures, 1 pending)
	//     5 steps (3 undefined, 0 failures, 1 pending, 1 optout)
	//
	//     You can implement step definition for undefined steps with these snippets:
	//
	//     And("^user hacker should have password changeme$", func(args Args) error {
	//         return Pending("Not implemented")
	//     })
	//
	//     Then("^only one user-record with name hacker should exist$", func(args Args) error {
	//         return Pending("Not implemented")
	//     })
	//
	//     When("^I press the create button$", func(args Args) error {
	//         return Pending("Not implemented")
	//     })
}
<|endoftext|>


<commit_before>package model

import "strings"

type Locale struct {
	Language string `json:"Language"`
	Value    string `json:"Value"`
}

var Locales = []Locale{
	{"English", "en"},
	{"Spanish", "es"},
	{"French", "fr"},
	{"Russian", "ru"},
	{"German", "de"},
	{"Italian", "it"},
	{"Swedish", "sv"},
	{"Portuguese", "pt"},
	{"Hungarian", "hu"},
	{"Dutch", "nl"},
}

//
//{"Romanian", "ro"},
//{"Arabic", "ar"},
//{"Korean", "ko"},
//{"Japanese", "ja"},
//{"Chinese", "zh"},

func GetDefaultLocale(language string) string {
	if strings.Contains(language, "en") {
		return "en"
	}
	if strings.Contains(language, "es") {
		return "es"
	}
	if strings.Contains(language, "fr") {
		return "fr"
	}
	if strings.Contains(language, "ru") {
		return "ru"
	}
	if strings.Contains(language, "de") {
		return "de"
	}
	if strings.Contains(language, "it") {
		return "it"
	}
	if strings.Contains(language, "sv") {
		return "sv"
	}
	if strings.Contains(language, "ro") {
		return "ro"
	}
	if strings.Contains(language, "pt") {
		return "pt"
	}
	if strings.Contains(language, "hu") {
		return "hu"
	}
	if strings.Contains(language, "nl") {
		return "nl"
	}
	if strings.Contains(language, "ar") {
		return "ar"
	}
	if strings.Contains(language, "ko") {
		return "ko"
	}
	if strings.Contains(language, "ja") {
		return "ja"
	}
	if strings.Contains(language, "zh") {
		return "zh"
	}
	return "en"
}
<commit_msg>remove certain langs<commit_after>package model

import "strings"

type Locale struct {
	Language string `json:"Language"`
	Value    string `json:"Value"`
}

var Locales = []Locale{
	{"English", "en"},
	{"Spanish", "es"},
	{"French", "fr"},
	{"German", "de"},
	{"Italian", "it"},
	{"Swedish", "sv"},
	{"Portuguese", "pt"},
	{"Hungarian", "hu"},
	{"Dutch", "nl"},
}

//
//{"Romanian", "ro"},
//{"Arabic", "ar"},
//{"Korean", "ko"},
//{"Japanese", "ja"},
//{"Chinese", "zh"},

// we have this translated but have some latin1 conversion work to do before it would be ready
//	{"Russian", "ru"},

func GetDefaultLocale(language string) string {
	if strings.Contains(language, "en") {
		return "en"
	}
	if strings.Contains(language, "es") {
		return "es"
	}
	if strings.Contains(language, "fr") {
		return "fr"
	}
	if strings.Contains(language, "ru") {
		return "ru"
	}
	if strings.Contains(language, "de") {
		return "de"
	}
	if strings.Contains(language, "it") {
		return "it"
	}
	if strings.Contains(language, "sv") {
		return "sv"
	}
	if strings.Contains(language, "ro") {
		return "ro"
	}
	if strings.Contains(language, "pt") {
		return "pt"
	}
	if strings.Contains(language, "hu") {
		return "hu"
	}
	if strings.Contains(language, "nl") {
		return "nl"
	}
	if strings.Contains(language, "ar") {
		return "ar"
	}
	if strings.Contains(language, "ko") {
		return "ko"
	}
	if strings.Contains(language, "ja") {
		return "ja"
	}
	if strings.Contains(language, "zh") {
		return "zh"
	}
	return "en"
}
<|endoftext|>


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

package main

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/globocom/tsuru/cmd"
	"io/ioutil"
	"net/http"
	"os"
)

type ServiceCreate struct{}

func (c *ServiceCreate) Info() *cmd.Info {
	desc := "Creates a service based on a passed manifest. The manifest format should be a yaml and follow the standard described in the documentation (should link to it here)"
	return &cmd.Info{
		Name:    "create",
		Usage:   "create path/to/manifesto",
		Desc:    desc,
		MinArgs: 1,
	}
}

func (c *ServiceCreate) Run(context *cmd.Context, client cmd.Doer) error {
	manifest := context.Args[0]
	url, err := cmd.GetUrl("/services")
	if err != nil {
		return err
	}
	b, err := ioutil.ReadFile(manifest)
	if err != nil {
		return err
	}
	request, err := http.NewRequest("POST", url, bytes.NewReader(b))
	if err != nil {
		return err
	}
	r, err := client.Do(request)
	if err != nil {
		return err
	}
	b, err = ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	fmt.Fprintf(context.Stdout, "%s", b)
	return nil
}

type ServiceRemove struct{}

func (c *ServiceRemove) Run(context *cmd.Context, client cmd.Doer) error {
	serviceName := context.Args[0]
	url, err := cmd.GetUrl("/services/" + serviceName)
	if err != nil {
		return err
	}
	request, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return err
	}
	_, err = client.Do(request)
	if err != nil {
		return err
	}
	fmt.Fprintln(context.Stdout, "Service successfully removed.")
	return nil
}

func (c *ServiceRemove) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "remove",
		Usage:   "remove <servicename>",
		Desc:    "removes a service from catalog",
		MinArgs: 1,
	}
}

type ServiceList struct{}

func (c *ServiceList) Info() *cmd.Info {
	return &cmd.Info{
		Name:  "list",
		Usage: "list",
		Desc:  "list services that belongs to user's team and it's service instances.",
	}
}

func (c *ServiceList) Run(ctx *cmd.Context, client cmd.Doer) error {
	url, err := cmd.GetUrl("/services")
	if err != nil {
		return err
	}
	request, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return err
	}
	resp, err := client.Do(request)
	if err != nil {
		return err
	}
	b, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		return err
	}
	rslt, err := cmd.ShowServicesInstancesList(b)
	if err != nil {
		return err
	}
	ctx.Stdout.Write(rslt)
	return nil
}

type ServiceUpdate struct{}

func (c *ServiceUpdate) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "update",
		Usage:   "update <path/to/manifesto>",
		Desc:    "Update service data, extracting it from the given manifesto file.",
		MinArgs: 1,
	}
}

func (c *ServiceUpdate) Run(ctx *cmd.Context, client cmd.Doer) error {
	manifest := ctx.Args[0]
	b, err := ioutil.ReadFile(manifest)
	if err != nil {
		return err
	}
	url, err := cmd.GetUrl("/services")
	if err != nil {
		return err
	}
	request, err := http.NewRequest("PUT", url, bytes.NewReader(b))
	if err != nil {
		return err
	}
	resp, err := client.Do(request)
	if err != nil {
		return err
	}
	if resp.StatusCode == http.StatusNoContent {
		fmt.Fprintln(ctx.Stdout, "Service successfully updated.")
	}
	return nil
}

type ServiceDocAdd struct{}

func (c *ServiceDocAdd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "doc-add",
		Usage:   "service doc-add <service> <path/to/docfile>",
		Desc:    "Update service documentation, extracting it from the given file.",
		MinArgs: 2,
	}
}

func (c *ServiceDocAdd) Run(ctx *cmd.Context, client cmd.Doer) error {
	serviceName := ctx.Args[0]
	url, err := cmd.GetUrl("/services/" + serviceName + "/doc")
	if err != nil {
		return err
	}
	docPath := ctx.Args[1]
	b, err := ioutil.ReadFile(docPath)
	request, err := http.NewRequest("PUT", url, bytes.NewReader(b))
	if err != nil {
		return err
	}
	_, err = client.Do(request)
	if err != nil {
		return err
	}
	fmt.Fprintf(ctx.Stdout, "Documentation for '%s' successfully updated.\n", serviceName)
	return nil
}

type ServiceDocGet struct{}

func (c *ServiceDocGet) Run(ctx *cmd.Context, client cmd.Doer) error {
	serviceName := ctx.Args[0]
	url, err := cmd.GetUrl("/services/" + serviceName + "/doc")
	if err != nil {
		return err
	}
	request, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return err
	}
	resp, err := client.Do(request)
	if err != nil {
		return err
	}

	b, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		return err
	}
	ctx.Stdout.Write(b)
	return nil
}

func (c *ServiceDocGet) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "doc-get",
		Usage:   "service doc-get <service>",
		Desc:    "Shows service documentation.",
		MinArgs: 1,
	}
}

type ServiceTemplate struct{}

func (c *ServiceTemplate) Info() *cmd.Info {
	usg := `template
e.g.: $ crane template`
	return &cmd.Info{
		Name:  "template",
		Usage: usg,
		Desc:  "Generates a manifest template file and places it in current path",
	}
}

func (c *ServiceTemplate) Run(ctx *cmd.Context, client cmd.Doer) error {
	template := `id: servicename
endpoint:
  production: production-endpoint.com
  test: test-endpoint.com:8080`
	f, err := os.Create("manifest.yaml")
	defer f.Close()
	if err != nil {
		return errors.New("Error while creating manifest template.\nOriginal error message is: " + err.Error())
	}
	f.Write([]byte(template))
	fmt.Fprintln(ctx.Stdout, `Generated file "manifest.yaml" in current path`)
	return nil
}
<commit_msg>cmd: remove Doer interface<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/globocom/tsuru/cmd"
	"io/ioutil"
	"net/http"
	"os"
)

type ServiceCreate struct{}

func (c *ServiceCreate) Info() *cmd.Info {
	desc := "Creates a service based on a passed manifest. The manifest format should be a yaml and follow the standard described in the documentation (should link to it here)"
	return &cmd.Info{
		Name:    "create",
		Usage:   "create path/to/manifesto",
		Desc:    desc,
		MinArgs: 1,
	}
}

func (c *ServiceCreate) Run(context *cmd.Context, client *cmd.Client) error {
	manifest := context.Args[0]
	url, err := cmd.GetUrl("/services")
	if err != nil {
		return err
	}
	b, err := ioutil.ReadFile(manifest)
	if err != nil {
		return err
	}
	request, err := http.NewRequest("POST", url, bytes.NewReader(b))
	if err != nil {
		return err
	}
	r, err := client.Do(request)
	if err != nil {
		return err
	}
	b, err = ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	fmt.Fprintf(context.Stdout, "%s", b)
	return nil
}

type ServiceRemove struct{}

func (c *ServiceRemove) Run(context *cmd.Context, client *cmd.Client) error {
	serviceName := context.Args[0]
	url, err := cmd.GetUrl("/services/" + serviceName)
	if err != nil {
		return err
	}
	request, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return err
	}
	_, err = client.Do(request)
	if err != nil {
		return err
	}
	fmt.Fprintln(context.Stdout, "Service successfully removed.")
	return nil
}

func (c *ServiceRemove) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "remove",
		Usage:   "remove <servicename>",
		Desc:    "removes a service from catalog",
		MinArgs: 1,
	}
}

type ServiceList struct{}

func (c *ServiceList) Info() *cmd.Info {
	return &cmd.Info{
		Name:  "list",
		Usage: "list",
		Desc:  "list services that belongs to user's team and it's service instances.",
	}
}

func (c *ServiceList) Run(ctx *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetUrl("/services")
	if err != nil {
		return err
	}
	request, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return err
	}
	resp, err := client.Do(request)
	if err != nil {
		return err
	}
	b, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		return err
	}
	rslt, err := cmd.ShowServicesInstancesList(b)
	if err != nil {
		return err
	}
	ctx.Stdout.Write(rslt)
	return nil
}

type ServiceUpdate struct{}

func (c *ServiceUpdate) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "update",
		Usage:   "update <path/to/manifesto>",
		Desc:    "Update service data, extracting it from the given manifesto file.",
		MinArgs: 1,
	}
}

func (c *ServiceUpdate) Run(ctx *cmd.Context, client *cmd.Client) error {
	manifest := ctx.Args[0]
	b, err := ioutil.ReadFile(manifest)
	if err != nil {
		return err
	}
	url, err := cmd.GetUrl("/services")
	if err != nil {
		return err
	}
	request, err := http.NewRequest("PUT", url, bytes.NewReader(b))
	if err != nil {
		return err
	}
	resp, err := client.Do(request)
	if err != nil {
		return err
	}
	if resp.StatusCode == http.StatusNoContent {
		fmt.Fprintln(ctx.Stdout, "Service successfully updated.")
	}
	return nil
}

type ServiceDocAdd struct{}

func (c *ServiceDocAdd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "doc-add",
		Usage:   "service doc-add <service> <path/to/docfile>",
		Desc:    "Update service documentation, extracting it from the given file.",
		MinArgs: 2,
	}
}

func (c *ServiceDocAdd) Run(ctx *cmd.Context, client *cmd.Client) error {
	serviceName := ctx.Args[0]
	url, err := cmd.GetUrl("/services/" + serviceName + "/doc")
	if err != nil {
		return err
	}
	docPath := ctx.Args[1]
	b, err := ioutil.ReadFile(docPath)
	request, err := http.NewRequest("PUT", url, bytes.NewReader(b))
	if err != nil {
		return err
	}
	_, err = client.Do(request)
	if err != nil {
		return err
	}
	fmt.Fprintf(ctx.Stdout, "Documentation for '%s' successfully updated.\n", serviceName)
	return nil
}

type ServiceDocGet struct{}

func (c *ServiceDocGet) Run(ctx *cmd.Context, client *cmd.Client) error {
	serviceName := ctx.Args[0]
	url, err := cmd.GetUrl("/services/" + serviceName + "/doc")
	if err != nil {
		return err
	}
	request, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return err
	}
	resp, err := client.Do(request)
	if err != nil {
		return err
	}

	b, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		return err
	}
	ctx.Stdout.Write(b)
	return nil
}

func (c *ServiceDocGet) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "doc-get",
		Usage:   "service doc-get <service>",
		Desc:    "Shows service documentation.",
		MinArgs: 1,
	}
}

type ServiceTemplate struct{}

func (c *ServiceTemplate) Info() *cmd.Info {
	usg := `template
e.g.: $ crane template`
	return &cmd.Info{
		Name:  "template",
		Usage: usg,
		Desc:  "Generates a manifest template file and places it in current path",
	}
}

func (c *ServiceTemplate) Run(ctx *cmd.Context, client *cmd.Client) error {
	template := `id: servicename
endpoint:
  production: production-endpoint.com
  test: test-endpoint.com:8080`
	f, err := os.Create("manifest.yaml")
	defer f.Close()
	if err != nil {
		return errors.New("Error while creating manifest template.\nOriginal error message is: " + err.Error())
	}
	f.Write([]byte(template))
	fmt.Fprintln(ctx.Stdout, `Generated file "manifest.yaml" in current path`)
	return nil
}
<|endoftext|>


<commit_before>// +build linux,go1.13

package netlink

import (
	"errors"
	"os"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/mdlayher/ethtool"
	"github.com/mdlayher/netlink"
	"golang.org/x/sys/unix"
)

func TestOpErrorUnwrapLinux(t *testing.T) {
	tests := []struct {
		name   string
		err    error
		target error
		ok     bool
	}{
		{
			name:   "ENOBUFS",
			err:    unix.ENOBUFS,
			target: os.ErrNotExist,
		},
		{
			name: "OpError ENOBUFS",
			err: &OpError{
				Op:  "receive",
				Err: unix.ENOBUFS,
			},
			target: os.ErrNotExist,
		},
		{
			name: "OpError os.SyscallError ENOBUFS",
			err: &OpError{
				Op:  "receive",
				Err: os.NewSyscallError("recvmsg", unix.ENOBUFS),
			},
			target: os.ErrNotExist,
		},
		{
			name:   "ENOENT",
			err:    unix.ENOENT,
			target: os.ErrNotExist,
			ok:     true,
		},
		{
			name: "OpError ENOENT",
			err: &OpError{
				Op:  "receive",
				Err: unix.ENOENT,
			},
			target: os.ErrNotExist,
			ok:     true,
		},
		{
			name: "OpError os.SyscallError ENOENT",
			err: &OpError{
				Op:  "receive",
				Err: os.NewSyscallError("recvmsg", unix.ENOENT),
			},
			target: os.ErrNotExist,
			ok:     true,
		},
		{
			name: "OpError os.SyscallError EEXIST",
			err: &OpError{
				Op:  "receive",
				Err: os.NewSyscallError("recvmsg", unix.EEXIST),
			},
			target: os.ErrExist,
			ok:     true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := errors.Is(tt.err, tt.target)
			if diff := cmp.Diff(tt.ok, got); diff != "" {
				t.Fatalf("unexpected result (-want +got):\n%s", diff)
			}
		})
	}
}

func TestIntegrationEthtoolExtendedAcknowledge(t *testing.T) {
	t.Parallel()

	// The ethtool package uses extended acknowledgements and should populate
	// all of netlink.OpError's fields when unwrapped.
	c, err := ethtool.New()
	if err != nil {
		if errors.Is(err, os.ErrNotExist) {
			t.Skip("skipping, ethtool genetlink not available on this system")
		}

		t.Fatalf("failed to open ethtool genetlink: %v", err)
	}

	_, err = c.LinkInfo(ethtool.Interface{Name: "notexist0"})
	if err == nil {
		t.Fatal("expected an error, but none occurred")
	}

	var oerr *netlink.OpError
	if !errors.As(err, &oerr) {
		t.Fatalf("expected wrapped *netlink.OpError, but got: %T", err)
	}

	// Assume the message contents will be relatively static but don't hardcode
	// offset just in case things change.
	if oerr.Offset == 0 {
		t.Fatal("no offset specified in *netlink.OpError")
	}
	oerr.Offset = 0

	want := &netlink.OpError{
		Op:      "receive",
		Err:     unix.ENODEV,
		Message: "no device matches name",
	}

	if diff := cmp.Diff(want, oerr); diff != "" {
		t.Fatalf("unexpected *netlink.OpError (-want +got):\n%s", diff)
	}
}
<commit_msg>netlink: fix 1.13+ tests<commit_after>// +build linux,go1.13

package netlink_test

import (
	"errors"
	"os"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/mdlayher/ethtool"
	"github.com/mdlayher/netlink"
	"golang.org/x/sys/unix"
)

func TestOpErrorUnwrapLinux(t *testing.T) {
	tests := []struct {
		name   string
		err    error
		target error
		ok     bool
	}{
		{
			name:   "ENOBUFS",
			err:    unix.ENOBUFS,
			target: os.ErrNotExist,
		},
		{
			name: "OpError ENOBUFS",
			err: &netlink.OpError{
				Op:  "receive",
				Err: unix.ENOBUFS,
			},
			target: os.ErrNotExist,
		},
		{
			name: "OpError os.SyscallError ENOBUFS",
			err: &netlink.OpError{
				Op:  "receive",
				Err: os.NewSyscallError("recvmsg", unix.ENOBUFS),
			},
			target: os.ErrNotExist,
		},
		{
			name:   "ENOENT",
			err:    unix.ENOENT,
			target: os.ErrNotExist,
			ok:     true,
		},
		{
			name: "OpError ENOENT",
			err: &netlink.OpError{
				Op:  "receive",
				Err: unix.ENOENT,
			},
			target: os.ErrNotExist,
			ok:     true,
		},
		{
			name: "OpError os.SyscallError ENOENT",
			err: &netlink.OpError{
				Op:  "receive",
				Err: os.NewSyscallError("recvmsg", unix.ENOENT),
			},
			target: os.ErrNotExist,
			ok:     true,
		},
		{
			name: "OpError os.SyscallError EEXIST",
			err: &netlink.OpError{
				Op:  "receive",
				Err: os.NewSyscallError("recvmsg", unix.EEXIST),
			},
			target: os.ErrExist,
			ok:     true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := errors.Is(tt.err, tt.target)
			if diff := cmp.Diff(tt.ok, got); diff != "" {
				t.Fatalf("unexpected result (-want +got):\n%s", diff)
			}
		})
	}
}

func TestIntegrationEthtoolExtendedAcknowledge(t *testing.T) {
	t.Parallel()

	// The ethtool package uses extended acknowledgements and should populate
	// all of netlink.OpError's fields when unwrapped.
	c, err := ethtool.New()
	if err != nil {
		if errors.Is(err, os.ErrNotExist) {
			t.Skip("skipping, ethtool genetlink not available on this system")
		}

		t.Fatalf("failed to open ethtool genetlink: %v", err)
	}

	_, err = c.LinkInfo(ethtool.Interface{Name: "notexist0"})
	if err == nil {
		t.Fatal("expected an error, but none occurred")
	}

	var oerr *netlink.OpError
	if !errors.As(err, &oerr) {
		t.Fatalf("expected wrapped *netlink.OpError, but got: %T", err)
	}

	// Assume the message contents will be relatively static but don't hardcode
	// offset just in case things change.
	if oerr.Offset == 0 {
		t.Fatal("no offset specified in *netlink.OpError")
	}
	oerr.Offset = 0

	want := &netlink.OpError{
		Op:      "receive",
		Err:     unix.ENODEV,
		Message: "no device matches name",
	}

	if diff := cmp.Diff(want, oerr); diff != "" {
		t.Fatalf("unexpected *netlink.OpError (-want +got):\n%s", diff)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 fluter

package paste

import "testing"

type entry struct {
	url string
	ok  bool
}

var entries = []entry{
	{"http://codepad.org/abcd", false},
	{"http://codepad.org/d4TzyKaI", true},
	{"http://bpaste.net/show/abc", false},
	{"https://bpaste.net/show/0313375aa3c8", true},
	{"http://pastebin.com/abc", false},
	{"http://pastebin.com/8KACZxp7", true},
	{"http://sprunge.us/abc", true},
	{"http://sprunge.us/BBai", true},
	{"http://ideone.com/abc", true},
	{"http://ideone.com/y2FsS8", true},
	{"http://pastie.org/abc", false},
	{"http://pastie.org/10764925", true},
	{"http://dpaste.com/abc", false},
	{"http://dpaste.com/2CQFK52", true},
	{"http://foo.bar/baz", false},
	{"http://paste.debian.net/427049/", true},
	{"http://paste.debian.net/abc", false},
	{"http://paste.fedoraproject.org/351674/", true},
	{"http://paste.fedoraproject.org/false/", false},
	{"http://paste.fedoraproject.org/351675/16030146/", true},
	{"https://ptpb.pw/WMa-", true},
	{"https://ptpb.pw/false", false},
	{"http://paste.pr0.tips/Ky", true},
	{"http://paste.pr0.tips/false", true},
	{"http://vp.dav1d.de/Vvn4U", true},
	{"http://vp.dav1d.de/false", false},
	{"http://hastebin.com/ilanaqadel.vbs", true},
	{"http://lpaste.net/159275", true},
	{"http://fpaste.org/351700/", true},
	//{"http://ghostbin.com/paste/tzh3m", true},
	{"https://dpaste.de/DhN3", true},
	{"http://paste.ee/p/yIw9B", true},
	{"http://paste.linuxassist.net/view/af59ea55", true},
	{"http://paste.linux.chat/view/af59ea55", true},
	{"http://paste.pound-python.org/show/ue14Up5c83BXUdDR1AAQ/", true},
	{"http://pastebin.geany.org/7cqOA/", true},
	{"https://paste.kde.org/pkzew5624", true},
	{"http://paste.eientei.org/show/1036/", true},
	{"http://www.heypasteit.com/clip/2KQ7", true},
	//{"https://pastebin.mozilla.org/8867128", true},
	{"http://paste.ubuntu.org.cn/4170959", true},
	{"http://pastebin.ca/3464385", true},
	{"https://paste.lugons.org/show/XlahOkDwVBqtkjRt6H2f/", true},
	{"https://paste.lugons.org/show/10028/", true},
	{"http://play.golang.org/p/v3rrZLwEUC", true},
}

func TestGet(t *testing.T) {
	for _, e := range entries {
		t.Log("Getting", e.url)
		ret, err := Get(e.url)
		if err != nil {
			t.Log(err)
		} else {
			t.Log(ret)
		}
		if (err == nil) == e.ok {
			t.Log("OK")
		} else {
			t.Fail()
			t.Log("FAIL")
		}
	}
}

func TestGetErr(t *testing.T) {
	_, err := Get("http://foo.bar/xyz")
	if err != ErrNotSupported {
		t.Fail()
	}

	_, err = Get("%3")
	if err == nil {
		t.Fail()
	}
}

func TestPut(t *testing.T) {
	text := "This is a test message"
	id, err := Paste(text)
	if err != nil {
		t.Error(err)
	}
	t.Log(id)
}
<commit_msg>remove unstable test case for dpaste.de<commit_after>// Copyright 2016 fluter

package paste

import "testing"

type entry struct {
	url string
	ok  bool
}

var entries = []entry{
	{"http://codepad.org/abcd", false},
	{"http://codepad.org/d4TzyKaI", true},
	{"http://bpaste.net/show/abc", false},
	{"https://bpaste.net/show/0313375aa3c8", true},
	{"http://pastebin.com/abc", false},
	{"http://pastebin.com/8KACZxp7", true},
	{"http://sprunge.us/abc", true},
	{"http://sprunge.us/BBai", true},
	{"http://ideone.com/abc", true},
	{"http://ideone.com/y2FsS8", true},
	{"http://pastie.org/abc", false},
	{"http://pastie.org/10764925", true},
	{"http://dpaste.com/abc", false},
	{"http://dpaste.com/2CQFK52", true},
	{"http://foo.bar/baz", false},
	{"http://paste.debian.net/427049/", true},
	{"http://paste.debian.net/abc", false},
	{"http://paste.fedoraproject.org/351674/", true},
	{"http://paste.fedoraproject.org/false/", false},
	{"http://paste.fedoraproject.org/351675/16030146/", true},
	{"https://ptpb.pw/WMa-", true},
	{"https://ptpb.pw/false", false},
	{"http://paste.pr0.tips/Ky", true},
	{"http://paste.pr0.tips/false", true},
	{"http://vp.dav1d.de/Vvn4U", true},
	{"http://vp.dav1d.de/false", false},
	{"http://hastebin.com/ilanaqadel.vbs", true},
	{"http://lpaste.net/159275", true},
	{"http://fpaste.org/351700/", true},
	//{"http://ghostbin.com/paste/tzh3m", true},
	//{"https://dpaste.de/DhN3", true},  - no permanent paste on this site, at most one month
	{"http://paste.ee/p/yIw9B", true},
	{"http://paste.linuxassist.net/view/af59ea55", true},
	{"http://paste.linux.chat/view/af59ea55", true},
	{"http://paste.pound-python.org/show/ue14Up5c83BXUdDR1AAQ/", true},
	{"http://pastebin.geany.org/7cqOA/", true},
	{"https://paste.kde.org/pkzew5624", true},
	{"http://paste.eientei.org/show/1036/", true},
	{"http://www.heypasteit.com/clip/2KQ7", true},
	//{"https://pastebin.mozilla.org/8867128", true},
	{"http://paste.ubuntu.org.cn/4170959", true},
	{"http://pastebin.ca/3464385", true},
	{"https://paste.lugons.org/show/XlahOkDwVBqtkjRt6H2f/", true},
	{"https://paste.lugons.org/show/10028/", true},
	{"http://play.golang.org/p/v3rrZLwEUC", true},
}

func TestGet(t *testing.T) {
	for _, e := range entries {
		t.Log("Getting", e.url)
		ret, err := Get(e.url)
		if err != nil {
			t.Log(err)
		} else {
			t.Log(ret)
		}
		if (err == nil) == e.ok {
			t.Log("OK")
		} else {
			t.Fail()
			t.Log("FAIL")
		}
	}
}

func TestGetErr(t *testing.T) {
	_, err := Get("http://foo.bar/xyz")
	if err != ErrNotSupported {
		t.Fail()
	}

	_, err = Get("%3")
	if err == nil {
		t.Fail()
	}
}

func TestPut(t *testing.T) {
	text := "This is a test message"
	id, err := Paste(text)
	if err != nil {
		t.Error(err)
	}
	t.Log(id)
}
<|endoftext|>


<commit_before>package cache

import (
	"bytes"
	"crypto/md5"
	"encoding/gob"
	"fmt"
	"io"
	"os"
	"sync"

	"github.com/donatj/imgdedup"
	"github.com/prologic/bitcask"
)

type Cache struct {
	db *bitcask.Bitcask

	sync.Mutex
}

func New(db *bitcask.Bitcask) *Cache {
	return &Cache{
		db: db,
	}
}

func (c *Cache) LoadCache(cachename string) *imgdedup.ImageInfo {
	c.Lock()
	defer c.Unlock()

	b, err := c.db.Get(cachename)
	if err == bitcask.ErrKeyNotFound {
		return nil
	} else if err != nil {
		panic(err)
	}

	data := bytes.NewBuffer(b)
	dec := gob.NewDecoder(data)

	imginfo := imgdedup.ImageInfo{}
	err = dec.Decode(&imginfo)
	if err != nil {
		return nil
	}

	return &imginfo
}

func (c *Cache) StoreCache(cachename string, imginfo *imgdedup.ImageInfo) error {
	c.Lock()
	defer c.Unlock()

	data := &bytes.Buffer{}

	enc := gob.NewEncoder(data)
	err := enc.Encode(*imginfo)
	if err != nil {
		return err
	}

	err = c.db.Put(cachename, data.Bytes())
	if err != nil {
		return err
	}

	return nil
}

func GetCacheName(imgpath string, subdivisions uint) string {
	file, err := os.Open(imgpath)
	if err != nil {
		return ""
	}
	defer file.Close()

	fi, err := file.Stat()
	if err != nil {
		return ""
	}

	str := imgpath + "|" + string(subdivisions) + "|" + string(fi.Size()) + string(fi.ModTime().Unix())

	h := md5.New()
	io.WriteString(h, str)

	return fmt.Sprintf("%x", h.Sum(nil))
}
<commit_msg>Fixes bad uint->string cast in cache pathing<commit_after>package cache

import (
	"bytes"
	"crypto/md5"
	"encoding/gob"
	"fmt"
	"io"
	"os"
	"sync"

	"github.com/donatj/imgdedup"
	"github.com/prologic/bitcask"
)

type Cache struct {
	db *bitcask.Bitcask

	sync.Mutex
}

func New(db *bitcask.Bitcask) *Cache {
	return &Cache{
		db: db,
	}
}

func (c *Cache) LoadCache(cachename string) *imgdedup.ImageInfo {
	c.Lock()
	defer c.Unlock()

	b, err := c.db.Get(cachename)
	if err == bitcask.ErrKeyNotFound {
		return nil
	} else if err != nil {
		panic(err)
	}

	data := bytes.NewBuffer(b)
	dec := gob.NewDecoder(data)

	imginfo := imgdedup.ImageInfo{}
	err = dec.Decode(&imginfo)
	if err != nil {
		return nil
	}

	return &imginfo
}

func (c *Cache) StoreCache(cachename string, imginfo *imgdedup.ImageInfo) error {
	c.Lock()
	defer c.Unlock()

	data := &bytes.Buffer{}

	enc := gob.NewEncoder(data)
	err := enc.Encode(*imginfo)
	if err != nil {
		return err
	}

	err = c.db.Put(cachename, data.Bytes())
	if err != nil {
		return err
	}

	return nil
}

func GetCacheName(imgpath string, subdivisions uint) string {
	file, err := os.Open(imgpath)
	if err != nil {
		return ""
	}
	defer file.Close()

	fi, err := file.Stat()
	if err != nil {
		return ""
	}

	str := imgpath + "|" + fmt.Sprint(subdivisions) + "|" + fmt.Sprint(fi.Size()) + "|" + fmt.Sprint(fi.ModTime().Unix())

	h := md5.New()
	io.WriteString(h, str)

	return fmt.Sprintf("%x", h.Sum(nil))
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package cache

// Cacher acts as a best effort key value store
type Cacher interface {
	// Put inserts an element into the cache. If spaced is required, elements will
	// be evicted.
	Put(key, value interface{})

	// Get returns the entry in the cache with the key specified, if no value
	// exists, false is returned.
	Get(key interface{}) (interface{}, bool)

	// Evict removes the specified entry from the cache
	Evict(key interface{})

	// Flush removes all entries from the cache
	Flush()
}

// Evictable allows the object to be notified when it is evicted
type Evictable interface {
	Key() interface{}
	Evict()
}

// Deduplicator acts as a best effort deduplication service
type Deduplicator interface {
	// Deduplicate returns either the provided value, or a previously provided
	// value with the same ID that hasn't yet been evicted
	Deduplicate(Evictable) Evictable

	// Flush removes all entries from the cache
	Flush()
}
<commit_msg>added comparable comment<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package cache

// Cacher acts as a best effort key value store. Keys must be comparable, as
// defined by https://golang.org/ref/spec#Comparison_operators.
type Cacher interface {
	// Put inserts an element into the cache. If spaced is required, elements will
	// be evicted.
	Put(key, value interface{})

	// Get returns the entry in the cache with the key specified, if no value
	// exists, false is returned.
	Get(key interface{}) (interface{}, bool)

	// Evict removes the specified entry from the cache
	Evict(key interface{})

	// Flush removes all entries from the cache
	Flush()
}

// Evictable allows the object to be notified when it is evicted
type Evictable interface {
	// Key must return a comparable value as defined by
	// https://golang.org/ref/spec#Comparison_operators.
	Key() interface{}
	Evict()
}

// Deduplicator acts as a best effort deduplication service
type Deduplicator interface {
	// Deduplicate returns either the provided value, or a previously provided
	// value with the same ID that hasn't yet been evicted
	Deduplicate(Evictable) Evictable

	// Flush removes all entries from the cache
	Flush()
}
<|endoftext|>


<commit_before>package cache

import (
	"github.com/heidi-ann/hydra/msgs"
)

type Cache map[int]msgs.ClientResponse

func Create() *Cache {
	var c Cache
	c = map[int]msgs.ClientResponse{}
	return &c
}

func (c *Cache) Check(req msgs.ClientRequest) (bool, msgs.ClientResponse) {
	last := (*c)[req.ClientID]
	return req.RequestID == last.RequestID, last
}

func (c *Cache) Add(res msgs.ClientResponse) {
	(*c)[res.ClientID] = res
}
<commit_msg>making cache safe for concurrent accesses<commit_after>// Cache is a simple key value store mapping client ID's to the response to the last request sent to them
// It is safe for concurreny access
// TODO: make locking more fine grained
package cache

import (
	"github.com/heidi-ann/hydra/msgs"
	"sync"
)

type Cache struct {
	m map[int]msgs.ClientResponse
	sync.RWMutex
}

func Create() *Cache {
	c := map[int]msgs.ClientResponse{}
	return &Cache{c, sync.RWMutex{}}
}

func (c *Cache) Check(req msgs.ClientRequest) (bool, msgs.ClientResponse) {
	c.RLock()
	last := c.m[req.ClientID]
	c.RUnlock()
	return req.RequestID == last.RequestID, last
}

func (c *Cache) Add(res msgs.ClientResponse) {
	c.Lock()
	c.m[res.ClientID] = res
	c.Unlock()
}
<|endoftext|>


<commit_before>package canal

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"sync"

	"github.com/fusionrsrch/go-mysql/client"
	"github.com/fusionrsrch/go-mysql/dump"
	"github.com/fusionrsrch/go-mysql/mysql"
	"github.com/fusionrsrch/go-mysql/replication"
	"github.com/fusionrsrch/go-mysql/schema"
	"github.com/siddontang/go/log"
	"github.com/siddontang/go/sync2"
)

var errCanalClosed = errors.New("canal was closed")

// Canal can sync your MySQL data into everywhere, like Elasticsearch, Redis, etc...
// MySQL must open row format for binlog
type Canal struct {
	m sync.Mutex

	cfg *Config

	master     *masterInfo
	dumper     *dump.Dumper
	dumpDoneCh chan struct{}
	syncer     *replication.BinlogSyncer

	rsLock     sync.Mutex
	rsHandlers []RowsEventHandler

	connLock sync.Mutex
	conn     *client.Conn

	wg sync.WaitGroup

	tableLock sync.Mutex
	tables    map[string]*schema.Table

	quit   chan struct{}
	closed sync2.AtomicBool
}

func NewCanal(cfg *Config) (*Canal, error) {
	c := new(Canal)
	c.cfg = cfg
	c.closed.Set(false)
	c.quit = make(chan struct{})

	os.MkdirAll(cfg.DataDir, 0755)

	c.dumpDoneCh = make(chan struct{})
	c.rsHandlers = make([]RowsEventHandler, 0, 4)
	c.tables = make(map[string]*schema.Table)

	var err error
	if c.master, err = loadMasterInfo(c.masterInfoPath()); err != nil {
		return nil, err
	} else if len(c.master.Addr) != 0 && c.master.Addr != c.cfg.Addr {
		log.Infof("MySQL addr %s in old master.info, but new %s, reset", c.master.Addr, c.cfg.Addr)
		// may use another MySQL, reset
		c.master = &masterInfo{}
	}

	c.master.Addr = c.cfg.Addr

	if err := c.prepareDumper(); err != nil {
		return nil, err
	}

	if err = c.prepareSyncer(); err != nil {
		return nil, err
	}

	if err := c.checkBinlogRowFormat(); err != nil {
		return nil, err
	}

	return c, nil
}

func (c *Canal) prepareDumper() error {
	var err error
	if c.dumper, err = dump.NewDumper(c.cfg.Dump.ExecutionPath,
		c.cfg.Addr, c.cfg.User, c.cfg.Password); err != nil {
		if err != exec.ErrNotFound {
			return err
		}
		//no mysqldump, use binlog only
		c.dumper = nil
		return nil
	}

	dbs := c.cfg.Dump.Databases
	tables := c.cfg.Dump.Tables
	tableDB := c.cfg.Dump.TableDB

	if len(tables) == 0 {
		c.dumper.AddDatabases(dbs...)
	} else {
		c.dumper.AddTables(tableDB, tables...)
	}

	for _, ignoreTable := range c.cfg.Dump.IgnoreTables {
		if seps := strings.Split(ignoreTable, ","); len(seps) == 2 {
			c.dumper.AddIgnoreTables(seps[0], seps[1])
		}
	}

	c.dumper.SetErrOut(ioutil.Discard)
	return nil
}

func (c *Canal) Start() error {
	c.wg.Add(1)
	go c.run()

	return nil
}

func (c *Canal) run() error {
	defer c.wg.Done()

	if err := c.tryDump(); err != nil {
		log.Errorf("canal dump mysql err: %v", err)
		return err
	}

	close(c.dumpDoneCh)

	if err := c.startSyncBinlog(); err != nil {
		if !c.isClosed() {
			log.Errorf("canal start sync binlog err: %v", err)
		}
		return err
	}

	return nil
}

func (c *Canal) isClosed() bool {
	return c.closed.Get()
}

func (c *Canal) Close() {
	log.Infof("close canal")

	c.m.Lock()
	defer c.m.Unlock()

	if c.isClosed() {
		return
	}

	c.closed.Set(true)

	close(c.quit)

	c.connLock.Lock()
	c.conn.Close()
	c.conn = nil
	c.connLock.Unlock()

	if c.syncer != nil {
		c.syncer.Close()
		c.syncer = nil
	}

	c.master.Close()

	c.wg.Wait()
}

func (c *Canal) WaitDumpDone() <-chan struct{} {
	return c.dumpDoneCh
}

func (c *Canal) GetTable(db string, table string) (*schema.Table, error) {
	key := fmt.Sprintf("%s.%s", db, table)
	c.tableLock.Lock()
	t, ok := c.tables[key]
	c.tableLock.Unlock()

	if ok {
		return t, nil
	}

	t, err := schema.NewTable(c, db, table)
	if err != nil {
		return nil, err
	}

	c.tableLock.Lock()
	c.tables[key] = t
	c.tableLock.Unlock()

	return t, nil
}

// Check MySQL binlog row image, must be in FULL, MINIMAL, NOBLOB
func (c *Canal) CheckBinlogRowImage(image string) error {
	fmt.Println(" CheckBinlogRowImage")
	// need to check MySQL binlog row image? full, minimal or noblob?
	// now only log
	if c.cfg.Flavor == mysql.MySQLFlavor {
		if res, err := c.Execute(`SHOW GLOBAL VARIABLES LIKE "binlog_row_image"`); err != nil {
			return err
		} else {
			// MySQL has binlog row image from 5.6, so older will return empty
			rowImage, _ := res.GetString(0, 1)
			if rowImage != "" && !strings.EqualFold(rowImage, image) {
				return fmt.Errorf("MySQL uses %s binlog row image, but we want %s", rowImage, image)
			}
		}
	}

	return nil
}

func (c *Canal) checkBinlogRowFormat() error {
	fmt.Println(" checkBinlogRowFormat")
	res, err := c.Execute(`SHOW GLOBAL VARIABLES LIKE "binlog_format";`)
	if err != nil {
		return err
	} else if f, _ := res.GetString(0, 1); f != "ROW" {
		return fmt.Errorf("binlog must ROW format, but %s now", f)
	}

	return nil
}

func (c *Canal) prepareSyncer() error {
	c.syncer = replication.NewBinlogSyncer(c.cfg.ServerID, c.cfg.Flavor)

	seps := strings.Split(c.cfg.Addr, ":")
	if len(seps) != 2 {
		return fmt.Errorf("invalid mysql addr format %s, must host:port", c.cfg.Addr)
	}

	port, err := strconv.ParseUint(seps[1], 10, 16)
	if err != nil {
		return err
	}

	if err = c.syncer.RegisterSlave(seps[0], uint16(port), c.cfg.User, c.cfg.Password); err != nil {
		return err
	}
	return nil
}

func (c *Canal) masterInfoPath() string {
	return path.Join(c.cfg.DataDir, "master.info")
}

// Execute a SQL
func (c *Canal) Execute(cmd string, args ...interface{}) (rr *mysql.Result, err error) {
	c.connLock.Lock()
	defer c.connLock.Unlock()

	retryNum := 3
	for i := 0; i < retryNum; i++ {
		if c.conn == nil {
			c.conn, err = client.Connect(c.cfg.Addr, c.cfg.User, c.cfg.Password, "")
			if err != nil {
				return nil, err
			}
		}

		rr, err = c.conn.Execute(cmd, args...)
		if err != nil && err != mysql.ErrBadConn {
			return
		} else if err == mysql.ErrBadConn {
			c.conn.Close()
			c.conn = nil
			continue
		} else {
			return
		}
	}
	return
}

func (c *Canal) SyncedPosition() mysql.Position {
	return c.master.Pos()
}
<commit_msg>Update<commit_after>package canal

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"sync"

	"github.com/fusionrsrch/go-mysql/client"
	"github.com/fusionrsrch/go-mysql/dump"
	"github.com/fusionrsrch/go-mysql/mysql"
	"github.com/fusionrsrch/go-mysql/replication"
	"github.com/fusionrsrch/go-mysql/schema"
	"github.com/siddontang/go/log"
	"github.com/siddontang/go/sync2"
)

var errCanalClosed = errors.New("canal was closed")

// Canal can sync your MySQL data into everywhere, like Elasticsearch, Redis, etc...
// MySQL must open row format for binlog
type Canal struct {
	m sync.Mutex

	cfg *Config

	master     *masterInfo
	dumper     *dump.Dumper
	dumpDoneCh chan struct{}
	syncer     *replication.BinlogSyncer

	rsLock     sync.Mutex
	rsHandlers []RowsEventHandler

	connLock sync.Mutex
	conn     *client.Conn

	wg sync.WaitGroup

	tableLock sync.Mutex
	tables    map[string]*schema.Table

	quit   chan struct{}
	closed sync2.AtomicBool
}

func NewCanal(cfg *Config) (*Canal, error) {
	c := new(Canal)
	c.cfg = cfg
	c.closed.Set(false)
	c.quit = make(chan struct{})

	os.MkdirAll(cfg.DataDir, 0755)

	c.dumpDoneCh = make(chan struct{})
	c.rsHandlers = make([]RowsEventHandler, 0, 4)
	c.tables = make(map[string]*schema.Table)

	var err error
	if c.master, err = loadMasterInfo(c.masterInfoPath()); err != nil {
		return nil, err
	} else if len(c.master.Addr) != 0 && c.master.Addr != c.cfg.Addr {
		log.Infof("MySQL addr %s in old master.info, but new %s, reset", c.master.Addr, c.cfg.Addr)
		// may use another MySQL, reset
		c.master = &masterInfo{}
	}

	c.master.Addr = c.cfg.Addr

	if err := c.prepareDumper(); err != nil {
		return nil, err
	}

	if err = c.prepareSyncer(); err != nil {
		return nil, err
	}

	if err := c.checkBinlogRowFormat(); err != nil {
		return nil, err
	}

	return c, nil
}

func (c *Canal) prepareDumper() error {
	var err error
	if c.dumper, err = dump.NewDumper(c.cfg.Dump.ExecutionPath,
		c.cfg.Addr, c.cfg.User, c.cfg.Password); err != nil {
		if err != exec.ErrNotFound {
			return err
		}
		//no mysqldump, use binlog only
		c.dumper = nil
		return nil
	}

	dbs := c.cfg.Dump.Databases
	tables := c.cfg.Dump.Tables
	tableDB := c.cfg.Dump.TableDB

	if len(tables) == 0 {
		c.dumper.AddDatabases(dbs...)
	} else {
		c.dumper.AddTables(tableDB, tables...)
	}

	for _, ignoreTable := range c.cfg.Dump.IgnoreTables {
		if seps := strings.Split(ignoreTable, ","); len(seps) == 2 {
			c.dumper.AddIgnoreTables(seps[0], seps[1])
		}
	}

	c.dumper.SetErrOut(ioutil.Discard)
	return nil
}

func (c *Canal) Start() error {
	c.wg.Add(1)
	go c.run()

	return nil
}

func (c *Canal) run() error {
	defer c.wg.Done()

	if err := c.tryDump(); err != nil {
		log.Errorf("canal dump mysql err: %v", err)
		return err
	}

	close(c.dumpDoneCh)

	if err := c.startSyncBinlog(); err != nil {
		if !c.isClosed() {
			log.Errorf("canal start sync binlog err: %v", err)
		}
		return err
	}

	return nil
}

func (c *Canal) isClosed() bool {
	return c.closed.Get()
}

func (c *Canal) Close() {
	log.Infof("close canal")

	c.m.Lock()
	defer c.m.Unlock()

	if c.isClosed() {
		return
	}

	c.closed.Set(true)

	close(c.quit)

	c.connLock.Lock()
	c.conn.Close()
	c.conn = nil
	c.connLock.Unlock()

	if c.syncer != nil {
		c.syncer.Close()
		c.syncer = nil
	}

	c.master.Close()

	c.wg.Wait()
}

func (c *Canal) WaitDumpDone() <-chan struct{} {
	return c.dumpDoneCh
}

func (c *Canal) GetTable(db string, table string) (*schema.Table, error) {
	key := fmt.Sprintf("%s.%s", db, table)
	c.tableLock.Lock()
	t, ok := c.tables[key]
	c.tableLock.Unlock()

	if ok {
		return t, nil
	}

	t, err := schema.NewTable(c, db, table)
	if err != nil {
		return nil, err
	}

	c.tableLock.Lock()
	c.tables[key] = t
	c.tableLock.Unlock()

	return t, nil
}

// Check MySQL binlog row image, must be in FULL, MINIMAL, NOBLOB
func (c *Canal) CheckBinlogRowImage(image string) error {
	fmt.Println(" CheckBinlogRowImage")
	// need to check MySQL binlog row image? full, minimal or noblob?
	// now only log
	if c.cfg.Flavor == mysql.MySQLFlavor {
		if res, err := c.Execute(`SHOW GLOBAL VARIABLES LIKE "binlog_row_image"`); err != nil {
			return err
		} else {
			// MySQL has binlog row image from 5.6, so older will return empty
			rowImage, _ := res.GetString(0, 1)
			if rowImage != "" && !strings.EqualFold(rowImage, image) {
				return fmt.Errorf("MySQL uses %s binlog row image, but we want %s", rowImage, image)
			}
			else {
				fmt.Println("MySQL 'binlog_row_image' set to %s", rowImage)
			}
		}
	}

	return nil
}

// Check MySQL binlog_row_format is set to 'ROW'
func (c *Canal) checkBinlogRowFormat() error {
	fmt.Println(" checkBinlogRowFormat")
	res, err := c.Execute(`SHOW GLOBAL VARIABLES LIKE "binlog_format";`)
	if err != nil {
		return err
	} else if f, _ := res.GetString(0, 1); f != "ROW" {
		return fmt.Errorf("binlog must ROW format, but %s now", f)
	}

	return nil
}

func (c *Canal) prepareSyncer() error {
	c.syncer = replication.NewBinlogSyncer(c.cfg.ServerID, c.cfg.Flavor)

	seps := strings.Split(c.cfg.Addr, ":")
	if len(seps) != 2 {
		return fmt.Errorf("invalid mysql addr format %s, must host:port", c.cfg.Addr)
	}

	port, err := strconv.ParseUint(seps[1], 10, 16)
	if err != nil {
		return err
	}

	if err = c.syncer.RegisterSlave(seps[0], uint16(port), c.cfg.User, c.cfg.Password); err != nil {
		return err
	}
	return nil
}

func (c *Canal) masterInfoPath() string {
	return path.Join(c.cfg.DataDir, "master.info")
}

// Execute a SQL
func (c *Canal) Execute(cmd string, args ...interface{}) (rr *mysql.Result, err error) {
	c.connLock.Lock()
	defer c.connLock.Unlock()

	retryNum := 3
	for i := 0; i < retryNum; i++ {
		if c.conn == nil {
			c.conn, err = client.Connect(c.cfg.Addr, c.cfg.User, c.cfg.Password, "")
			if err != nil {
				return nil, err
			}
		}

		rr, err = c.conn.Execute(cmd, args...)
		if err != nil && err != mysql.ErrBadConn {
			return
		} else if err == mysql.ErrBadConn {
			c.conn.Close()
			c.conn = nil
			continue
		} else {
			return
		}
	}
	return
}

func (c *Canal) SyncedPosition() mysql.Position {
	return c.master.Pos()
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/fnproject/fn/fnlb/lb"
)

const VERSION = "0.0.9"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.Parse()

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	var wg sync.WaitGroup
	wg.Add(1)
	defer wg.Wait()

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		defer wg.Done()
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<commit_msg>fnlb: 0.0.10 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/fnproject/fn/fnlb/lb"
)

const VERSION = "0.0.10"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.Parse()

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	var wg sync.WaitGroup
	wg.Add(1)
	defer wg.Wait()

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		defer wg.Done()
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<|endoftext|>


<commit_before>/*

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 (
	"flag"
	"os"

	nbv1 "github.com/kubeflow/kubeflow/components/notebook-controller/api/v1"
	nbv1alpha1 "github.com/kubeflow/kubeflow/components/notebook-controller/api/v1alpha1"
	nbv1beta1 "github.com/kubeflow/kubeflow/components/notebook-controller/api/v1beta1"
	"github.com/kubeflow/kubeflow/components/notebook-controller/controllers"
	controller_metrics "github.com/kubeflow/kubeflow/components/notebook-controller/pkg/metrics"
	"k8s.io/apimachinery/pkg/runtime"
	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/log/zap"
	// +kubebuilder:scaffold:imports
)

var (
	scheme   = runtime.NewScheme()
	setupLog = ctrl.Log.WithName("setup")
)

func init() {
	_ = clientgoscheme.AddToScheme(scheme)

	_ = nbv1alpha1.AddToScheme(scheme)
	_ = nbv1beta1.AddToScheme(scheme)
	_ = nbv1.AddToScheme(scheme)
	// +kubebuilder:scaffold:scheme
}

func main() {
	var metricsAddr string
	var enableLeaderElection bool
	flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
	flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
		"Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
	flag.Parse()

	ctrl.SetLogger(zap.Logger(true))

	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
		Scheme:             scheme,
		MetricsBindAddress: metricsAddr,
		LeaderElection:     enableLeaderElection,
	})
	if err != nil {
		setupLog.Error(err, "unable to start manager")
		os.Exit(1)
	}

	if err = (&controllers.NotebookReconciler{
		Client:        mgr.GetClient(),
		Log:           ctrl.Log.WithName("controllers").WithName("Notebook"),
		Scheme:        mgr.GetScheme(),
		Metrics:       controller_metrics.NewMetrics(mgr.GetClient()),
		EventRecorder: mgr.GetEventRecorderFor("notebook-controller"),
	}).SetupWithManager(mgr); err != nil {
		setupLog.Error(err, "unable to create controller", "controller", "Notebook")
		os.Exit(1)
	}

	// uncomment when we need the conversion webhook.
	// if err = (&nbv1beta1.Notebook{}).SetupWebhookWithManager(mgr); err != nil {
	// 	setupLog.Error(err, "unable to create webhook", "webhook", "Captain")
	// 	os.Exit(1)
	// }

	// +kubebuilder:scaffold:builder

	setupLog.Info("starting manager")
	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
		setupLog.Error(err, "problem running manager")
		os.Exit(1)
	}
}
<commit_msg>Fixes the default leader election ID (#5374)<commit_after>/*

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 (
	"flag"
	"os"

	nbv1 "github.com/kubeflow/kubeflow/components/notebook-controller/api/v1"
	nbv1alpha1 "github.com/kubeflow/kubeflow/components/notebook-controller/api/v1alpha1"
	nbv1beta1 "github.com/kubeflow/kubeflow/components/notebook-controller/api/v1beta1"
	"github.com/kubeflow/kubeflow/components/notebook-controller/controllers"
	controller_metrics "github.com/kubeflow/kubeflow/components/notebook-controller/pkg/metrics"
	"k8s.io/apimachinery/pkg/runtime"
	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/log/zap"
	// +kubebuilder:scaffold:imports
)

var (
	scheme   = runtime.NewScheme()
	setupLog = ctrl.Log.WithName("setup")
)

func init() {
	_ = clientgoscheme.AddToScheme(scheme)

	_ = nbv1alpha1.AddToScheme(scheme)
	_ = nbv1beta1.AddToScheme(scheme)
	_ = nbv1.AddToScheme(scheme)
	// +kubebuilder:scaffold:scheme
}

func main() {
	var metricsAddr, leaderElectionNamespace string
	var enableLeaderElection bool
	flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
	flag.StringVar(&leaderElectionNamespace, "leader-election-namespace", "",
		"Determines the namespace in which the leader election configmap will be created.")
	flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
		"Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
	flag.Parse()

	ctrl.SetLogger(zap.Logger(true))
	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
		Scheme:                  scheme,
		MetricsBindAddress:      metricsAddr,
		LeaderElection:          enableLeaderElection,
		LeaderElectionNamespace: leaderElectionNamespace,
		LeaderElectionID:        "kubeflow-notebook-controller",
	})
	if err != nil {
		setupLog.Error(err, "unable to start manager")
		os.Exit(1)
	}

	if err = (&controllers.NotebookReconciler{
		Client:        mgr.GetClient(),
		Log:           ctrl.Log.WithName("controllers").WithName("Notebook"),
		Scheme:        mgr.GetScheme(),
		Metrics:       controller_metrics.NewMetrics(mgr.GetClient()),
		EventRecorder: mgr.GetEventRecorderFor("notebook-controller"),
	}).SetupWithManager(mgr); err != nil {
		setupLog.Error(err, "unable to create controller", "controller", "Notebook")
		os.Exit(1)
	}

	// uncomment when we need the conversion webhook.
	// if err = (&nbv1beta1.Notebook{}).SetupWebhookWithManager(mgr); err != nil {
	// 	setupLog.Error(err, "unable to create webhook", "webhook", "Captain")
	// 	os.Exit(1)
	// }

	// +kubebuilder:scaffold:builder

	setupLog.Info("starting manager")
	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
		setupLog.Error(err, "problem running manager")
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"path/filepath"
	"reflect"
)

// MonstiSettings holds common Monsti settings.
type MonstiSettings struct {
	// Absolute paths to used directories.
	Directories struct {
		// Configuration directory
		Config string
		// Site data directory
		Data string
		// Shared data directory
		Share string
		// Runtime data directory
		Run string
	}
}

// GetServicePath returns the path to the given service's socket.
func (s MonstiSettings) GetServicePath(service string) string {
	return filepath.Join(s.Directories.Run, service+".socket")
}

// GetSiteConfigPath returns the path to the given site's configuration
// directory.
func (s MonstiSettings) GetSiteConfigPath(site string) string {
	return filepath.Join(s.Directories.Config, "sites", site)
}

// GetLocalePath returns the path to the locale directory.
func (s MonstiSettings) GetLocalePath() string {
	return filepath.Join(s.Directories.Share, "locale")
}

// GetSiteNodesPath returns the path to the given site's node directory.
func (s MonstiSettings) GetSiteNodesPath(site string) string {
	return filepath.Join(s.Directories.Data, site, "nodes")
}

// GetSiteStaticsPath returns the path to the given site's site-static
// directory.
func (s MonstiSettings) GetSiteStaticsPath(site string) string {
	return filepath.Join(s.Directories.Data, site, "site-static")
}

// GetSiteTemplatesPath returns the path to the given site's templates
// directory.
func (s MonstiSettings) GetSiteTemplatesPath(site string) string {
	return filepath.Join(s.Directories.Data, site, "templates")
}

// GetStaticsPath returns the path to the global site-static directory.
func (s MonstiSettings) GetStaticsPath() string {
	return filepath.Join(s.Directories.Share, "site-static")
}

// GetTemplatesPath returns the path to the global templates directory.
func (s MonstiSettings) GetTemplatesPath() string {
	return filepath.Join(s.Directories.Share, "templates")
}

// LoadModuleSettings loads the given module's configuration.
//
// module is the name of the module, e.g. "data"
// cfgPath is the path to the configuration directory
// settings is a pointer to a struct to be filled with the module settings. It
// must contain a field named "Monsti" of type util.MonstiSettings to be filled
// with Monsti's common settings.
func LoadModuleSettings(module, cfgPath string, settings interface{}) error {
	// Value checking
	value := reflect.ValueOf(settings)
	if !value.IsValid() || value.Kind() != reflect.Ptr ||
		reflect.Indirect(value).Kind() != reflect.Struct {
		return fmt.Errorf("util: LoadModuleSettings expects its third " +
			"argument to be a pointer to a struct")
	}
	monstiSettings := reflect.Indirect(value).FieldByName("Monsti")
	if reflect.ValueOf(monstiSettings).Kind() != reflect.Struct {
		return fmt.Errorf("util: LoadModuleSettings expects its third " +
			`argument to contain a field named "Monsti" of type ` +
			`util.MonstiSettings`)
	}

	// Load module settings
	path := filepath.Join(cfgPath, module+".yaml")
	if err := ParseYAML(path, settings); err != nil {
		return fmt.Errorf("util: Could not parse module settings: %v", err)
	}

	// Load Monsti settings
	monstiSettings.Set(reflect.Zero(monstiSettings.Type()))
	path = filepath.Join(cfgPath, "monsti.yaml")
	if err := ParseYAML(path,
		monstiSettings.Addr().Interface()); err != nil {
		return fmt.Errorf("util: Could not parse Monsti settings: %v", err)
	}
	monstiValue := monstiSettings.Addr().Interface().(*MonstiSettings)
	monstiValue.Directories.Config = cfgPath
	MakeAbsolute(&monstiValue.Directories.Data, cfgPath)
	MakeAbsolute(&monstiValue.Directories.Share, cfgPath)
	MakeAbsolute(&monstiValue.Directories.Run, cfgPath)
	return nil
}
<commit_msg>Service in service path should be lowercased.<commit_after>package util

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

// MonstiSettings holds common Monsti settings.
type MonstiSettings struct {
	// Absolute paths to used directories.
	Directories struct {
		// Configuration directory
		Config string
		// Site data directory
		Data string
		// Shared data directory
		Share string
		// Runtime data directory
		Run string
	}
}

// GetServicePath returns the path to the given service's socket.
func (s MonstiSettings) GetServicePath(service string) string {
	return filepath.Join(s.Directories.Run, strings.ToLower(service)+".socket")
}

// GetSiteConfigPath returns the path to the given site's configuration
// directory.
func (s MonstiSettings) GetSiteConfigPath(site string) string {
	return filepath.Join(s.Directories.Config, "sites", site)
}

// GetLocalePath returns the path to the locale directory.
func (s MonstiSettings) GetLocalePath() string {
	return filepath.Join(s.Directories.Share, "locale")
}

// GetSiteNodesPath returns the path to the given site's node directory.
func (s MonstiSettings) GetSiteNodesPath(site string) string {
	return filepath.Join(s.Directories.Data, site, "nodes")
}

// GetSiteStaticsPath returns the path to the given site's site-static
// directory.
func (s MonstiSettings) GetSiteStaticsPath(site string) string {
	return filepath.Join(s.Directories.Data, site, "site-static")
}

// GetSiteTemplatesPath returns the path to the given site's templates
// directory.
func (s MonstiSettings) GetSiteTemplatesPath(site string) string {
	return filepath.Join(s.Directories.Data, site, "templates")
}

// GetStaticsPath returns the path to the global site-static directory.
func (s MonstiSettings) GetStaticsPath() string {
	return filepath.Join(s.Directories.Share, "site-static")
}

// GetTemplatesPath returns the path to the global templates directory.
func (s MonstiSettings) GetTemplatesPath() string {
	return filepath.Join(s.Directories.Share, "templates")
}

// LoadModuleSettings loads the given module's configuration.
//
// module is the name of the module, e.g. "data"
// cfgPath is the path to the configuration directory
// settings is a pointer to a struct to be filled with the module settings. It
// must contain a field named "Monsti" of type util.MonstiSettings to be filled
// with Monsti's common settings.
func LoadModuleSettings(module, cfgPath string, settings interface{}) error {
	// Value checking
	value := reflect.ValueOf(settings)
	if !value.IsValid() || value.Kind() != reflect.Ptr ||
		reflect.Indirect(value).Kind() != reflect.Struct {
		return fmt.Errorf("util: LoadModuleSettings expects its third " +
			"argument to be a pointer to a struct")
	}
	monstiSettings := reflect.Indirect(value).FieldByName("Monsti")
	if reflect.ValueOf(monstiSettings).Kind() != reflect.Struct {
		return fmt.Errorf("util: LoadModuleSettings expects its third " +
			`argument to contain a field named "Monsti" of type ` +
			`util.MonstiSettings`)
	}

	// Load module settings
	path := filepath.Join(cfgPath, module+".yaml")
	if err := ParseYAML(path, settings); err != nil {
		return fmt.Errorf("util: Could not parse module settings: %v", err)
	}

	// Load Monsti settings
	monstiSettings.Set(reflect.Zero(monstiSettings.Type()))
	path = filepath.Join(cfgPath, "monsti.yaml")
	if err := ParseYAML(path,
		monstiSettings.Addr().Interface()); err != nil {
		return fmt.Errorf("util: Could not parse Monsti settings: %v", err)
	}
	monstiValue := monstiSettings.Addr().Interface().(*MonstiSettings)
	monstiValue.Directories.Config = cfgPath
	MakeAbsolute(&monstiValue.Directories.Data, cfgPath)
	MakeAbsolute(&monstiValue.Directories.Share, cfgPath)
	MakeAbsolute(&monstiValue.Directories.Run, cfgPath)
	return nil
}
<|endoftext|>


<commit_before>package ipify

import (
	"fmt"
	"runtime"
	"strings"
)

// The version of this library.
var VERSION = "1.0.0"

// This is the ipify service base URI.  This is where all API requests go.
var API_URI = "https://api.ipify.org"

// The maximum amount of tries to attempt when making API calls.
var MAX_TRIES = 3

// The user-agent string is provided so that I can (eventually) keep track of
// what libraries to support over time.  EG: Maybe the service is used
// primarily by Windows developers, and I should invest more time in improving
// those integrations.
var USER_AGENT = fmt.Sprintf(
	"go-ipify/%s go/%s %s",
	VERSION,
	runtime.Version()[2:],
	strings.Title(runtime.GOOS),
)
<commit_msg>Moving comments so the variables aren't included in godoc.<commit_after>package ipify

import (
	"fmt"
	"runtime"
	"strings"
)

// The version of this library.

var VERSION = "1.0.0"

// This is the ipify service base URI.  This is where all API requests go.

var API_URI = "https://api.ipify.org"

// The maximum amount of tries to attempt when making API calls.

var MAX_TRIES = 3

// The user-agent string is provided so that I can (eventually) keep track of
// what libraries to support over time.  EG: Maybe the service is used
// primarily by Windows developers, and I should invest more time in improving
// those integrations.

var USER_AGENT = fmt.Sprintf(
	"go-ipify/%s go/%s %s",
	VERSION,
	runtime.Version()[2:],
	strings.Title(runtime.GOOS),
)
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httptest"
	"os"
	"sync/atomic"
	"testing"

	"github.com/bpicode/fritzctl/config"
	"github.com/mitchellh/cli"
	"github.com/stretchr/testify/assert"
)

// TestCommands is a unit test that runs most commands.
func TestCommands(t *testing.T) {
	testCases := []struct {
		cmd  cli.Command
		args []string
		srv  *httptest.Server
	}{
		{cmd: &pingCommand{}, srv: serverAnswering("../testdata/loginresponse_test.xml")},
		{cmd: &listSwitchesCommand{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_4_devices_test.xml")},
		{cmd: &listThermostatsCommand{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_4_devices_test.xml")},
		{cmd: &switchOnCommand{}, args: []string{"My device"}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_4_devices_test.xml", "testdata/answer_switch_on_test")},
		{cmd: &switchOffCommand{}, args: []string{"My device"}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_4_devices_test.xml", "testdata/answer_switch_on_test")},
		{cmd: &temperatureCommand{}, args: []string{"19.5", "My device"}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_4_devices_test.xml", "testdata/answer_switch_on_test")},
		{cmd: &toggleCommand{}, args: []string{"My device"}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_4_devices_test.xml", "testdata/answer_switch_on_test")},
		{cmd: &sessionIDCommand{}, args: []string{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml")},
		{cmd: &listLandevicesCommand{}, args: []string{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/landevices_test.json")},
		{cmd: &listLogsCommand{}, args: []string{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/logs_7_lines_test.json")},
		{cmd: &listInetstatsCommand{}, args: []string{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/traffic_mon_answer.json")},
		{cmd: &listSwitchesCommand{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_fritzos06.83.xml")},
		{cmd: &listThermostatsCommand{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_fritzos06.83.xml")},
		{cmd: &manifestExportCommand{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_fritzos06.83.xml")},
		{cmd: &manifestPlanCommand{}, args: []string{"../testdata/devicelist_fritzos06.83_plan.yml"}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_fritzos06.83.xml")},
		{cmd: &manifestApplyCommand{}, args: []string{"../testdata/devicelist_fritzos06.83_plan.yml"}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_fritzos06.83.xml", "testdata/answer_switch_on_test", "testdata/answer_switch_on_test")},
	}
	for i, testCase := range testCases {
		t.Run(fmt.Sprintf("Test run command %d", i), func(t *testing.T) {
			l, err := net.Listen("tcp", ":61666")
			assert.NoError(t, err)
			testCase.srv.Listener = l
			testCase.srv.Start()
			defer testCase.srv.Close()
			exitCode := testCase.cmd.Run(testCase.args)
			assert.Equal(t, 0, exitCode)
		})
	}
}

// TestConfigure tests the interactive configuration.
func TestConfigure(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "test_fritzctl")
	defer os.Remove(tempDir)
	assert.NoError(t, err)
	config.DefaultConfigDir = tempDir
	c := configureCommand{}
	i := c.Run([]string{})
	assert.Equal(t, 0, i)
}

func serverAnswering(answers ...string) *httptest.Server {
	config.ConfigDir = "../testdata"
	config.ConfigFilename = "config_localhost_https_test.json"

	var it int32
	it = 0
	server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ch, _ := os.Open(answers[int(it)%len(answers)])
		defer ch.Close()
		atomic.AddInt32(&it, 1)
		io.Copy(w, ch)
	}))
	return server
}

// TestCommandsHaveHelp ensures that every command provides
// a help text.
func TestCommandsHaveHelp(t *testing.T) {
	c := cli.NewCLI(config.ApplicationName, config.Version)
	c.Args = os.Args[1:]
	c.Commands = map[string]cli.CommandFactory{
		"complete":        CompletionBash(c),
		"configure":       Configure,
		"applymanifest":   ManifestApply,
		"exportmanifest":  ManifestExport,
		"planmanifest":    ManifestPlan,
		"listswitches":    ListSwitches,
		"listthermostats": ListThermostats,
		"listlandevices":  ListLandevices,
		"listlogs":        ListLogs,
		"ping":            Ping,
		"sessionid":       SessionID,
		"switchon":        SwitchOnDevice,
		"switchoff":       SwitchOffDevice,
		"toggle":          ToggleDevice,
		"temperature":     Temperature,
		"inetstatas":      ListInetstats,
	}
	for i, command := range c.Commands {
		t.Run(fmt.Sprintf("Test help of command %s", i), func(t *testing.T) {
			com, err := command()
			assert.NoError(t, err)
			help := com.Help()
			fmt.Printf("Help on command %s: '%s'\n", i, help)
			assert.NotEmpty(t, help)
		})
	}
}

// TestCommandsHaveSynopsis ensures that every command provides
// short a synopsis text.
func TestCommandsHaveSynopsis(t *testing.T) {
	c := cli.NewCLI(config.ApplicationName, config.Version)
	c.Args = os.Args[1:]
	c.Commands = map[string]cli.CommandFactory{
		"complete":        CompletionBash(c),
		"configure":       Configure,
		"applymanifest":   ManifestApply,
		"exportmanifest":  ManifestExport,
		"planmanifest":    ManifestPlan,
		"listswitches":    ListSwitches,
		"listthermostats": ListThermostats,
		"listlandevices":  ListLandevices,
		"listlogs":        ListLogs,
		"ping":            Ping,
		"sessionid":       SessionID,
		"switchon":        SwitchOnDevice,
		"switchoff":       SwitchOffDevice,
		"toggle":          ToggleDevice,
		"temperature":     Temperature,
		"inetstatas":      ListInetstats,
	}
	for i, command := range c.Commands {
		t.Run(fmt.Sprintf("Test synopsis of command %s", i), func(t *testing.T) {
			com, err := command()
			assert.NoError(t, err)
			syn := com.Synopsis()
			fmt.Printf("Synopsis on command '%s': '%s'\n", i, syn)
			assert.NotEmpty(t, syn)
		})
	}
}

// TestCompletionBash tests the bash completion export.
func TestCompletionBash(t *testing.T) {
	c := cli.NewCLI(config.ApplicationName, config.Version)
	c.Args = os.Args[1:]
	c.Commands = map[string]cli.CommandFactory{
		"ping": Ping,
	}
	completionBashFactory := CompletionBash(c)
	command, err := completionBashFactory()
	assert.NoError(t, err)
	exitCode := command.Run([]string{})
	assert.Equal(t, 0, exitCode)
}
<commit_msg>fix race condition in tests<commit_after>package cmd

import (
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httptest"
	"os"
	"sync/atomic"
	"testing"

	"github.com/bpicode/fritzctl/config"
	"github.com/mitchellh/cli"
	"github.com/stretchr/testify/assert"
)

// TestCommands is a unit test that runs most commands.
func TestCommands(t *testing.T) {
	testCases := []struct {
		cmd  cli.Command
		args []string
		srv  *httptest.Server
	}{
		{cmd: &pingCommand{}, srv: serverAnswering("../testdata/loginresponse_test.xml")},
		{cmd: &listSwitchesCommand{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_4_devices_test.xml")},
		{cmd: &listThermostatsCommand{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_4_devices_test.xml")},
		{cmd: &switchOnCommand{}, args: []string{"My device"}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_4_devices_test.xml", "testdata/answer_switch_on_test")},
		{cmd: &switchOffCommand{}, args: []string{"My device"}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_4_devices_test.xml", "testdata/answer_switch_on_test")},
		{cmd: &temperatureCommand{}, args: []string{"19.5", "My device"}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_4_devices_test.xml", "testdata/answer_switch_on_test")},
		{cmd: &toggleCommand{}, args: []string{"My device"}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_4_devices_test.xml", "testdata/answer_switch_on_test")},
		{cmd: &sessionIDCommand{}, args: []string{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml")},
		{cmd: &listLandevicesCommand{}, args: []string{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/landevices_test.json")},
		{cmd: &listLogsCommand{}, args: []string{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/logs_7_lines_test.json")},
		{cmd: &listInetstatsCommand{}, args: []string{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/traffic_mon_answer.json")},
		{cmd: &listSwitchesCommand{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_fritzos06.83.xml")},
		{cmd: &listThermostatsCommand{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_fritzos06.83.xml")},
		{cmd: &manifestExportCommand{}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_fritzos06.83.xml")},
		{cmd: &manifestPlanCommand{}, args: []string{"../testdata/devicelist_fritzos06.83_plan.yml"}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_fritzos06.83.xml")},
		{cmd: &manifestApplyCommand{}, args: []string{"../testdata/devicelist_fritzos06.83_plan.yml"}, srv: serverAnswering("../testdata/loginresponse_test.xml", "../testdata/loginresponse_test.xml", "../testdata/devicelist_fritzos06.83.xml", "testdata/answer_switch_on_test", "testdata/answer_switch_on_test")},
	}
	for i, testCase := range testCases {
		t.Run(fmt.Sprintf("Test run command %d", i), func(t *testing.T) {
			l, err := net.Listen("tcp", ":61666")
			assert.NoError(t, err)
			testCase.srv.Listener = l
			testCase.srv.Start()
			defer testCase.srv.Close()
			exitCode := testCase.cmd.Run(testCase.args)
			assert.Equal(t, 0, exitCode)
		})
	}
}

// TestConfigure tests the interactive configuration.
func TestConfigure(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "test_fritzctl")
	defer os.Remove(tempDir)
	assert.NoError(t, err)
	config.DefaultConfigDir = tempDir
	c := configureCommand{}
	i := c.Run([]string{})
	assert.Equal(t, 0, i)
}

func serverAnswering(answers ...string) *httptest.Server {
	config.ConfigDir = "../testdata"
	config.ConfigFilename = "config_localhost_https_test.json"

	var it int32 = 0
	server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ch, _ := os.Open(answers[int(atomic.LoadInt32(&it))%len(answers)])
		defer ch.Close()
		atomic.AddInt32(&it, 1)
		io.Copy(w, ch)
	}))
	return server
}

// TestCommandsHaveHelp ensures that every command provides
// a help text.
func TestCommandsHaveHelp(t *testing.T) {
	c := cli.NewCLI(config.ApplicationName, config.Version)
	c.Args = os.Args[1:]
	c.Commands = map[string]cli.CommandFactory{
		"complete":        CompletionBash(c),
		"configure":       Configure,
		"applymanifest":   ManifestApply,
		"exportmanifest":  ManifestExport,
		"planmanifest":    ManifestPlan,
		"listswitches":    ListSwitches,
		"listthermostats": ListThermostats,
		"listlandevices":  ListLandevices,
		"listlogs":        ListLogs,
		"ping":            Ping,
		"sessionid":       SessionID,
		"switchon":        SwitchOnDevice,
		"switchoff":       SwitchOffDevice,
		"toggle":          ToggleDevice,
		"temperature":     Temperature,
		"inetstatas":      ListInetstats,
	}
	for i, command := range c.Commands {
		t.Run(fmt.Sprintf("Test help of command %s", i), func(t *testing.T) {
			com, err := command()
			assert.NoError(t, err)
			help := com.Help()
			fmt.Printf("Help on command %s: '%s'\n", i, help)
			assert.NotEmpty(t, help)
		})
	}
}

// TestCommandsHaveSynopsis ensures that every command provides
// short a synopsis text.
func TestCommandsHaveSynopsis(t *testing.T) {
	c := cli.NewCLI(config.ApplicationName, config.Version)
	c.Args = os.Args[1:]
	c.Commands = map[string]cli.CommandFactory{
		"complete":        CompletionBash(c),
		"configure":       Configure,
		"applymanifest":   ManifestApply,
		"exportmanifest":  ManifestExport,
		"planmanifest":    ManifestPlan,
		"listswitches":    ListSwitches,
		"listthermostats": ListThermostats,
		"listlandevices":  ListLandevices,
		"listlogs":        ListLogs,
		"ping":            Ping,
		"sessionid":       SessionID,
		"switchon":        SwitchOnDevice,
		"switchoff":       SwitchOffDevice,
		"toggle":          ToggleDevice,
		"temperature":     Temperature,
		"inetstatas":      ListInetstats,
	}
	for i, command := range c.Commands {
		t.Run(fmt.Sprintf("Test synopsis of command %s", i), func(t *testing.T) {
			com, err := command()
			assert.NoError(t, err)
			syn := com.Synopsis()
			fmt.Printf("Synopsis on command '%s': '%s'\n", i, syn)
			assert.NotEmpty(t, syn)
		})
	}
}

// TestCompletionBash tests the bash completion export.
func TestCompletionBash(t *testing.T) {
	c := cli.NewCLI(config.ApplicationName, config.Version)
	c.Args = os.Args[1:]
	c.Commands = map[string]cli.CommandFactory{
		"ping": Ping,
	}
	completionBashFactory := CompletionBash(c)
	command, err := completionBashFactory()
	assert.NoError(t, err)
	exitCode := command.Run([]string{})
	assert.Equal(t, 0, exitCode)
}
<|endoftext|>