<commit_before>package main

import (
	"bytes"
	"errors"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"testing"

	log "github.com/Sirupsen/logrus"
	"github.com/fsouza/go-dockerclient"
	"github.com/nitro/sidecar-executor/container"
	. "github.com/smartystreets/goconvey/convey"
)

type mockFetcher struct {
	ShouldFail    bool
	ShouldError   bool
	ShouldBadJson bool
	callCount   int
}

func (m *mockFetcher) Get(string) (*http.Response, error) {
	m.callCount += 1

	if m.ShouldBadJson {
		return m.badJson()
	}

	if m.ShouldError {
		return nil, errors.New("OMG something went horribly wrong!")
	}

	if m.ShouldFail {
		return m.failedRequest()
	} else {
		return m.successRequest()
	}
}

func (m *mockFetcher) successRequest() (*http.Response, error) {
	return httpResponse(200, `
		{
		    "Servers": {
		        "roncevalles": {
					"Services": {
						"deadbeef0010": {
		            	    "ID": "deadbeef0010",
		            	    "Status": 0
		            	}
					}
				}
			}
		}
	`), nil
}

func (m *mockFetcher) badJson() (*http.Response, error) {
	return httpResponse(200, `OMG invalid JSON`), nil
}

func (m *mockFetcher) failedRequest() (*http.Response, error) {
	return httpResponse(500, `
		{
		    "Servers": {
		        "roncevalles": {
					"Services": {
						"deadbeef0010": {
		            	    "ID": "deadbeef0010",
		            	    "Status": 1
		            	}
					}
				}
			}
		}
	`), nil
}

func httpResponse(status int, bodyStr string) *http.Response {
	body := bytes.NewBuffer([]byte(bodyStr))

	return &http.Response{
		Status:        strconv.Itoa(status),
		StatusCode:    status,
		Proto:         "HTTP/1.1",
		ProtoMajor:    1,
		ProtoMinor:    1,
		Body:          ioutil.NopCloser(body),
		ContentLength: int64(body.Len()),
	}
}

func Test_sidecarStatus(t *testing.T) {
	Convey("When handling Sidecar status", t, func() {
		log.SetOutput(ioutil.Discard) // Don't show logged errors/warnings/etc

		os.Setenv("TASK_HOST", "roncevalles")
		fetcher := &mockFetcher{}

		client := &container.MockDockerClient{}
		exec := newSidecarExecutor(client, &docker.AuthConfiguration{})
		exec.fetcher = fetcher

		config.SidecarRetryDelay = 0
		config.SidecarRetryCount = 0

		Convey("return healthy on HTTP request errors", func() {
			fetcher.ShouldError = true

			So(exec.sidecarStatus("deadbeef0010"), ShouldBeNil)
			So(exec.failCount, ShouldEqual, 0)
		})

		Convey("retries as expected", func() {
			fetcher.ShouldError = true
			config.SidecarRetryCount = 5

			exec.sidecarStatus("deadbeef0010")
			So(fetcher.callCount, ShouldEqual, 6) // 1 try + (5 retries)
		})

		Convey("healthy on JSON parse errors", func() {
			fetcher.ShouldBadJson = true
			So(exec.sidecarStatus("deadbeef0010"), ShouldBeNil)
			So(exec.failCount, ShouldEqual, 0)
		})

		Convey("errors when it can talk to Sidecar and fail count is exceeded", func() {
			fetcher.ShouldFail = true

			config.SidecarMaxFails = 3
			exec.failCount = 3

			result := exec.sidecarStatus("deadbeef0010")
			So(result, ShouldNotBeNil)
			So(result.Error(), ShouldContainSubstring, "deadbeef0010 failing task!")
			So(exec.failCount, ShouldEqual, 0) // Gets reset!
		})

		Convey("healthy when it can talk to Sidecar and fail count is below limit", func() {
			fetcher.ShouldFail = true

			config.SidecarMaxFails = 3
			exec.failCount = 1

			result := exec.sidecarStatus("deadbeef0010")
			So(result, ShouldBeNil)
			So(exec.failCount, ShouldEqual, 2)
		})

		Convey("resets failCount on first healthy response", func() {
			fetcher.ShouldFail = true

			config.SidecarMaxFails = 3
			exec.failCount = 1

			result := exec.sidecarStatus("deadbeef0010")
			So(result, ShouldBeNil)
			So(exec.failCount, ShouldEqual, 2)

			// Get a healthy response, reset the counter
			fetcher.ShouldFail = false
			result = exec.sidecarStatus("deadbeef0010")
			So(result, ShouldBeNil)
			So(exec.failCount, ShouldEqual, 0)
		})
	})
}
<commit_msg>A few more tests around sidecarStatus<commit_after>package main

import (
	"bytes"
	"errors"
	"io/ioutil"
	"net/http"
	"os"
	"reflect"
	"strconv"
	"testing"

	log "github.com/Sirupsen/logrus"
	"github.com/fsouza/go-dockerclient"
	"github.com/nitro/sidecar-executor/container"
	. "github.com/smartystreets/goconvey/convey"
)

type mockFetcher struct {
	ShouldFail    bool
	ShouldError   bool
	ShouldBadJson bool
	callCount   int
}

func (m *mockFetcher) Get(string) (*http.Response, error) {
	m.callCount += 1

	if m.ShouldBadJson {
		return m.badJson()
	}

	if m.ShouldError {
		return nil, errors.New("OMG something went horribly wrong!")
	}

	if m.ShouldFail {
		return m.failedRequest()
	} else {
		return m.successRequest()
	}
}

func (m *mockFetcher) successRequest() (*http.Response, error) {
	return httpResponse(200, `
		{
		    "Servers": {
		        "roncevalles": {
					"Services": {
						"deadbeef0010": {
		            	    "ID": "deadbeef0010",
		            	    "Status": 0
		            	}
					}
				}
			}
		}
	`), nil
}

func (m *mockFetcher) badJson() (*http.Response, error) {
	return httpResponse(200, `OMG invalid JSON`), nil
}

func (m *mockFetcher) failedRequest() (*http.Response, error) {
	return httpResponse(500, `
		{
		    "Servers": {
		        "roncevalles": {
					"Services": {
						"deadbeef0010": {
		            	    "ID": "deadbeef0010",
		            	    "Status": 1
		            	}
					}
				}
			}
		}
	`), nil
}

func httpResponse(status int, bodyStr string) *http.Response {
	body := bytes.NewBuffer([]byte(bodyStr))

	return &http.Response{
		Status:        strconv.Itoa(status),
		StatusCode:    status,
		Proto:         "HTTP/1.1",
		ProtoMajor:    1,
		ProtoMinor:    1,
		Body:          ioutil.NopCloser(body),
		ContentLength: int64(body.Len()),
	}
}

func Test_sidecarStatus(t *testing.T) {
	Convey("When handling Sidecar status", t, func() {
		log.SetOutput(ioutil.Discard) // Don't show logged errors/warnings/etc

		os.Setenv("TASK_HOST", "roncevalles")
		fetcher := &mockFetcher{}

		client := &container.MockDockerClient{}
		exec := newSidecarExecutor(client, &docker.AuthConfiguration{})
		exec.fetcher = fetcher

		config.SidecarRetryDelay = 0
		config.SidecarRetryCount = 0

		Convey("return healthy on HTTP request errors", func() {
			fetcher.ShouldError = true

			So(exec.sidecarStatus("deadbeef0010"), ShouldBeNil)
			So(exec.failCount, ShouldEqual, 0)
		})

		Convey("retries as expected", func() {
			fetcher.ShouldError = true
			config.SidecarRetryCount = 5

			exec.sidecarStatus("deadbeef0010")
			So(fetcher.callCount, ShouldEqual, 6) // 1 try + (5 retries)
		})

		Convey("healthy on JSON parse errors", func() {
			fetcher.ShouldBadJson = true
			So(exec.sidecarStatus("deadbeef0010"), ShouldBeNil)
			So(exec.failCount, ShouldEqual, 0)
		})

		Convey("errors when it can talk to Sidecar and fail count is exceeded", func() {
			fetcher.ShouldFail = true

			config.SidecarMaxFails = 3
			exec.failCount = 3

			result := exec.sidecarStatus("deadbeef0010")
			So(result, ShouldNotBeNil)
			So(result.Error(), ShouldContainSubstring, "deadbeef0010 failing task!")
			So(exec.failCount, ShouldEqual, 0) // Gets reset!
		})

		Convey("healthy when it can talk to Sidecar and fail count is below limit", func() {
			fetcher.ShouldFail = true

			config.SidecarMaxFails = 3
			exec.failCount = 1

			result := exec.sidecarStatus("deadbeef0010")
			So(result, ShouldBeNil)
			So(exec.failCount, ShouldEqual, 2)
		})

		Convey("resets failCount on first healthy response", func() {
			fetcher.ShouldFail = true

			config.SidecarMaxFails = 3
			exec.failCount = 1

			result := exec.sidecarStatus("deadbeef0010")
			So(result, ShouldBeNil)
			So(exec.failCount, ShouldEqual, 2)

			// Get a healthy response, reset the counter
			fetcher.ShouldFail = false
			result = exec.sidecarStatus("deadbeef0010")
			So(result, ShouldBeNil)
			So(exec.failCount, ShouldEqual, 0)
		})

		Convey("healthy when the host doesn't exist in Sidecar", func() {
			os.Setenv("TASK_HOST", "zaragoza")
			fetcher.ShouldError = false

			So(exec.sidecarStatus("deadbeef0010"), ShouldBeNil)
			So(exec.failCount, ShouldEqual, 0)
		})
	})
}

func Test_logConfig(t *testing.T) {
	// We want to make sure we don't forget to print settings when they get added
	Convey("Logs all the config settings", t, func() {
		output := bytes.NewBuffer([]byte{})

		os.Setenv("MESOS_LEGEND", "roncevalles")

		log.SetOutput(output) // Don't show the output
		logConfig()

		v := reflect.ValueOf(config)
		for i := 0; i < v.NumField(); i++ {
		    So(string(output.Bytes()), ShouldContainSubstring, v.Type().Field(i).Name)
		}
	})
}
<|endoftext|>


<commit_before>package hotspot

import (
	"fmt"
	"path"
	"testing"

	"github.com/ready-steady/assert"
)

const (
	fixturePath = "fixtures"
)

func TestNew(t *testing.T) {
	config := prepare("002")
	model := New(config)

	assert.Equal(model.Cores, uint(2), t)
	assert.Equal(model.Nodes, uint(20), t)

	assert.EqualWithin(model.C, fixtureC, 2e-15, t)
	assert.EqualWithin(model.G, fixtureG, 2e-14, t)
}

func BenchmarkNew(b *testing.B) {
	config := prepare("032")

	for i := 0; i < b.N; i++ {
		New(config)
	}
}

func prepare(floorplan string) *Config {
	return &Config{
		Floorplan:     findFixture(fmt.Sprintf("%s.flp", floorplan)),
		Configuration: findFixture("hotspot.config"),
	}
}

func findFixture(name string) string {
	return path.Join(fixturePath, name)
}
<commit_msg>Replace EqualWithin with Close<commit_after>package hotspot

import (
	"fmt"
	"path"
	"testing"

	"github.com/ready-steady/assert"
)

const (
	fixturePath = "fixtures"
)

func TestNew(t *testing.T) {
	config := prepare("002")
	model := New(config)

	assert.Equal(model.Cores, uint(2), t)
	assert.Equal(model.Nodes, uint(20), t)

	assert.Close(model.C, fixtureC, 2e-15, t)
	assert.Close(model.G, fixtureG, 2e-14, t)
}

func BenchmarkNew(b *testing.B) {
	config := prepare("032")

	for i := 0; i < b.N; i++ {
		New(config)
	}
}

func prepare(floorplan string) *Config {
	return &Config{
		Floorplan:     findFixture(fmt.Sprintf("%s.flp", floorplan)),
		Configuration: findFixture("hotspot.config"),
	}
}

func findFixture(name string) string {
	return path.Join(fixturePath, name)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"net/http"
	"net/http/httptest"
	"testing"
)

func setCorrectBasicAuth(r *http.Request) {
	r.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:admin")))
}

func TestHelloWorld(t *testing.T) {
	server := httptest.NewServer(Router())
	defer server.Close()

	res, _ := http.Get(server.URL)

	if res.StatusCode != http.StatusOK {
		t.Error(res.StatusCode)
	}
}

func TestCatalog(t *testing.T) {
	ts := Router()

	r, _ := http.NewRequest("GET", "/v2/catalog", nil)

	w := httptest.NewRecorder()
	ts.ServeHTTP(w, r)
	// should return 401
	if w.Code != http.StatusUnauthorized {
		t.Errorf("Got %d, wanted 401.", w.Code)
	}

	// should return 200
	w = httptest.NewRecorder()
	setCorrectBasicAuth(r)
	ts.ServeHTTP(w, r)
	if w.Code != http.StatusOK {
		t.Errorf("Got %d, wanted 200.", w.Code)
	}
}
<commit_msg>Seperate out auth tests.<commit_after>package main

import (
	"encoding/base64"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

func setCorrectBasicAuth(r *http.Request) {
	r.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:admin")))
}

func TestHelloWorld(t *testing.T) {
	server := httptest.NewServer(Router())
	defer server.Close()

	res, _ := http.Get(server.URL)

	if res.StatusCode != http.StatusOK {
		t.Error(res.StatusCode)
	}
}

func TestAuth(t *testing.T) {
	ts := Router()

	r, _ := http.NewRequest("GET", "/v2/catalog", nil)
	w := httptest.NewRecorder()

	ts.ServeHTTP(w, r)
	// should return 401
	if w.Code != http.StatusUnauthorized {
		t.Errorf("Got %d, wanted 401.", w.Code)
	}

	// should return 200
	w = httptest.NewRecorder()
	setCorrectBasicAuth(r)

	ts.ServeHTTP(w, r)
	if w.Code != http.StatusOK {
		t.Errorf("Got %d, wanted 200.", w.Code)
	}
}

func TestCatalog(t *testing.T) {
	ts := Router()
	r, _ := http.NewRequest("GET", "/v2/catalog", nil)
	w := httptest.NewRecorder()

	setCorrectBasicAuth(r)
	ts.ServeHTTP(w, r)

	b, _ := ioutil.ReadAll(w.Body)
	body := string(b)

	if !strings.Contains(body, "postgresql-db") {
		t.Errorf("Expected body to contain postgresql-db. Got %s", body)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/ONSdigital/florence/assets"
	. "github.com/smartystreets/goconvey/convey"
)

func TestMain(t *testing.T) {
	Convey("Returns 200 when asset is requested", t, func() {
		recorder := httptest.NewRecorder()
		request, err := http.NewRequest("GET", "/florence/dist/js/florence.bundle.js", nil)
		request.URL.RawQuery = ":uri=js/florence.bundle.js"
		So(err, ShouldBeNil)
		request.Header.Set("Accept-Language", "en")
		staticFiles(recorder, request)
		So(recorder.Code, ShouldEqual, 200)
	})

	Convey("Returns 404 when an unrecognised asset path is given", t, func() {
		recorder := httptest.NewRecorder()
		rdr := bytes.NewReader([]byte(``))
		request, err := http.NewRequest("GET", "/florence/dist/foo", rdr)
		request.URL.RawQuery = ":uri=foo"
		So(err, ShouldBeNil)
		request.Header.Set("Accept-Language", "en")
		staticFiles(recorder, request)
		So(recorder.Code, ShouldEqual, 404)
	})

	Convey("Request for legacy HTML file returns a 200 response", t, func() {
		recorder := httptest.NewRecorder()
		rdr := bytes.NewReader([]byte(``))
		request, err := http.NewRequest("GET", "", rdr)
		So(err, ShouldBeNil)
		request.Header.Set("Accept-Language", "en")
		legacyIndexFile(recorder, request)
		So(recorder.Code, ShouldEqual, 200)
	})

	Convey("Request for missing legacy HTML file returns a 404", t, func() {
		getAsset = func(path string) ([]byte, error) {
			return nil, errors.New("Legacy HTML file not found")
		}
		defer func() {
			getAsset = assets.Asset
		}()
		recorder := httptest.NewRecorder()
		rdr := bytes.NewReader([]byte(``))
		request, err := http.NewRequest("GET", "", rdr)
		So(err, ShouldBeNil)
		request.Header.Set("Accept-Language", "en")
		legacyIndexFile(recorder, request)
		So(recorder.Code, ShouldEqual, 404)
	})

	Convey("Request for refactored HTML file returns a 200 response", t, func() {
		recorder := httptest.NewRecorder()
		rdr := bytes.NewReader([]byte(``))
		request, err := http.NewRequest("GET", "", rdr)
		So(err, ShouldBeNil)
		request.Header.Set("Accept-Language", "en")
		refactoredIndexFile(recorder, request)
		So(recorder.Code, ShouldEqual, 200)
	})

	Convey("Request for missing refactored HTML file returns a 404", t, func() {
		getAsset = func(path string) ([]byte, error) {
			return nil, errors.New("Refactored HTML file not found")
		}
		defer func() {
			getAsset = assets.Asset
		}()
		recorder := httptest.NewRecorder()
		rdr := bytes.NewReader([]byte(``))
		request, err := http.NewRequest("GET", "", rdr)
		So(err, ShouldBeNil)
		request.Header.Set("Accept-Language", "en")
		refactoredIndexFile(recorder, request)
		So(recorder.Code, ShouldEqual, 404)
	})

	Convey("Table renderer proxy director function trims '/table' from the request URL", t, func() {
		request, err := http.NewRequest("GET", "/table/parse", nil)
		So(err, ShouldBeNil)
		tableDirector(request)
		So(request.URL.String(), ShouldEqual, "/parse")
	})

	Convey("Zebedee proxy director function trims '/zebedee' from the request URL", t, func() {
		request, err := http.NewRequest("GET", "/zebedee/test", nil)
		So(err, ShouldBeNil)
		zebedeeDirector(request)
		So(request.URL.String(), ShouldEqual, "/test")
	})

	Convey("Zebedee proxy director function sets 'X-Florence-Token' header when access_token cookie is available", t, func() {
		cookie := http.Cookie{"access_token", "foo", "/", "http://localhost", time.Now().AddDate(0, 0, 1), time.Now().AddDate(0, 0, 1).Format(time.UnixDate), 0, false, true, "access_token=foo", []string{"access_token=foo"}}
		request, err := http.NewRequest("GET", "", nil)
		So(err, ShouldBeNil)
		request.AddCookie(&cookie)
		zebedeeDirector(request)
		So(request.Header.Get("X-Florence-Token"), ShouldEqual, "foo")
	})

	Convey("Zebedee proxy director function doesn't set 'X-Florence-Token' header when no access_token cookie is available", t, func() {
		request, err := http.NewRequest("GET", "", nil)
		So(err, ShouldBeNil)
		zebedeeDirector(request)
		So(request.Header.Get("X-Florence-Token"), ShouldBeBlank)
	})
}
<commit_msg>Fix go test failure<commit_after>package main

import (
	"bytes"
	"errors"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/ONSdigital/florence/assets"
	. "github.com/smartystreets/goconvey/convey"
)

func TestMain(t *testing.T) {
	Convey("Returns 200 when asset is requested", t, func() {
		recorder := httptest.NewRecorder()
		request, err := http.NewRequest("GET", "/florence/dist/js/app.bundle.js", nil)
		request.URL.RawQuery = ":uri=js/app.bundle.js"
		So(err, ShouldBeNil)
		request.Header.Set("Accept-Language", "en")
		staticFiles(recorder, request)
		So(recorder.Code, ShouldEqual, 200)
	})

	Convey("Returns 404 when an unrecognised asset path is given", t, func() {
		recorder := httptest.NewRecorder()
		rdr := bytes.NewReader([]byte(``))
		request, err := http.NewRequest("GET", "/florence/dist/foo", rdr)
		request.URL.RawQuery = ":uri=foo"
		So(err, ShouldBeNil)
		request.Header.Set("Accept-Language", "en")
		staticFiles(recorder, request)
		So(recorder.Code, ShouldEqual, 404)
	})

	Convey("Request for legacy HTML file returns a 200 response", t, func() {
		recorder := httptest.NewRecorder()
		rdr := bytes.NewReader([]byte(``))
		request, err := http.NewRequest("GET", "", rdr)
		So(err, ShouldBeNil)
		request.Header.Set("Accept-Language", "en")
		legacyIndexFile(recorder, request)
		So(recorder.Code, ShouldEqual, 200)
	})

	Convey("Request for missing legacy HTML file returns a 404", t, func() {
		getAsset = func(path string) ([]byte, error) {
			return nil, errors.New("Legacy HTML file not found")
		}
		defer func() {
			getAsset = assets.Asset
		}()
		recorder := httptest.NewRecorder()
		rdr := bytes.NewReader([]byte(``))
		request, err := http.NewRequest("GET", "", rdr)
		So(err, ShouldBeNil)
		request.Header.Set("Accept-Language", "en")
		legacyIndexFile(recorder, request)
		So(recorder.Code, ShouldEqual, 404)
	})

	Convey("Request for refactored HTML file returns a 200 response", t, func() {
		recorder := httptest.NewRecorder()
		rdr := bytes.NewReader([]byte(``))
		request, err := http.NewRequest("GET", "", rdr)
		So(err, ShouldBeNil)
		request.Header.Set("Accept-Language", "en")
		refactoredIndexFile(recorder, request)
		So(recorder.Code, ShouldEqual, 200)
	})

	Convey("Request for missing refactored HTML file returns a 404", t, func() {
		getAsset = func(path string) ([]byte, error) {
			return nil, errors.New("Refactored HTML file not found")
		}
		defer func() {
			getAsset = assets.Asset
		}()
		recorder := httptest.NewRecorder()
		rdr := bytes.NewReader([]byte(``))
		request, err := http.NewRequest("GET", "", rdr)
		So(err, ShouldBeNil)
		request.Header.Set("Accept-Language", "en")
		refactoredIndexFile(recorder, request)
		So(recorder.Code, ShouldEqual, 404)
	})

	Convey("Table renderer proxy director function trims '/table' from the request URL", t, func() {
		request, err := http.NewRequest("GET", "/table/parse", nil)
		So(err, ShouldBeNil)
		tableDirector(request)
		So(request.URL.String(), ShouldEqual, "/parse")
	})

	Convey("Zebedee proxy director function trims '/zebedee' from the request URL", t, func() {
		request, err := http.NewRequest("GET", "/zebedee/test", nil)
		So(err, ShouldBeNil)
		zebedeeDirector(request)
		So(request.URL.String(), ShouldEqual, "/test")
	})

	Convey("Zebedee proxy director function sets 'X-Florence-Token' header when access_token cookie is available", t, func() {
		cookie := http.Cookie{"access_token", "foo", "/", "http://localhost", time.Now().AddDate(0, 0, 1), time.Now().AddDate(0, 0, 1).Format(time.UnixDate), 0, false, true, "access_token=foo", []string{"access_token=foo"}}
		request, err := http.NewRequest("GET", "", nil)
		So(err, ShouldBeNil)
		request.AddCookie(&cookie)
		zebedeeDirector(request)
		So(request.Header.Get("X-Florence-Token"), ShouldEqual, "foo")
	})

	Convey("Zebedee proxy director function doesn't set 'X-Florence-Token' header when no access_token cookie is available", t, func() {
		request, err := http.NewRequest("GET", "", nil)
		So(err, ShouldBeNil)
		zebedeeDirector(request)
		So(request.Header.Get("X-Florence-Token"), ShouldBeBlank)
	})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"strings"
)

const pvpFeatsOfStrengthCategory int = 15270

var achievementIDs = []int{
	// Arena achievements
	401, 405, 404, 1159, 1160, 1161, 5266, 5267, 876, 2090, 2093, 2092, 2091,
	// RBG achievements
	5329, 5326, 5339, 5353, 5341, 5355, 5343, 5356, 6942, 6941}

func importStaticData() {
	logger.Println("Beginning import of static data")
	importRealms(region) // TODO IMPORT FOR EACH REGION
	importRaces()
	importClasses()
	importSpecsAndTalents()
	importPvPTalents()
	importAchievements()

	logger.Println("Static data import complete")
}

func parseRealms(data *[]byte) []realm {
	type Realms struct {
		Realms []realm
	}
	var realms Realms
	err := json.Unmarshal(*data, &realms)
	if err != nil {
		logger.Printf("%s json parsing failed: %s", errPrefix, err)
		return make([]realm, 0)
	}
	return realms.Realms
}

func importRealms(region string) {
	var realmJSON *[]byte = getDynamic(region, "realm/index")
	var realms []realm = parseRealms(realmJSON)
	logger.Printf("Found %d %s realms", len(realms), region)
	addRealms(&realms, region)
}

func parseRaces(data *[]byte) []race {
	type Races struct {
		Races []race
	}
	var races Races
	err := json.Unmarshal(*data, &races)
	if err != nil {
		logger.Printf("%s json parsing failed: %s", errPrefix, err)
		return make([]race, 0)
	}
	return races.Races
}

func importRaces() {
	var racesJSON *[]byte = getStatic(region, "playable-race/index")
	var races []race = parseRaces(racesJSON)
	logger.Printf("Found %d races", len(races))
	addRaces(&races)
}

func parseClasses(data *[]byte) []class {
	type Classes struct {
		Classes []class
	}
	var classes Classes
	err := json.Unmarshal(*data, &classes)
	if err != nil {
		logger.Printf("%s json parsing failed: %s", errPrefix, err)
		return make([]class, 0)
	}
	return classes.Classes
}

func importClasses() {
	var classesJSON *[]byte = getStatic(region, "playable-class/index")
	var classes []class = parseClasses(classesJSON)
	logger.Printf("Found %d classes", len(classes))
	addClasses(&classes)
}

func importSpecsAndTalents() {
	var specsJSON *[]byte = getStatic(region, "playable-specialization/index")
	var specs []spec = parseSpecs(specsJSON)
	logger.Printf("Found %d specializations", len(specs))
	addSpecs(&specs)
	var talents []talent = make([]talent, 0)
	for _, spec := range specs {
		talents = append(talents, spec.Talents...)
	}
	addTalents(&talents)
}

func parseSpecs(data *[]byte) []spec {
	type CharacterSpecializationJSON struct {
		ID int
	}
	type SpecsJSON struct {
		CharacterSpecializations []CharacterSpecializationJSON `json:"character_specializations"`
	}
	var specsJSON SpecsJSON
	err := json.Unmarshal(*data, &specsJSON)
	if err != nil {
		logger.Printf("%s json parsing failed: %s", errPrefix, err)
		return make([]spec, 0)
	}
	var specIDs []int = make([]int, 0)
	for _, cs := range specsJSON.CharacterSpecializations {
		specIDs = append(specIDs, cs.ID)
	}
	return getFullSpecInfo(specIDs)
}

func getFullSpecInfo(specIDs []int) []spec {
	var specs []spec = make([]spec, 0)
	var ch chan spec = make(chan spec, len(specIDs))
	for _, i := range specIDs {
		go getSpec(ch, i)
	}
	for range specIDs {
		specs = append(specs, <-ch)
	}
	return specs
}

func getSpec(ch chan spec, specID int) {
	type RoleJSON struct {
		Role string `json:"type"`
	}
	type SpecJSON struct {
		ID            int
		PlayableClass class `json:"playable_class"`
		Name          string
		Media         keyedValue
		Role          RoleJSON
		TalentTiers   []talentTierJSON `json:"talent_tiers"`
	}
	var path string = fmt.Sprintf("playable-specialization/%d", specID)
	var icon = getIcon(region, path)
	var specJSON *[]byte = getStatic(region, path)
	var s SpecJSON
	json.Unmarshal(*specJSON, &s)
	ch <- spec{
		s.ID,
		s.PlayableClass.ID,
		s.Name,
		s.Role.Role,
		icon,
		getFullSpecTalents(specID, s.TalentTiers)}
}

func getFullSpecTalents(specID int, talentTiers []talentTierJSON) []talent {
	var talents []talent = make([]talent, 0)
	type TalentJSON struct {
		ID            int
		Spell         keyedValue
		PlayableClass class `json:"playable_class"`
	}
	for _, t := range talentTiers {
		tier := t.TierIndex
		for _, talentEntry := range t.Talents {
			col := talentEntry.ColumnIndex
			id := talentEntry.Talent.ID
			var talentJSON *[]byte = getStatic(region, fmt.Sprintf("talent/%d", id))
			var talentDetails TalentJSON
			json.Unmarshal(*talentJSON, &talentDetails)
			icon := getIcon(region, fmt.Sprintf("spell/%d", talentDetails.Spell.ID))
			talent := talent{
				id,
				talentDetails.Spell.ID,
				talentDetails.PlayableClass.ID,
				specID,
				talentDetails.Spell.Name,
				icon,
				tier,
				col}
			talents = append(talents, talent)
		}
	}
	return talents
}

func importPvPTalents() {
	var talentsJSON *[]byte = getStatic(region, "pvp-talent/index")
	var pvpTalents []pvpTalent = parsePvPTalents(talentsJSON)
	logger.Printf("Found %d PvP Talents", len(pvpTalents))
	addPvPTalents(&pvpTalents)
}

func parsePvPTalents(data *[]byte) []pvpTalent {
	type PvPTalentsJSON struct {
		PvPTalents []keyedValue `json:"pvp_talents"`
	}
	var pvpTalentsJSON PvPTalentsJSON
	err := json.Unmarshal(*data, &pvpTalentsJSON)
	if err != nil {
		logger.Printf("%s json parsing failed: %s", errPrefix, err)
		return make([]pvpTalent, 0)
	}
	var pvpTalents []pvpTalent = make([]pvpTalent, 0)
	var ch chan pvpTalent = make(chan pvpTalent, len(pvpTalentsJSON.PvPTalents))
	for _, keyedValue := range pvpTalentsJSON.PvPTalents {
		go getPvPTalent(ch, keyedValue.ID)
	}
	for range pvpTalentsJSON.PvPTalents {
		pvpTalents = append(pvpTalents, <-ch)
	}
	return pvpTalents
}

func getPvPTalent(ch chan pvpTalent, id int) {
	type PvPTalentJSON struct {
		Spell                  keyedValue
		PlayableSpecialization keyedValue `json:"playable_specialization"`
	}
	var pvpTalentJSON *[]byte = getStatic(region, fmt.Sprintf("pvp-talent/%d", id))
	var talentDetails PvPTalentJSON
	json.Unmarshal(*pvpTalentJSON, &talentDetails)
	icon := getIcon(region, fmt.Sprintf("spell/%d", talentDetails.Spell.ID))
	ch <- pvpTalent{
		id,
		talentDetails.Spell.Name,
		talentDetails.Spell.ID,
		talentDetails.PlayableSpecialization.ID,
		icon}
}

func parseAchievements(data *[]byte) []achievement {
	type Achievements struct {
		ID           int
		Name         string
		Achievements []keyedValue
	}

	var achievements Achievements
	err := json.Unmarshal(*data, &achievements)
	var pvpAchievements []achievement = make([]achievement, 0)
	if err != nil {
		logger.Printf("%s json parsing failed: %s", errPrefix, err)
		return pvpAchievements
	}

	var achievementIDs []int = make([]int, 0)
	for _, ac := range achievements.Achievements {
		if strings.Contains(ac.Name, "Season") {
			achievementIDs = append(achievementIDs, ac.ID)
		}
	}
	var ch chan achievement = make(chan achievement, len(achievementIDs))
	for _, id := range achievementIDs {
		go getPvPAchievement(ch, id)
	}
	for range achievementIDs {
		pvpAchievements = append(pvpAchievements, <-ch)
	}

	return pvpAchievements
}

func getPvPAchievement(ch chan achievement, id int) {
	ch <- getAchievement(id)
}

func getAchievement(id int) achievement {
	type PvPAchievementJSON struct {
		ID          int
		Name        string
		Description string
	}
	var pvpAchievementJSON *[]byte = getStatic(region, fmt.Sprintf("achievement/%d", id))
	var pvpAchievementJSONDetails PvPAchievementJSON
	json.Unmarshal(*pvpAchievementJSON, &pvpAchievementJSONDetails)
	return achievement{
		id,
		pvpAchievementJSONDetails.Name,
		pvpAchievementJSONDetails.Description}
}

func importAchievements() {
	var achievementsJSON *[]byte = getStatic(region, fmt.Sprintf("achievement-category/%d", pvpFeatsOfStrengthCategory))
	var achievements []achievement = parseAchievements(achievementsJSON)
	var seasonalCount int = len(achievements)
	logger.Printf("Found %d seasonal achievements", seasonalCount)
	for _, id := range achievementIDs {
		achievement := getAchievement(id)
		achievements = append(achievements, achievement)
	}
	logger.Printf("Found %d non-seasonal achievements", len(achievements)-seasonalCount)
	addAchievements(&achievements)
}
<commit_msg>import realms for each region<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"strings"
)

const pvpFeatsOfStrengthCategory int = 15270

var achievementIDs = []int{
	// Arena achievements
	401, 405, 404, 1159, 1160, 1161, 5266, 5267, 876, 2090, 2093, 2092, 2091,
	// RBG achievements
	5329, 5326, 5339, 5353, 5341, 5355, 5343, 5356, 6942, 6941}

func importStaticData() {
	logger.Println("Beginning import of static data")
	for _, r := range regions {
		importRealms(r)
	}
	importRaces()
	importClasses()
	importSpecsAndTalents()
	importPvPTalents()
	importAchievements()

	logger.Println("Static data import complete")
}

func parseRealms(data *[]byte) []realm {
	type Realms struct {
		Realms []realm
	}
	var realms Realms
	err := json.Unmarshal(*data, &realms)
	if err != nil {
		logger.Printf("%s json parsing failed: %s", errPrefix, err)
		return make([]realm, 0)
	}
	return realms.Realms
}

func importRealms(region string) {
	var realmJSON *[]byte = getDynamic(region, "realm/index")
	var realms []realm = parseRealms(realmJSON)
	logger.Printf("Found %d %s realms", len(realms), region)
	addRealms(&realms, region)
}

func parseRaces(data *[]byte) []race {
	type Races struct {
		Races []race
	}
	var races Races
	err := json.Unmarshal(*data, &races)
	if err != nil {
		logger.Printf("%s json parsing failed: %s", errPrefix, err)
		return make([]race, 0)
	}
	return races.Races
}

func importRaces() {
	var racesJSON *[]byte = getStatic(region, "playable-race/index")
	var races []race = parseRaces(racesJSON)
	logger.Printf("Found %d races", len(races))
	addRaces(&races)
}

func parseClasses(data *[]byte) []class {
	type Classes struct {
		Classes []class
	}
	var classes Classes
	err := json.Unmarshal(*data, &classes)
	if err != nil {
		logger.Printf("%s json parsing failed: %s", errPrefix, err)
		return make([]class, 0)
	}
	return classes.Classes
}

func importClasses() {
	var classesJSON *[]byte = getStatic(region, "playable-class/index")
	var classes []class = parseClasses(classesJSON)
	logger.Printf("Found %d classes", len(classes))
	addClasses(&classes)
}

func importSpecsAndTalents() {
	var specsJSON *[]byte = getStatic(region, "playable-specialization/index")
	var specs []spec = parseSpecs(specsJSON)
	logger.Printf("Found %d specializations", len(specs))
	addSpecs(&specs)
	var talents []talent = make([]talent, 0)
	for _, spec := range specs {
		talents = append(talents, spec.Talents...)
	}
	addTalents(&talents)
}

func parseSpecs(data *[]byte) []spec {
	type CharacterSpecializationJSON struct {
		ID int
	}
	type SpecsJSON struct {
		CharacterSpecializations []CharacterSpecializationJSON `json:"character_specializations"`
	}
	var specsJSON SpecsJSON
	err := json.Unmarshal(*data, &specsJSON)
	if err != nil {
		logger.Printf("%s json parsing failed: %s", errPrefix, err)
		return make([]spec, 0)
	}
	var specIDs []int = make([]int, 0)
	for _, cs := range specsJSON.CharacterSpecializations {
		specIDs = append(specIDs, cs.ID)
	}
	return getFullSpecInfo(specIDs)
}

func getFullSpecInfo(specIDs []int) []spec {
	var specs []spec = make([]spec, 0)
	var ch chan spec = make(chan spec, len(specIDs))
	for _, i := range specIDs {
		go getSpec(ch, i)
	}
	for range specIDs {
		specs = append(specs, <-ch)
	}
	return specs
}

func getSpec(ch chan spec, specID int) {
	type RoleJSON struct {
		Role string `json:"type"`
	}
	type SpecJSON struct {
		ID            int
		PlayableClass class `json:"playable_class"`
		Name          string
		Media         keyedValue
		Role          RoleJSON
		TalentTiers   []talentTierJSON `json:"talent_tiers"`
	}
	var path string = fmt.Sprintf("playable-specialization/%d", specID)
	var icon = getIcon(region, path)
	var specJSON *[]byte = getStatic(region, path)
	var s SpecJSON
	json.Unmarshal(*specJSON, &s)
	ch <- spec{
		s.ID,
		s.PlayableClass.ID,
		s.Name,
		s.Role.Role,
		icon,
		getFullSpecTalents(specID, s.TalentTiers)}
}

func getFullSpecTalents(specID int, talentTiers []talentTierJSON) []talent {
	var talents []talent = make([]talent, 0)
	type TalentJSON struct {
		ID            int
		Spell         keyedValue
		PlayableClass class `json:"playable_class"`
	}
	for _, t := range talentTiers {
		tier := t.TierIndex
		for _, talentEntry := range t.Talents {
			col := talentEntry.ColumnIndex
			id := talentEntry.Talent.ID
			var talentJSON *[]byte = getStatic(region, fmt.Sprintf("talent/%d", id))
			var talentDetails TalentJSON
			json.Unmarshal(*talentJSON, &talentDetails)
			icon := getIcon(region, fmt.Sprintf("spell/%d", talentDetails.Spell.ID))
			talent := talent{
				id,
				talentDetails.Spell.ID,
				talentDetails.PlayableClass.ID,
				specID,
				talentDetails.Spell.Name,
				icon,
				tier,
				col}
			talents = append(talents, talent)
		}
	}
	return talents
}

func importPvPTalents() {
	var talentsJSON *[]byte = getStatic(region, "pvp-talent/index")
	var pvpTalents []pvpTalent = parsePvPTalents(talentsJSON)
	logger.Printf("Found %d PvP Talents", len(pvpTalents))
	addPvPTalents(&pvpTalents)
}

func parsePvPTalents(data *[]byte) []pvpTalent {
	type PvPTalentsJSON struct {
		PvPTalents []keyedValue `json:"pvp_talents"`
	}
	var pvpTalentsJSON PvPTalentsJSON
	err := json.Unmarshal(*data, &pvpTalentsJSON)
	if err != nil {
		logger.Printf("%s json parsing failed: %s", errPrefix, err)
		return make([]pvpTalent, 0)
	}
	var pvpTalents []pvpTalent = make([]pvpTalent, 0)
	var ch chan pvpTalent = make(chan pvpTalent, len(pvpTalentsJSON.PvPTalents))
	for _, keyedValue := range pvpTalentsJSON.PvPTalents {
		go getPvPTalent(ch, keyedValue.ID)
	}
	for range pvpTalentsJSON.PvPTalents {
		pvpTalents = append(pvpTalents, <-ch)
	}
	return pvpTalents
}

func getPvPTalent(ch chan pvpTalent, id int) {
	type PvPTalentJSON struct {
		Spell                  keyedValue
		PlayableSpecialization keyedValue `json:"playable_specialization"`
	}
	var pvpTalentJSON *[]byte = getStatic(region, fmt.Sprintf("pvp-talent/%d", id))
	var talentDetails PvPTalentJSON
	json.Unmarshal(*pvpTalentJSON, &talentDetails)
	icon := getIcon(region, fmt.Sprintf("spell/%d", talentDetails.Spell.ID))
	ch <- pvpTalent{
		id,
		talentDetails.Spell.Name,
		talentDetails.Spell.ID,
		talentDetails.PlayableSpecialization.ID,
		icon}
}

func parseAchievements(data *[]byte) []achievement {
	type Achievements struct {
		ID           int
		Name         string
		Achievements []keyedValue
	}

	var achievements Achievements
	err := json.Unmarshal(*data, &achievements)
	var pvpAchievements []achievement = make([]achievement, 0)
	if err != nil {
		logger.Printf("%s json parsing failed: %s", errPrefix, err)
		return pvpAchievements
	}

	var achievementIDs []int = make([]int, 0)
	for _, ac := range achievements.Achievements {
		if strings.Contains(ac.Name, "Season") {
			achievementIDs = append(achievementIDs, ac.ID)
		}
	}
	var ch chan achievement = make(chan achievement, len(achievementIDs))
	for _, id := range achievementIDs {
		go getPvPAchievement(ch, id)
	}
	for range achievementIDs {
		pvpAchievements = append(pvpAchievements, <-ch)
	}

	return pvpAchievements
}

func getPvPAchievement(ch chan achievement, id int) {
	ch <- getAchievement(id)
}

func getAchievement(id int) achievement {
	type PvPAchievementJSON struct {
		ID          int
		Name        string
		Description string
	}
	var pvpAchievementJSON *[]byte = getStatic(region, fmt.Sprintf("achievement/%d", id))
	var pvpAchievementJSONDetails PvPAchievementJSON
	json.Unmarshal(*pvpAchievementJSON, &pvpAchievementJSONDetails)
	return achievement{
		id,
		pvpAchievementJSONDetails.Name,
		pvpAchievementJSONDetails.Description}
}

func importAchievements() {
	var achievementsJSON *[]byte = getStatic(region, fmt.Sprintf("achievement-category/%d", pvpFeatsOfStrengthCategory))
	var achievements []achievement = parseAchievements(achievementsJSON)
	var seasonalCount int = len(achievements)
	logger.Printf("Found %d seasonal achievements", seasonalCount)
	for _, id := range achievementIDs {
		achievement := getAchievement(id)
		achievements = append(achievements, achievement)
	}
	logger.Printf("Found %d non-seasonal achievements", len(achievements)-seasonalCount)
	addAchievements(&achievements)
}
<|endoftext|>


<commit_before>package store_test

import (
	"bytes"
	"labix.org/v2/mgo"
	. "launchpad.net/gocheck"
	"os/exec"
	"time"
)

// ----------------------------------------------------------------------------
// The mgo test suite

type MgoSuite struct {
	Addr    string
	Session *mgo.Session
	output  bytes.Buffer
	server  *exec.Cmd
}

func (s *MgoSuite) SetUpSuite(c *C) {
	mgo.SetDebug(true)
	mgo.SetStats(true)
	dbdir := c.MkDir()
	args := []string{
		"--dbpath", dbdir,
		"--bind_ip", "127.0.0.1",
		"--port", "50017",
		"--nssize", "1",
		"--noprealloc",
		"--smallfiles",
		"--nojournal",
	}
	s.server = exec.Command("mongod", args...)
	s.server.Stdout = &s.output
	s.server.Stderr = &s.output
	err := s.server.Start()
	if err != nil {
		panic(err)
	}
}

func (s *MgoSuite) TearDownSuite(c *C) {
	s.server.Process.Kill()
	s.server.Process.Wait()
}

func (s *MgoSuite) SetUpTest(c *C) {
	err := DropAll("localhost:50017")
	if err != nil {
		panic(err)
	}
	mgo.SetLogger(c)
	mgo.ResetStats()
	s.Addr = "127.0.0.1:50017"
	s.Session, err = mgo.Dial(s.Addr)
	if err != nil {
		panic(err)
	}
}

func (s *MgoSuite) TearDownTest(c *C) {
	s.Session.Close()
	for i := 0; ; i++ {
		stats := mgo.GetStats()
		if stats.SocketsInUse == 0 && stats.SocketsAlive == 0 {
			break
		}
		if i == 20 {
			c.Fatal("Test left sockets in a dirty state")
		}
		c.Logf("Waiting for sockets to die: %d in use, %d alive", stats.SocketsInUse, stats.SocketsAlive)
		time.Sleep(500 * time.Millisecond)
	}
}

func DropAll(mongourl string) (err error) {
	session, err := mgo.Dial(mongourl)
	if err != nil {
		return err
	}
	defer session.Close()

	names, err := session.DatabaseNames()
	if err != nil {
		return err
	}
	for _, name := range names {
		switch name {
		case "admin", "local", "config":
		default:
			err = session.DB(name).DropDatabase()
			if err != nil {
				return err
			}
		}
	}
	return nil
}
<commit_msg>say not to panic, say yes to assert<commit_after>package store_test

import (
	"bytes"
	"labix.org/v2/mgo"
	. "launchpad.net/gocheck"
	"os/exec"
	"time"
)

// ----------------------------------------------------------------------------
// The mgo test suite

type MgoSuite struct {
	Addr    string
	Session *mgo.Session
	output  bytes.Buffer
	server  *exec.Cmd
}

func (s *MgoSuite) SetUpSuite(c *C) {
	mgo.SetDebug(true)
	mgo.SetStats(true)
	dbdir := c.MkDir()
	args := []string{
		"--dbpath", dbdir,
		"--bind_ip", "127.0.0.1",
		"--port", "50017",
		"--nssize", "1",
		"--noprealloc",
		"--smallfiles",
		"--nojournal",
	}
	s.server = exec.Command("mongod", args...)
	s.server.Stdout = &s.output
	s.server.Stderr = &s.output
	err := s.server.Start()
	c.Assert(err, IsNil)
}

func (s *MgoSuite) TearDownSuite(c *C) {
	s.server.Process.Kill()
	s.server.Process.Wait()
}

func (s *MgoSuite) SetUpTest(c *C) {
	err := DropAll("localhost:50017")
	c.Assert(err, IsNil)
	mgo.SetLogger(c)
	mgo.ResetStats()
	s.Addr = "127.0.0.1:50017"
	s.Session, err = mgo.Dial(s.Addr)
	c.Assert(err, IsNil)
}

func (s *MgoSuite) TearDownTest(c *C) {
	if s.Session != nil {
		s.Session.Close()
	}
	for i := 0; ; i++ {
		stats := mgo.GetStats()
		if stats.SocketsInUse == 0 && stats.SocketsAlive == 0 {
			break
		}
		if i == 20 {
			c.Fatal("Test left sockets in a dirty state")
		}
		c.Logf("Waiting for sockets to die: %d in use, %d alive", stats.SocketsInUse, stats.SocketsAlive)
		time.Sleep(500 * time.Millisecond)
	}
}

func DropAll(mongourl string) (err error) {
	session, err := mgo.Dial(mongourl)
	if err != nil {
		return err
	}
	defer session.Close()

	names, err := session.DatabaseNames()
	if err != nil {
		return err
	}
	for _, name := range names {
		switch name {
		case "admin", "local", "config":
		default:
			err = session.DB(name).DropDatabase()
			if err != nil {
				return err
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// +build !windows

package taskrunner

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"syscall"
	"testing"
	"time"

	"github.com/hashicorp/nomad/client/allocrunner/interfaces"
	"github.com/hashicorp/nomad/helper/testlog"
	"github.com/hashicorp/nomad/nomad/mock"
	"github.com/hashicorp/nomad/testutil"
	"github.com/stretchr/testify/require"
)

// TestTaskRunner_LogmonHook_StartCrashStop simulates logmon crashing while the
// Nomad client is restarting and asserts failing to reattach to logmon causes
// nomad to spawn a new logmon.
func TestTaskRunner_LogmonHook_StartCrashStop(t *testing.T) {
	t.Parallel()

	alloc := mock.BatchAlloc()
	task := alloc.Job.TaskGroups[0].Tasks[0]

	dir, err := ioutil.TempDir("", "nomadtest")
	require.NoError(t, err)
	defer func() {
		require.NoError(t, os.RemoveAll(dir))
	}()

	hookConf := newLogMonHookConfig(task.Name, dir)
	hook := newLogMonHook(hookConf, testlog.HCLogger(t))

	req := interfaces.TaskPrestartRequest{
		Task: task,
	}
	resp := interfaces.TaskPrestartResponse{}

	// First start
	require.NoError(t, hook.Prestart(context.Background(), &req, &resp))
	defer hook.Stop(context.Background(), nil, nil)

	origState := resp.State
	origHookData := resp.State[logmonReattachKey]
	require.NotEmpty(t, origHookData)

	// Pluck PID out of reattach synthesize a crash
	reattach := struct {
		Pid int
	}{}
	require.NoError(t, json.Unmarshal([]byte(origHookData), &reattach))
	pid := reattach.Pid
	require.NotZero(t, pid)

	proc, _ := os.FindProcess(pid)

	// Assert logmon is running
	require.NoError(t, proc.Signal(syscall.Signal(0)))

	// Kill it
	require.NoError(t, proc.Signal(os.Kill))

	// Since signals are asynchronous wait for the process to die
	testutil.WaitForResult(func() (bool, error) {
		err := proc.Signal(syscall.Signal(0))
		return err != nil, fmt.Errorf("pid %d still running", pid)
	}, func(err error) {
		require.NoError(t, err)
	})

	// Running prestart again should return a recoverable error with no
	// reattach config to cause the task to be restarted with a new logmon.
	req.PreviousState = map[string]string{
		logmonReattachKey: origHookData,
	}
	resp = interfaces.TaskPrestartResponse{}
	err = hook.Prestart(context.Background(), &req, &resp)
	require.NoError(t, err)
	require.NotEqual(t, origState, resp.State)

	// Running stop should shutdown logmon
	require.NoError(t, hook.Stop(context.Background(), nil, nil))
}

// TestTaskRunner_LogmonHook_ShutdownMidStart simulates logmon crashing while the
// Nomad client is calling Start() and asserts that we recover and spawn a new logmon.
func TestTaskRunner_LogmonHook_ShutdownMidStart(t *testing.T) {
	t.Parallel()

	alloc := mock.BatchAlloc()
	task := alloc.Job.TaskGroups[0].Tasks[0]

	dir, err := ioutil.TempDir("", "nomadtest")
	require.NoError(t, err)
	defer func() {
		require.NoError(t, os.RemoveAll(dir))
	}()

	hookConf := newLogMonHookConfig(task.Name, dir)
	hook := newLogMonHook(hookConf, testlog.HCLogger(t))

	req := interfaces.TaskPrestartRequest{
		Task: task,
	}
	resp := interfaces.TaskPrestartResponse{}

	// First start
	require.NoError(t, hook.Prestart(context.Background(), &req, &resp))
	defer hook.Stop(context.Background(), nil, nil)

	origState := resp.State
	origHookData := resp.State[logmonReattachKey]
	require.NotEmpty(t, origHookData)

	// Pluck PID out of reattach synthesize a crash
	reattach := struct {
		Pid int
	}{}
	require.NoError(t, json.Unmarshal([]byte(origHookData), &reattach))
	pid := reattach.Pid
	require.NotZero(t, pid)

	proc, _ := os.FindProcess(pid)

	// Assert logmon is running
	require.NoError(t, proc.Signal(syscall.Signal(0)))

	// SIGSTOP would freeze process without it being considered
	// exited; so this causes process to be non-exited at beginning of call
	// then we kill process while Start call is running
	require.NoError(t, proc.Signal(syscall.SIGSTOP))
	// sleep for the signal to take effect
	time.Sleep(1 * time.Second)

	go func() {
		time.Sleep(2 * time.Second)

		proc.Signal(syscall.SIGCONT)
		proc.Signal(os.Kill)
	}()

	req.PreviousState = map[string]string{
		logmonReattachKey: origHookData,
	}

	initLogmon, initClient := hook.logmon, hook.logmonPluginClient

	resp = interfaces.TaskPrestartResponse{}
	err = hook.Prestart(context.Background(), &req, &resp)
	require.NoError(t, err)
	require.NotEqual(t, origState, resp.State)

	// assert that we got a new client and logmon
	require.True(t, initLogmon != hook.logmon)
	require.True(t, initClient != hook.logmonPluginClient)
}
<commit_msg>try checking process status<commit_after>// +build !windows

package taskrunner

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"syscall"
	"testing"
	"time"

	"github.com/hashicorp/nomad/client/allocrunner/interfaces"
	"github.com/hashicorp/nomad/helper/testlog"
	"github.com/hashicorp/nomad/nomad/mock"
	"github.com/hashicorp/nomad/testutil"
	"github.com/shirou/gopsutil/process"
	"github.com/stretchr/testify/require"
)

// TestTaskRunner_LogmonHook_StartCrashStop simulates logmon crashing while the
// Nomad client is restarting and asserts failing to reattach to logmon causes
// nomad to spawn a new logmon.
func TestTaskRunner_LogmonHook_StartCrashStop(t *testing.T) {
	t.Parallel()

	alloc := mock.BatchAlloc()
	task := alloc.Job.TaskGroups[0].Tasks[0]

	dir, err := ioutil.TempDir("", "nomadtest")
	require.NoError(t, err)
	defer func() {
		require.NoError(t, os.RemoveAll(dir))
	}()

	hookConf := newLogMonHookConfig(task.Name, dir)
	hook := newLogMonHook(hookConf, testlog.HCLogger(t))

	req := interfaces.TaskPrestartRequest{
		Task: task,
	}
	resp := interfaces.TaskPrestartResponse{}

	// First start
	require.NoError(t, hook.Prestart(context.Background(), &req, &resp))
	defer hook.Stop(context.Background(), nil, nil)

	origState := resp.State
	origHookData := resp.State[logmonReattachKey]
	require.NotEmpty(t, origHookData)

	// Pluck PID out of reattach synthesize a crash
	reattach := struct {
		Pid int
	}{}
	require.NoError(t, json.Unmarshal([]byte(origHookData), &reattach))
	pid := reattach.Pid
	require.NotZero(t, pid)

	proc, _ := os.FindProcess(pid)

	// Assert logmon is running
	require.NoError(t, proc.Signal(syscall.Signal(0)))

	// Kill it
	require.NoError(t, proc.Signal(os.Kill))

	// Since signals are asynchronous wait for the process to die
	testutil.WaitForResult(func() (bool, error) {
		err := proc.Signal(syscall.Signal(0))
		return err != nil, fmt.Errorf("pid %d still running", pid)
	}, func(err error) {
		require.NoError(t, err)
	})

	// Running prestart again should return a recoverable error with no
	// reattach config to cause the task to be restarted with a new logmon.
	req.PreviousState = map[string]string{
		logmonReattachKey: origHookData,
	}
	resp = interfaces.TaskPrestartResponse{}
	err = hook.Prestart(context.Background(), &req, &resp)
	require.NoError(t, err)
	require.NotEqual(t, origState, resp.State)

	// Running stop should shutdown logmon
	require.NoError(t, hook.Stop(context.Background(), nil, nil))
}

// TestTaskRunner_LogmonHook_ShutdownMidStart simulates logmon crashing while the
// Nomad client is calling Start() and asserts that we recover and spawn a new logmon.
func TestTaskRunner_LogmonHook_ShutdownMidStart(t *testing.T) {
	t.Parallel()

	alloc := mock.BatchAlloc()
	task := alloc.Job.TaskGroups[0].Tasks[0]

	dir, err := ioutil.TempDir("", "nomadtest")
	require.NoError(t, err)
	defer func() {
		require.NoError(t, os.RemoveAll(dir))
	}()

	hookConf := newLogMonHookConfig(task.Name, dir)
	hook := newLogMonHook(hookConf, testlog.HCLogger(t))

	req := interfaces.TaskPrestartRequest{
		Task: task,
	}
	resp := interfaces.TaskPrestartResponse{}

	// First start
	require.NoError(t, hook.Prestart(context.Background(), &req, &resp))
	defer hook.Stop(context.Background(), nil, nil)

	origState := resp.State
	origHookData := resp.State[logmonReattachKey]
	require.NotEmpty(t, origHookData)

	// Pluck PID out of reattach synthesize a crash
	reattach := struct {
		Pid int
	}{}
	require.NoError(t, json.Unmarshal([]byte(origHookData), &reattach))
	pid := reattach.Pid
	require.NotZero(t, pid)

	proc, err := process.NewProcess(int32(pid))
	require.NoError(t, err)

	// Assert logmon is running
	require.NoError(t, proc.SendSignal(syscall.Signal(0)))

	// SIGSTOP would freeze process without it being considered
	// exited; so this causes process to be non-exited at beginning of call
	// then we kill process while Start call is running
	require.NoError(t, proc.SendSignal(syscall.SIGSTOP))
	testutil.WaitForResult(func() (bool, error) {
		status, err := proc.Status()
		if err != nil {
			return false, err
		}

		if status != "T" && status != "T+" {
			return false, fmt.Errorf("process is not asleep yet: %v", status)
		}

		return true, nil
	}, func(err error) {
		require.NoError(t, err)
	})

	go func() {
		time.Sleep(2 * time.Second)

		proc.SendSignal(syscall.SIGCONT)
		proc.Kill()
	}()

	req.PreviousState = map[string]string{
		logmonReattachKey: origHookData,
	}

	initLogmon, initClient := hook.logmon, hook.logmonPluginClient

	resp = interfaces.TaskPrestartResponse{}
	err = hook.Prestart(context.Background(), &req, &resp)
	require.NoError(t, err)
	require.NotEqual(t, origState, resp.State)

	// assert that we got a new client and logmon
	require.True(t, initLogmon != hook.logmon)
	require.True(t, initClient != hook.logmonPluginClient)
}
<|endoftext|>


<commit_before>package aws

import (
	"reflect"
	"testing"

	"github.com/hashicorp/terraform/flatmap"
	"github.com/mitchellh/goamz/ec2"
	"github.com/mitchellh/goamz/elb"
)

// Returns test configuration
func testConf() map[string]string {
	return map[string]string{
		"listener.#":                   "1",
		"listener.0.lb_port":           "80",
		"listener.0.lb_protocol":       "http",
		"listener.0.instance_port":     "8000",
		"listener.0.instance_protocol": "http",
		"availability_zones.#":         "2",
		"availability_zones.0":         "us-east-1a",
		"availability_zones.1":         "us-east-1b",
		"ingress.#":                    "1",
		"ingress.0.protocol":           "icmp",
		"ingress.0.from_port":          "1",
		"ingress.0.to_port":            "-1",
		"ingress.0.cidr_blocks.#":      "1",
		"ingress.0.cidr_blocks.0":      "0.0.0.0/0",
		"ingress.0.security_groups.#":  "2",
		"ingress.0.security_groups.0":  "sg-11111",
		"ingress.0.security_groups.1":  "foo/sg-22222",
	}
}

func Test_expandIPPerms(t *testing.T) {
	expanded := []interface{}{
		map[string]interface{}{
			"protocol":    "icmp",
			"from_port":   1,
			"to_port":     -1,
			"cidr_blocks": []interface{}{"0.0.0.0/0"},
			"security_groups": []interface{}{
				"sg-11111",
				"foo/sg-22222",
			},
		},
		map[string]interface{}{
			"protocol":  "icmp",
			"from_port": 1,
			"to_port":   -1,
			"self":      true,
		},
	}
	perms := expandIPPerms("foo", expanded)

	expected := []ec2.IPPerm{
		ec2.IPPerm{
			Protocol:  "icmp",
			FromPort:  1,
			ToPort:    -1,
			SourceIPs: []string{"0.0.0.0/0"},
			SourceGroups: []ec2.UserSecurityGroup{
				ec2.UserSecurityGroup{
					Id: "sg-11111",
				},
				ec2.UserSecurityGroup{
					OwnerId: "foo",
					Id:      "sg-22222",
				},
			},
		},
		ec2.IPPerm{
			Protocol: "icmp",
			FromPort: 1,
			ToPort:   -1,
			SourceGroups: []ec2.UserSecurityGroup{
				ec2.UserSecurityGroup{
					Id: "foo",
				},
			},
		},
	}

	if !reflect.DeepEqual(perms, expected) {
		t.Fatalf(
			"Got:\n\n%#v\n\nExpected:\n\n%#v\n",
			perms[0],
			expected)
	}

}

func Test_flattenIPPerms(t *testing.T) {
	cases := []struct {
		Input  []ec2.IPPerm
		Output []map[string]interface{}
	}{
		{
			Input: []ec2.IPPerm{
				ec2.IPPerm{
					Protocol:  "icmp",
					FromPort:  1,
					ToPort:    -1,
					SourceIPs: []string{"0.0.0.0/0"},
					SourceGroups: []ec2.UserSecurityGroup{
						ec2.UserSecurityGroup{
							Id: "sg-11111",
						},
					},
				},
			},

			Output: []map[string]interface{}{
				map[string]interface{}{
					"protocol":        "icmp",
					"from_port":       1,
					"to_port":         -1,
					"cidr_blocks":     []string{"0.0.0.0/0"},
					"security_groups": []string{"sg-11111"},
				},
			},
		},

		{
			Input: []ec2.IPPerm{
				ec2.IPPerm{
					Protocol:     "icmp",
					FromPort:     1,
					ToPort:       -1,
					SourceIPs:    []string{"0.0.0.0/0"},
					SourceGroups: nil,
				},
			},

			Output: []map[string]interface{}{
				map[string]interface{}{
					"protocol":    "icmp",
					"from_port":   1,
					"to_port":     -1,
					"cidr_blocks": []string{"0.0.0.0/0"},
				},
			},
		},
		{
			Input: []ec2.IPPerm{
				ec2.IPPerm{
					Protocol:  "icmp",
					FromPort:  1,
					ToPort:    -1,
					SourceIPs: nil,
				},
			},

			Output: []map[string]interface{}{
				map[string]interface{}{
					"protocol":  "icmp",
					"from_port": 1,
					"to_port":   -1,
				},
			},
		},
	}

	for _, tc := range cases {
		output := flattenIPPerms(tc.Input)
		if !reflect.DeepEqual(output, tc.Output) {
			t.Fatalf("Input:\n\n%#v\n\nOutput:\n\n%#v", tc.Input, output)
		}
	}
}

func Test_expandListeners(t *testing.T) {
	expanded := flatmap.Expand(testConf(), "listener").([]interface{})
	listeners, err := expandListeners(expanded)
	if err != nil {
		t.Fatalf("bad: %#v", err)
	}

	expected := elb.Listener{
		InstancePort:     8000,
		LoadBalancerPort: 80,
		InstanceProtocol: "http",
		Protocol:         "http",
	}

	if !reflect.DeepEqual(listeners[0], expected) {
		t.Fatalf(
			"Got:\n\n%#v\n\nExpected:\n\n%#v\n",
			listeners[0],
			expected)
	}

}

func Test_flattenHealthCheck(t *testing.T) {
	cases := []struct {
		Input  elb.HealthCheck
		Output []map[string]interface{}
	}{
		{
			Input: elb.HealthCheck{
				UnhealthyThreshold: 10,
				HealthyThreshold:   10,
				Target:             "HTTP:80/",
				Timeout:            30,
				Interval:           30,
			},
			Output: []map[string]interface{}{
				map[string]interface{}{
					"unhealthy_threshold": 10,
					"healthy_threshold":   10,
					"target":              "HTTP:80/",
					"timeout":             30,
					"interval":            30,
				},
			},
		},
	}

	for _, tc := range cases {
		output := flattenHealthCheck(tc.Input)
		if !reflect.DeepEqual(output, tc.Output) {
			t.Fatalf("Got:\n\n%#v\n\nExpected:\n\n%#v", output, tc.Output)
		}
	}
}

func Test_expandStringList(t *testing.T) {
	expanded := flatmap.Expand(testConf(), "availability_zones").([]interface{})
	stringList := expandStringList(expanded)
	expected := []string{
		"us-east-1a",
		"us-east-1b",
	}

	if !reflect.DeepEqual(stringList, expected) {
		t.Fatalf(
			"Got:\n\n%#v\n\nExpected:\n\n%#v\n",
			stringList,
			expected)
	}

}
<commit_msg>providers/aws: fix failing test<commit_after>package aws

import (
	"reflect"
	"testing"

	"github.com/hashicorp/terraform/flatmap"
	"github.com/mitchellh/goamz/ec2"
	"github.com/mitchellh/goamz/elb"
)

// Returns test configuration
func testConf() map[string]string {
	return map[string]string{
		"listener.#":                   "1",
		"listener.0.lb_port":           "80",
		"listener.0.lb_protocol":       "http",
		"listener.0.instance_port":     "8000",
		"listener.0.instance_protocol": "http",
		"availability_zones.#":         "2",
		"availability_zones.0":         "us-east-1a",
		"availability_zones.1":         "us-east-1b",
		"ingress.#":                    "1",
		"ingress.0.protocol":           "icmp",
		"ingress.0.from_port":          "1",
		"ingress.0.to_port":            "-1",
		"ingress.0.cidr_blocks.#":      "1",
		"ingress.0.cidr_blocks.0":      "0.0.0.0/0",
		"ingress.0.security_groups.#":  "2",
		"ingress.0.security_groups.0":  "sg-11111",
		"ingress.0.security_groups.1":  "foo/sg-22222",
	}
}

func Test_expandIPPerms(t *testing.T) {
	expanded := []interface{}{
		map[string]interface{}{
			"protocol":    "icmp",
			"from_port":   1,
			"to_port":     -1,
			"cidr_blocks": []interface{}{"0.0.0.0/0"},
			"security_groups": []interface{}{
				"sg-11111",
				"foo/sg-22222",
			},
		},
		map[string]interface{}{
			"protocol":  "icmp",
			"from_port": 1,
			"to_port":   -1,
			"self":      true,
		},
	}
	perms := expandIPPerms("foo", expanded)

	expected := []ec2.IPPerm{
		ec2.IPPerm{
			Protocol:  "icmp",
			FromPort:  1,
			ToPort:    -1,
			SourceIPs: []string{"0.0.0.0/0"},
			SourceGroups: []ec2.UserSecurityGroup{
				ec2.UserSecurityGroup{
					Id: "sg-11111",
				},
				ec2.UserSecurityGroup{
					OwnerId: "foo",
					Id:      "sg-22222",
				},
			},
		},
		ec2.IPPerm{
			Protocol: "icmp",
			FromPort: 1,
			ToPort:   -1,
			SourceGroups: []ec2.UserSecurityGroup{
				ec2.UserSecurityGroup{
					Id: "foo",
				},
			},
		},
	}

	if !reflect.DeepEqual(perms, expected) {
		t.Fatalf(
			"Got:\n\n%#v\n\nExpected:\n\n%#v\n",
			perms[0],
			expected)
	}

}

func Test_flattenIPPerms(t *testing.T) {
	cases := []struct {
		Input  []ec2.IPPerm
		Output []map[string]interface{}
	}{
		{
			Input: []ec2.IPPerm{
				ec2.IPPerm{
					Protocol:  "icmp",
					FromPort:  1,
					ToPort:    -1,
					SourceIPs: []string{"0.0.0.0/0"},
					SourceGroups: []ec2.UserSecurityGroup{
						ec2.UserSecurityGroup{
							Id: "sg-11111",
						},
					},
				},
			},

			Output: []map[string]interface{}{
				map[string]interface{}{
					"protocol":        "icmp",
					"from_port":       1,
					"to_port":         -1,
					"cidr_blocks":     []string{"0.0.0.0/0"},
					"security_groups": []string{"sg-11111"},
				},
			},
		},

		{
			Input: []ec2.IPPerm{
				ec2.IPPerm{
					Protocol:     "icmp",
					FromPort:     1,
					ToPort:       -1,
					SourceIPs:    []string{"0.0.0.0/0"},
					SourceGroups: nil,
				},
			},

			Output: []map[string]interface{}{
				map[string]interface{}{
					"protocol":    "icmp",
					"from_port":   1,
					"to_port":     -1,
					"cidr_blocks": []string{"0.0.0.0/0"},
				},
			},
		},
		{
			Input: []ec2.IPPerm{
				ec2.IPPerm{
					Protocol:  "icmp",
					FromPort:  1,
					ToPort:    -1,
					SourceIPs: nil,
				},
			},

			Output: []map[string]interface{}{
				map[string]interface{}{
					"protocol":  "icmp",
					"from_port": 1,
					"to_port":   -1,
				},
			},
		},
	}

	for _, tc := range cases {
		output := flattenIPPerms(tc.Input)
		if !reflect.DeepEqual(output, tc.Output) {
			t.Fatalf("Input:\n\n%#v\n\nOutput:\n\n%#v", tc.Input, output)
		}
	}
}

func Test_expandListeners(t *testing.T) {
	expanded := []interface{}{
		map[string]interface{}{
			"instance_port": 8000,
			"lb_port": 80,
			"instance_protocol": "http",
			"lb_protocol": "http",
		},
	}
	listeners, err := expandListeners(expanded)
	if err != nil {
		t.Fatalf("bad: %#v", err)
	}

	expected := elb.Listener{
		InstancePort:     8000,
		LoadBalancerPort: 80,
		InstanceProtocol: "http",
		Protocol:         "http",
	}

	if !reflect.DeepEqual(listeners[0], expected) {
		t.Fatalf(
			"Got:\n\n%#v\n\nExpected:\n\n%#v\n",
			listeners[0],
			expected)
	}

}

func Test_flattenHealthCheck(t *testing.T) {
	cases := []struct {
		Input  elb.HealthCheck
		Output []map[string]interface{}
	}{
		{
			Input: elb.HealthCheck{
				UnhealthyThreshold: 10,
				HealthyThreshold:   10,
				Target:             "HTTP:80/",
				Timeout:            30,
				Interval:           30,
			},
			Output: []map[string]interface{}{
				map[string]interface{}{
					"unhealthy_threshold": 10,
					"healthy_threshold":   10,
					"target":              "HTTP:80/",
					"timeout":             30,
					"interval":            30,
				},
			},
		},
	}

	for _, tc := range cases {
		output := flattenHealthCheck(tc.Input)
		if !reflect.DeepEqual(output, tc.Output) {
			t.Fatalf("Got:\n\n%#v\n\nExpected:\n\n%#v", output, tc.Output)
		}
	}
}

func Test_expandStringList(t *testing.T) {
	expanded := flatmap.Expand(testConf(), "availability_zones").([]interface{})
	stringList := expandStringList(expanded)
	expected := []string{
		"us-east-1a",
		"us-east-1b",
	}

	if !reflect.DeepEqual(stringList, expected) {
		t.Fatalf(
			"Got:\n\n%#v\n\nExpected:\n\n%#v\n",
			stringList,
			expected)
	}

}
<|endoftext|>


<commit_before><commit_msg>Initial commit<commit_after><|endoftext|>


<commit_before>// Copyright (C) 2015 Foursquare Labs Inc.

package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/foursquare/fsgo/net/discovery"
	"github.com/foursquare/fsgo/net/httpthrift"
	"github.com/foursquare/fsgo/report"
	"github.com/foursquare/quiver/gen"
)

type Load struct {
	collection string
	sample     *int64
	keys       [][]byte

	server func() string

	diffing bool
	diff    func() string

	work chan bool

	rtt     string
	diffRtt string

	queueSize report.Guage
	dropped   report.Meter

	mixPrefix, mixIterator, mixMulti int32

	keysPerReqMin, keysPerReqMax, keysPerReqSpread float64

	// for atomic keyset swaps in setKeys.
	sync.RWMutex
}

func GetQuiverClient(url func() string) *gen.HFileServiceClient {
	recv, send := httpthrift.NewDynamicClientProts(url, false)
	return gen.NewHFileServiceClientProtocol(nil, recv, send)
}

// Feeds the work channel at requested qps.
func (l *Load) generator(qps int) {
	pause := time.Duration(time.Second.Nanoseconds() / int64(qps))

	for _ = range time.Tick(pause) {
		l.queueSize.Update(int64(len(l.work)))
		select {
		case l.work <- true:
		default:
			l.dropped.Mark(1)
		}
	}
}

// given a string like testing=fsan44:20202, return (http://fsan44:20202/rpc/HFileService, testing).
func hfileUrlAndName(s string) (func() string, string, discovery.Conn) {
	name := strings.NewReplacer("http://", "", ".", "_", ":", "_", "/", "_").Replace(s)

	if parts := strings.Split(s, "="); len(parts) > 1 {
		s = parts[1]
		name = parts[0]
	}

	if strings.HasPrefix(s, "zk:") {
		if len(zk) < 1 {
			log.Fatal("must specify --zk to use discovery")
		}
		s := s[len("zk:"):]
		shardAndPath := strings.Split(s, "@")
		if len(shardAndPath) != 2 {
			log.Fatal("format: zk:$SHARD@$PATH")
		}
		shard, path := shardAndPath[0], shardAndPath[1]

		disco, conn, err := discovery.NewServiceDiscoveryAndConn(zk, path)
		if err != nil {
			log.Fatal(err)
		} else {
			disco.Watch()
		}

		log.Printf("discovering instances of %s at %s\n", shard, path)
		provider := disco.Provider(shard)
		f := func() string {
			i, err := provider.GetInstance()
			if err != nil {
				log.Println("error discovering instance:", err)
			} else if i == nil {
				log.Println("no instances found")
			} else {
				return fmt.Sprintf("http://%s/rpc/HFileService", i.Spec())
			}
			return ""
		}

		return f, name, conn
	}

	if !strings.Contains(s, "/") {
		fmt.Printf("'%s' doens't appear to specify a path. Appending /rpc/HFileService...\n", s)
		s = s + "/rpc/HFileService"
	}

	if !strings.HasPrefix(s, "http") {
		s = "http://" + s
	}
	return func() string { return s }, name, nil
}

var zk = ""

func main() {
	orig := flag.String("server", "localhost:9999", "URL of hfile server")
	rawDiff := flag.String("diff", "", "URL of second hfile server to compare")
	collection := flag.String("collection", "", "name of collection")
	graphite := report.Flag()
	workers := flag.Int("workers", 8, "worker pool size")
	flag.StringVar(&zk, "zk", "", "zookeeper host")

	qps := flag.Int("qps", 100, "qps to attempt")
	maxQps := flag.Bool("max-qps", false, "Each workers sends a query as soon as the previous response is processed")

	minKeys := flag.Int("keys-min", 10, "min number of keys per request")
	maxKeys := flag.Int("keys-max", 5000, "max number of keys per request")
	spreadKeys := flag.Float64("keys-spread", 10, "coefficient for exponential distribution of key count")
	printSpread := flag.Bool("print-spread", false, "print distribution of key count (over 100000 requests)")

	sample := flag.Int64("sampleSize", 1000, "number of random keys to use")

	mixPrefix := flag.Int("mix-prefix", 10, "getPrefixes traffic mix % (un-alloc is getSingle)")
	mixIter := flag.Int("mix-iterator", 10, "getPrefixes traffic mix % (un-alloc is getSingle)")
	mixMulti := flag.Int("mix-multi", 20, "getPrefixes traffic mix % (un-alloc is getSingle)")

	flag.Parse()

	r := report.NewRecorder().
		MaybeReportTo(graphite).
		SetAsDefault()

	rttName := "rtt"
	server, name, conn := hfileUrlAndName(*orig)
	if conn != nil {
		defer conn.Close()
	}

	if collection == nil || len(*collection) < 1 {
		fmt.Println("--collection is required")
		c := GetQuiverClient(server)
		r := &gen.InfoRequest{}

		if resp, err := c.GetInfo(r); err != nil {
			fmt.Println("tried to fetch possible collections but got an error:", err)
		} else {
			fmt.Println("possible --collection options:")
			for _, v := range resp {
				fmt.Println("\t", v.GetName())
			}
		}
		os.Exit(1)
	}

	diffing := false
	diffRtt := ""
	diffName := ""
	diff := func() string { return "" }

	if rawDiff != nil && len(*rawDiff) > 0 {
		diffing = true
		diff, diffName, conn = hfileUrlAndName(*rawDiff)
		if conn != nil {
			defer conn.Close()
		}
		diffRtt = "rtt." + diffName
		rttName = "rtt." + name
	}

	l := &Load{
		collection:       *collection,
		sample:           sample,
		server:           server,
		diffing:          diffing,
		diff:             diff,
		work:             make(chan bool, (*workers)),
		dropped:          r.GetMeter("dropped"),
		queueSize:        r.GetGuage("queue"),
		rtt:              rttName,
		diffRtt:          diffRtt,
		mixPrefix:        int32(*mixPrefix),
		mixIterator:      int32(*mixPrefix + *mixIter),
		mixMulti:         int32(*mixPrefix + *mixIter + *mixMulti),
		keysPerReqMin:    float64(*minKeys),
		keysPerReqMax:    float64(*maxKeys),
		keysPerReqSpread: *spreadKeys,
	}

	if *printSpread {
		fmt.Println("Key count distribtion:")
		l.printKeySpread()
	}

	if err := l.setKeys(); err != nil {
		fmt.Println("Failed to fetch testing keys:", err)
		os.Exit(1)
	}

	if *maxQps {
		fmt.Printf("Sending max qps to %s (%s), drawing from %d random keys...\n", name, server(), len(l.keys))
	} else {
		fmt.Printf("Sending %dqps to %s (%s), drawing from %d random keys...\n", *qps, name, server(), len(l.keys))
		go l.generator(*qps)
	}
	if l.diffing {
		fmt.Printf("Diffing against %s (%s)\n", diffName, l.diff())
	}

	l.startWorkers(*workers, *maxQps)

	reader := bufio.NewReader(os.Stdin)

	for {
		fmt.Print("Press enter for stats summary.\n")
		reader.ReadString('\n')
		l.PrintSummary()
	}
}
<commit_msg>use round robin instead of random<commit_after>// Copyright (C) 2015 Foursquare Labs Inc.

package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/foursquare/fsgo/net/discovery"
	"github.com/foursquare/fsgo/net/httpthrift"
	"github.com/foursquare/fsgo/report"
	"github.com/foursquare/quiver/gen"
)

type Load struct {
	collection string
	sample     *int64
	keys       [][]byte

	server func() string

	diffing bool
	diff    func() string

	work chan bool

	rtt     string
	diffRtt string

	queueSize report.Guage
	dropped   report.Meter

	mixPrefix, mixIterator, mixMulti int32

	keysPerReqMin, keysPerReqMax, keysPerReqSpread float64

	// for atomic keyset swaps in setKeys.
	sync.RWMutex
}

func GetQuiverClient(url func() string) *gen.HFileServiceClient {
	recv, send := httpthrift.NewDynamicClientProts(url, false)
	return gen.NewHFileServiceClientProtocol(nil, recv, send)
}

// Feeds the work channel at requested qps.
func (l *Load) generator(qps int) {
	pause := time.Duration(time.Second.Nanoseconds() / int64(qps))

	for _ = range time.Tick(pause) {
		l.queueSize.Update(int64(len(l.work)))
		select {
		case l.work <- true:
		default:
			l.dropped.Mark(1)
		}
	}
}

// given a string like testing=fsan44:20202, return (http://fsan44:20202/rpc/HFileService, testing).
func hfileUrlAndName(s string) (func() string, string, discovery.Conn) {
	name := strings.NewReplacer("http://", "", ".", "_", ":", "_", "/", "_").Replace(s)

	if parts := strings.Split(s, "="); len(parts) > 1 {
		s = parts[1]
		name = parts[0]
	}

	if strings.HasPrefix(s, "zk:") {
		if len(zk) < 1 {
			log.Fatal("must specify --zk to use discovery")
		}
		s := s[len("zk:"):]
		shardAndPath := strings.Split(s, "@")
		if len(shardAndPath) != 2 {
			log.Fatal("format: zk:$SHARD@$PATH")
		}
		shard, path := shardAndPath[0], shardAndPath[1]

		disco, conn, err := discovery.NewServiceDiscoveryAndConn(zk, path)
		if err != nil {
			log.Fatal(err)
		} else {
			disco.Watch()
		}

		log.Printf("discovering instances of %s at %s\n", shard, path)
		provider := disco.ProviderWithStrategy(shard, discovery.NewRoundRobinProvider())
		f := func() string {
			i, err := provider.GetInstance()
			if err != nil {
				log.Println("error discovering instance:", err)
			} else if i == nil {
				log.Println("no instances found")
			} else {
				return fmt.Sprintf("http://%s/rpc/HFileService", i.Spec())
			}
			return ""
		}

		return f, name, conn
	}

	if !strings.Contains(s, "/") {
		fmt.Printf("'%s' doens't appear to specify a path. Appending /rpc/HFileService...\n", s)
		s = s + "/rpc/HFileService"
	}

	if !strings.HasPrefix(s, "http") {
		s = "http://" + s
	}
	return func() string { return s }, name, nil
}

var zk = ""

func main() {
	orig := flag.String("server", "localhost:9999", "URL of hfile server")
	rawDiff := flag.String("diff", "", "URL of second hfile server to compare")
	collection := flag.String("collection", "", "name of collection")
	graphite := report.Flag()
	workers := flag.Int("workers", 8, "worker pool size")
	flag.StringVar(&zk, "zk", "", "zookeeper host")

	qps := flag.Int("qps", 100, "qps to attempt")
	maxQps := flag.Bool("max-qps", false, "Each workers sends a query as soon as the previous response is processed")

	minKeys := flag.Int("keys-min", 10, "min number of keys per request")
	maxKeys := flag.Int("keys-max", 5000, "max number of keys per request")
	spreadKeys := flag.Float64("keys-spread", 10, "coefficient for exponential distribution of key count")
	printSpread := flag.Bool("print-spread", false, "print distribution of key count (over 100000 requests)")

	sample := flag.Int64("sampleSize", 1000, "number of random keys to use")

	mixPrefix := flag.Int("mix-prefix", 10, "getPrefixes traffic mix % (un-alloc is getSingle)")
	mixIter := flag.Int("mix-iterator", 10, "getPrefixes traffic mix % (un-alloc is getSingle)")
	mixMulti := flag.Int("mix-multi", 20, "getPrefixes traffic mix % (un-alloc is getSingle)")

	flag.Parse()

	r := report.NewRecorder().
		MaybeReportTo(graphite).
		SetAsDefault()

	rttName := "rtt"
	server, name, conn := hfileUrlAndName(*orig)
	if conn != nil {
		defer conn.Close()
	}

	if collection == nil || len(*collection) < 1 {
		fmt.Println("--collection is required")
		c := GetQuiverClient(server)
		r := &gen.InfoRequest{}

		if resp, err := c.GetInfo(r); err != nil {
			fmt.Println("tried to fetch possible collections but got an error:", err)
		} else {
			fmt.Println("possible --collection options:")
			for _, v := range resp {
				fmt.Println("\t", v.GetName())
			}
		}
		os.Exit(1)
	}

	diffing := false
	diffRtt := ""
	diffName := ""
	diff := func() string { return "" }

	if rawDiff != nil && len(*rawDiff) > 0 {
		diffing = true
		diff, diffName, conn = hfileUrlAndName(*rawDiff)
		if conn != nil {
			defer conn.Close()
		}
		diffRtt = "rtt." + diffName
		rttName = "rtt." + name
	}

	l := &Load{
		collection:       *collection,
		sample:           sample,
		server:           server,
		diffing:          diffing,
		diff:             diff,
		work:             make(chan bool, (*workers)),
		dropped:          r.GetMeter("dropped"),
		queueSize:        r.GetGuage("queue"),
		rtt:              rttName,
		diffRtt:          diffRtt,
		mixPrefix:        int32(*mixPrefix),
		mixIterator:      int32(*mixPrefix + *mixIter),
		mixMulti:         int32(*mixPrefix + *mixIter + *mixMulti),
		keysPerReqMin:    float64(*minKeys),
		keysPerReqMax:    float64(*maxKeys),
		keysPerReqSpread: *spreadKeys,
	}

	if *printSpread {
		fmt.Println("Key count distribtion:")
		l.printKeySpread()
	}

	if err := l.setKeys(); err != nil {
		fmt.Println("Failed to fetch testing keys:", err)
		os.Exit(1)
	}

	if *maxQps {
		fmt.Printf("Sending max qps to %s (%s), drawing from %d random keys...\n", name, server(), len(l.keys))
	} else {
		fmt.Printf("Sending %dqps to %s (%s), drawing from %d random keys...\n", *qps, name, server(), len(l.keys))
		go l.generator(*qps)
	}
	if l.diffing {
		fmt.Printf("Diffing against %s (%s)\n", diffName, l.diff())
	}

	l.startWorkers(*workers, *maxQps)

	reader := bufio.NewReader(os.Stdin)

	for {
		fmt.Print("Press enter for stats summary.\n")
		reader.ReadString('\n')
		l.PrintSummary()
	}
}
<|endoftext|>


<commit_before><commit_msg>Use yaml construct tags in config<commit_after><|endoftext|>


<commit_before><commit_msg>add DJ config to struct<commit_after><|endoftext|>


<commit_before>/*

    account.go
        Account (Signed) Endpoints for Binance Exchange API

*/
package binance

import (
    "fmt"
)

// Get Basic Account Information
func (b *Binance) GetAccountInfo() (account Account, err error) {

    reqUrl := fmt.Sprintf("api/v3/account")

    _, err = b.client.do("GET", reqUrl, "", true, &account)
    if err != nil {
        return
    }

    return
}

// Filter Basic Account Information To Retrieve Current Holdings
func (b *Binance) GetPositions() (positions []Balance, err error) {

    reqUrl := fmt.Sprintf("api/v3/account")
    account := Account{}

    _, err = b.client.do("GET", reqUrl, "", true, &account)
    if err != nil {
        return
    }

    positions = make([]Balance, len(account.Balances))
    i := 0

    for _, balance := range account.Balances {
        if balance.Free != 0.0 || balance.Locked != 0.0 {
            positions[i] = balance
            i++
        }
    }

    return positions[:i], nil
}

// Place a Limit Order
func (b *Binance) PlaceLimitOrder(l LimitOrder) (res PlacedOrder, err error) {

    err = l.ValidateLimitOrder()
    if err != nil {
        return
    }

    reqUrl := fmt.Sprintf("api/v3/order?symbol=%s&side=%s&type=%s&timeInForce=%s&quantity=%f&price=%f&recvWindow=%d", l.Symbol, l.Side, l.Type, l.TimeInForce, l.Quantity, l.Price, l.RecvWindow)

    _, err = b.client.do("POST", reqUrl, "", true, &res)
    if err != nil {
        return
    }

    return
}

// Place a Market Order
func (b *Binance) PlaceMarketOrder(m MarketOrder) (res PlacedOrder, err error) {

    err = m.ValidateMarketOrder()
    if err != nil {
        return
    }

    reqUrl := fmt.Sprintf("api/v3/order?symbol=%s&side=%s&type=%s&quantity=%f&recvWindow=%d", m.Symbol, m.Side, m.Type, m.Quantity, m.RecvWindow)

    _, err = b.client.do("POST", reqUrl, "", true, &res)
    if err != nil {
        return
    }

    return
}

// Cancel an Order
func (b *Binance) CancelOrder(query OrderQuery) (order CanceledOrder, err error) {

    err = query.ValidateOrderQuery()
    if err != nil {
        return
    }

    reqUrl := fmt.Sprintf("api/v3/order?symbol=%s&orderId=%d&recvWindow=%d", query.Symbol, query.OrderId, query.RecvWindow)

    _, err = b.client.do("DELETE", reqUrl, "", true, &order)
    if err != nil {
        return
    }

    return
}

// Check the Status of an Order
func (b *Binance) CheckOrder(query OrderQuery) (status OrderStatus, err error) {

    err = query.ValidateOrderQuery()
    if err != nil {
        return
    }

    reqUrl := fmt.Sprintf("api/v3/order?symbol=%s&orderId=%d&origClientOrderId=%s&recvWindow=%d", query.Symbol, query.OrderId, query.RecvWindow)

    _, err = b.client.do("GET", reqUrl, "", true, &status)
    if err != nil {
        return
    }

    return
}

// Retrieve All Open Orders
func (b *Binance) GetAllOpenOrders() (orders []OrderStatus, err error) {
    _, err = b.client.do("GET", "v3/openOrders", "", true, &orders)

    if err != nil {
        return
    }

    return
}

// Retrieve All Open Orders for a given symbol
func (b *Binance) GetOpenOrders(query OpenOrdersQuery) (orders []OrderStatus, err error) {

    err = query.ValidateOpenOrdersQuery()
    if err != nil {
        return
    }
    reqUrl := fmt.Sprintf("api/v3/openOrders?symbol=%s&recvWindow=%d", query.Symbol, query.RecvWindow)
    _, err = b.client.do("GET", reqUrl, "", true, &orders)
    if err != nil {
        return
    }

    return
}

// Retrieves all trades
func (b *Binance) GetTrades(symbol string) (trades []Trade, err error) {
    _, err = b.client.do("GET", "api/v3/myTrades?symbol=" + symbol, "", true, &trades)

    if err != nil {
        return
    }
    return
}

//
// Retrieves all withdrawals
func (b *Binance) GetWithdrawHistory() (withdraws WithdrawList, err error) {

    reqUrl := fmt.Sprintf("wapi/v3/withdrawHistory.html")

    _, err = b.client.do("GET", reqUrl, "", true, &withdraws)
    if err != nil {
        return
    }
    return
}

//
// Retrieves all deposits
func (b *Binance) GetDepositHistory() (deposits DepositList, err error) {

    reqUrl := fmt.Sprintf("wapi/v3/depositHistory.html")

    _, err = b.client.do("GET", reqUrl, "", true, &deposits)
    if err != nil {
        return
    }
    return
}
<commit_msg>restore GetTrades method<commit_after>/*

    account.go
        Account (Signed) Endpoints for Binance Exchange API

*/
package binance

import (
    "fmt"
)

// Get Basic Account Information
func (b *Binance) GetAccountInfo() (account Account, err error) {

    reqUrl := fmt.Sprintf("api/v3/account")

    _, err = b.client.do("GET", reqUrl, "", true, &account)
    if err != nil {
        return
    }

    return
}

// Filter Basic Account Information To Retrieve Current Holdings
func (b *Binance) GetPositions() (positions []Balance, err error) {

    reqUrl := fmt.Sprintf("api/v3/account")
    account := Account{}

    _, err = b.client.do("GET", reqUrl, "", true, &account)
    if err != nil {
        return
    }

    positions = make([]Balance, len(account.Balances))
    i := 0

    for _, balance := range account.Balances {
        if balance.Free != 0.0 || balance.Locked != 0.0 {
            positions[i] = balance
            i++
        }
    }

    return positions[:i], nil
}

// Place a Limit Order
func (b *Binance) PlaceLimitOrder(l LimitOrder) (res PlacedOrder, err error) {

    err = l.ValidateLimitOrder()
    if err != nil {
        return
    }

    reqUrl := fmt.Sprintf("api/v3/order?symbol=%s&side=%s&type=%s&timeInForce=%s&quantity=%f&price=%f&recvWindow=%d", l.Symbol, l.Side, l.Type, l.TimeInForce, l.Quantity, l.Price, l.RecvWindow)

    _, err = b.client.do("POST", reqUrl, "", true, &res)
    if err != nil {
        return
    }

    return
}

// Place a Market Order
func (b *Binance) PlaceMarketOrder(m MarketOrder) (res PlacedOrder, err error) {

    err = m.ValidateMarketOrder()
    if err != nil {
        return
    }

    reqUrl := fmt.Sprintf("api/v3/order?symbol=%s&side=%s&type=%s&quantity=%f&recvWindow=%d", m.Symbol, m.Side, m.Type, m.Quantity, m.RecvWindow)

    _, err = b.client.do("POST", reqUrl, "", true, &res)
    if err != nil {
        return
    }

    return
}

// Cancel an Order
func (b *Binance) CancelOrder(query OrderQuery) (order CanceledOrder, err error) {

    err = query.ValidateOrderQuery()
    if err != nil {
        return
    }

    reqUrl := fmt.Sprintf("api/v3/order?symbol=%s&orderId=%d&recvWindow=%d", query.Symbol, query.OrderId, query.RecvWindow)

    _, err = b.client.do("DELETE", reqUrl, "", true, &order)
    if err != nil {
        return
    }

    return
}

// Check the Status of an Order
func (b *Binance) CheckOrder(query OrderQuery) (status OrderStatus, err error) {

    err = query.ValidateOrderQuery()
    if err != nil {
        return
    }

    reqUrl := fmt.Sprintf("api/v3/order?symbol=%s&orderId=%d&origClientOrderId=%s&recvWindow=%d", query.Symbol, query.OrderId, query.RecvWindow)

    _, err = b.client.do("GET", reqUrl, "", true, &status)
    if err != nil {
        return
    }

    return
}

// Retrieve All Open Orders
func (b *Binance) GetAllOpenOrders() (orders []OrderStatus, err error) {
    _, err = b.client.do("GET", "v3/openOrders", "", true, &orders)

    if err != nil {
        return
    }

    return
}

// Retrieve All Open Orders for a given symbol
func (b *Binance) GetOpenOrders(query OpenOrdersQuery) (orders []OrderStatus, err error) {

    err = query.ValidateOpenOrdersQuery()
    if err != nil {
        return
    }
    reqUrl := fmt.Sprintf("api/v3/openOrders?symbol=%s&recvWindow=%d", query.Symbol, query.RecvWindow)
    _, err = b.client.do("GET", reqUrl, "", true, &orders)
    if err != nil {
        return
    }

    return
}

// Retrieves all trades
func (b *Binance) GetTrades(symbol string) (trades []Trade, err error) {

    reqUrl := fmt.Sprintf("api/v3/myTrades?symbol=%s", symbol)

     _, err = b.client.do("GET", reqUrl, "", true, &trades)

    if err != nil {
        return
    }
    return
}

//
// Retrieves all withdrawals
func (b *Binance) GetWithdrawHistory() (withdraws WithdrawList, err error) {

    reqUrl := fmt.Sprintf("wapi/v3/withdrawHistory.html")

    _, err = b.client.do("GET", reqUrl, "", true, &withdraws)
    if err != nil {
        return
    }
    return
}

//
// Retrieves all deposits
func (b *Binance) GetDepositHistory() (deposits DepositList, err error) {

    reqUrl := fmt.Sprintf("wapi/v3/depositHistory.html")

    _, err = b.client.do("GET", reqUrl, "", true, &deposits)
    if err != nil {
        return
    }
    return
}
<|endoftext|>


<commit_before>// Package binding transforms, with validation, a raw request into
// a populated structure used by your application logic.
package binding

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"reflect"
	"strconv"
	"strings"

	"github.com/codegangsta/martini"
)

/*
	To the land of Middle-ware Earth:
		One func to rule them all,
		One func to find them,
		One func to bring them all,
		And in this package BIND them.
			- Sincerely, Sauron
*/

// Bind accepts a copy of an empty struct and populates it with
// values from the request (if deserialization is successful). It
// wraps up the functionality of the Form and Json middleware
// according to the Content-Type of the request, and it guesses
// if no Content-Type is specified. Bind invokes the ErrorHandler
// middleware to bail out if errors occurred. If you want to perform
// your own error handling, use Form or Json middleware directly.
func Bind(obj interface{}) martini.Handler {
	return func(context martini.Context, req *http.Request) {
		contentType := req.Header.Get("Content-Type")

		if strings.Contains(contentType, "form-urlencoded") {
			context.Invoke(Form(obj))
		} else if strings.Contains(contentType, "json") {
			context.Invoke(Json(obj))
		} else {
			context.Invoke(Json(obj))
			if getErrors(context).Count() > 0 {
				context.Invoke(Form(obj))
			}
		}

		context.Invoke(ErrorHandler)
	}
}

// Form is middleware to deserialize Form-encoded data from the request.
// It gets data from the form-urlencoded payload, if present, or from the
// query string as well. It uses the http.Request.ParseForm() method to
// perform deserialization, then reflection is used to map each field
// into the struct with the proper type.
func Form(formStruct interface{}) martini.Handler {
	return func(context martini.Context, req *http.Request) {
		ensureNotPointer(formStruct)
		formStruct := reflect.New(reflect.TypeOf(formStruct))
		errors := newErrors()
		parseErr := req.ParseForm()

		if parseErr != nil {
			errors.Overall[DeserializationError] = parseErr.Error()
		}

		typ := formStruct.Elem().Type()

		for i := 0; i < typ.NumField(); i++ {
			typeField := typ.Field(i)
			if inputFieldName := typeField.Tag.Get("form"); inputFieldName != "" {
				inputValue := req.Form.Get(inputFieldName)
				structField := formStruct.Elem().Field(i)

				if !structField.CanSet() {
					continue
				}

				setWithProperType(typeField, inputValue, structField, inputFieldName, errors)
			}
		}

		validateAndMap(formStruct, context, errors)
	}
}

// Json is middleware to deserialize a JSON payload from the request
// into the struct that is passed in. The resulting struct is then
// validated, but no error handling is actually performed here.
func Json(jsonStruct interface{}) martini.Handler {
	return func(context martini.Context, req *http.Request) {
		ensureNotPointer(jsonStruct)
		jsonStruct := reflect.New(reflect.TypeOf(jsonStruct))
		errors := newErrors()

		if req.Body != nil {
			defer req.Body.Close()
		}

		content, err := ioutil.ReadAll(req.Body)
		if err != nil {
			errors.Overall[ReaderError] = err.Error()
		} else if err = json.Unmarshal(content, jsonStruct.Interface()); err != nil {
			errors.Overall[DeserializationError] = err.Error()
		}

		validateAndMap(jsonStruct, context, errors)
	}
}

// Validate is middleware to enforce required fields. If the struct
// passed in is a Validator, then the user-defined Validate method
// is executed, and its errors are mapped to the context. This middleware
// performs no error handling: it merely detects them and maps them.
func Validate(obj interface{}) martini.Handler {
	return func(context martini.Context, req *http.Request) {
		errors := newErrors()
		validateStruct(errors, obj)

		if validator, ok := obj.(Validator); ok {
			validator.Validate(errors, req)
		}
		context.Map(*errors)

	}
}

func validateStruct(errors *Errors, obj interface{}) {
	typ := reflect.TypeOf(obj)
	val := reflect.ValueOf(obj)

	if typ.Kind() == reflect.Ptr {
		typ = typ.Elem()
		val = val.Elem()
	}

	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)

		// Allow ignored fields in the struct
		if field.Tag.Get("form") == "-" {
			continue
		}

		fieldValue := val.Field(i).Interface()
		zero := reflect.Zero(field.Type).Interface()

		if strings.Index(field.Tag.Get("binding"), "required") > -1 {
			if field.Type.Kind() == reflect.Struct {
				validateStruct(errors, fieldValue)
			} else if reflect.DeepEqual(zero, fieldValue) {
				errors.Fields[field.Name] = RequireError
			}
		}
	}
}

// ErrorHandler simply counts the number of errors in the
// context and, if more than 0, writes a 400 Bad Request
// response and a JSON payload describing the errors with
// the "Content-Type" set to "application/json".
// Middleware remaining on the stack will not even see the request
// if, by this point, there are any errors.
// This is a "default" handler, of sorts, and you are
// welcome to use your own instead. The Bind middleware
// invokes this automatically for convenience.
func ErrorHandler(errs Errors, resp http.ResponseWriter) {
	if errs.Count() > 0 {
		resp.Header().Set("Content-Type", "application/json; charset=utf-8")
		resp.WriteHeader(http.StatusBadRequest)
		errOutput, _ := json.Marshal(errs)
		resp.Write(errOutput)
		return
	}
}

// This sets the value in a struct of an indeterminate type to the
// matching value from the request (via Form middleware) in the
// same type, so that not all deserialized values have to be strings.
// Supported types are string, int, float, and bool.
func setWithProperType(typeField reflect.StructField, val string, structField reflect.Value, nameInTag string, errors *Errors) {
	switch typeField.Type.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if val == "" {
			val = "0"
		}
		intVal, err := strconv.Atoi(val)
		if err != nil {
			errors.Fields[nameInTag] = IntegerTypeError
		} else {
			structField.SetInt(int64(intVal))
		}
	case reflect.Bool:
		if val == "" {
			val = "false"
		}
		boolVal, err := strconv.ParseBool(val)
		if err != nil {
			errors.Fields[nameInTag] = BooleanTypeError
		} else {
			structField.SetBool(boolVal)
		}
	case reflect.Float32:
		if val == "" {
			val = "0.0"
		}
		floatVal, err := strconv.ParseFloat(val, 32)
		if err != nil {
			errors.Fields[nameInTag] = FloatTypeError
		} else {
			structField.SetFloat(floatVal)
		}
	case reflect.Float64:
		if val == "" {
			val = "0.0"
		}
		floatVal, err := strconv.ParseFloat(val, 64)
		if err != nil {
			errors.Fields[nameInTag] = FloatTypeError
		} else {
			structField.SetFloat(floatVal)
		}
	case reflect.String:
		structField.SetString(val)
	}
}

// Don't pass in pointers to bind to. Can lead to bugs. See:
// https://github.com/codegangsta/martini-contrib/issues/40
// https://github.com/codegangsta/martini-contrib/pull/34#issuecomment-29683659
func ensureNotPointer(obj interface{}) {
	if reflect.TypeOf(obj).Kind() == reflect.Ptr {
		panic("Pointers are not accepted as binding models")
	}
}

// Performs validation and combines errors from validation
// with errors from deserialization, then maps both the
// resulting struct and the errors to the context.
func validateAndMap(obj reflect.Value, context martini.Context, errors *Errors) {
	context.Invoke(Validate(obj.Interface()))
	errors.combine(getErrors(context))
	context.Map(*errors)
	context.Map(obj.Elem().Interface())
}

func newErrors() *Errors {
	return &Errors{make(map[string]string), make(map[string]string)}
}

func getErrors(context martini.Context) Errors {
	return context.Get(reflect.TypeOf(Errors{})).Interface().(Errors)
}

func (this *Errors) combine(other Errors) {
	for key, val := range other.Fields {
		if _, exists := this.Fields[key]; !exists {
			this.Fields[key] = val
		}
	}
	for key, val := range other.Overall {
		if _, exists := this.Overall[key]; !exists {
			this.Overall[key] = val
		}
	}
}

// Total errors is the sum of errors with the request overall
// and errors on individual fields.
func (self Errors) Count() int {
	return len(self.Overall) + len(self.Fields)
}

type (
	// Errors represents the contract of the response body when the
	// binding step fails before getting to the application.
	Errors struct {
		Overall map[string]string `json:"overall"`
		Fields  map[string]string `json:"fields"`
	}

	// Implement the Validator interface to define your own input
	// validation before the request even gets to your application.
	// The Validate method will be executed during the validation phase.
	Validator interface {
		Validate(*Errors, *http.Request)
	}
)

const (
	RequireError         string = "Required"
	DeserializationError string = "DeserializationError"
	ReaderError          string = "ReaderError"
	IntegerTypeError     string = "IntegerTypeError"
	BooleanTypeError     string = "BooleanTypeError"
	FloatTypeError       string = "FloatTypeError"
)
<commit_msg>Sauron wouldn’t sign a letter with “Sincerely”<commit_after>// Package binding transforms, with validation, a raw request into
// a populated structure used by your application logic.
package binding

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"reflect"
	"strconv"
	"strings"

	"github.com/codegangsta/martini"
)

/*
	To the land of Middle-ware Earth:

		One func to rule them all,
		One func to find them,
		One func to bring them all,
		And in this package BIND them.
*/

// Bind accepts a copy of an empty struct and populates it with
// values from the request (if deserialization is successful). It
// wraps up the functionality of the Form and Json middleware
// according to the Content-Type of the request, and it guesses
// if no Content-Type is specified. Bind invokes the ErrorHandler
// middleware to bail out if errors occurred. If you want to perform
// your own error handling, use Form or Json middleware directly.
func Bind(obj interface{}) martini.Handler {
	return func(context martini.Context, req *http.Request) {
		contentType := req.Header.Get("Content-Type")

		if strings.Contains(contentType, "form-urlencoded") {
			context.Invoke(Form(obj))
		} else if strings.Contains(contentType, "json") {
			context.Invoke(Json(obj))
		} else {
			context.Invoke(Json(obj))
			if getErrors(context).Count() > 0 {
				context.Invoke(Form(obj))
			}
		}

		context.Invoke(ErrorHandler)
	}
}

// Form is middleware to deserialize Form-encoded data from the request.
// It gets data from the form-urlencoded payload, if present, or from the
// query string as well. It uses the http.Request.ParseForm() method to
// perform deserialization, then reflection is used to map each field
// into the struct with the proper type.
func Form(formStruct interface{}) martini.Handler {
	return func(context martini.Context, req *http.Request) {
		ensureNotPointer(formStruct)
		formStruct := reflect.New(reflect.TypeOf(formStruct))
		errors := newErrors()
		parseErr := req.ParseForm()

		if parseErr != nil {
			errors.Overall[DeserializationError] = parseErr.Error()
		}

		typ := formStruct.Elem().Type()

		for i := 0; i < typ.NumField(); i++ {
			typeField := typ.Field(i)
			if inputFieldName := typeField.Tag.Get("form"); inputFieldName != "" {
				inputValue := req.Form.Get(inputFieldName)
				structField := formStruct.Elem().Field(i)

				if !structField.CanSet() {
					continue
				}

				setWithProperType(typeField, inputValue, structField, inputFieldName, errors)
			}
		}

		validateAndMap(formStruct, context, errors)
	}
}

// Json is middleware to deserialize a JSON payload from the request
// into the struct that is passed in. The resulting struct is then
// validated, but no error handling is actually performed here.
func Json(jsonStruct interface{}) martini.Handler {
	return func(context martini.Context, req *http.Request) {
		ensureNotPointer(jsonStruct)
		jsonStruct := reflect.New(reflect.TypeOf(jsonStruct))
		errors := newErrors()

		if req.Body != nil {
			defer req.Body.Close()
		}

		content, err := ioutil.ReadAll(req.Body)
		if err != nil {
			errors.Overall[ReaderError] = err.Error()
		} else if err = json.Unmarshal(content, jsonStruct.Interface()); err != nil {
			errors.Overall[DeserializationError] = err.Error()
		}

		validateAndMap(jsonStruct, context, errors)
	}
}

// Validate is middleware to enforce required fields. If the struct
// passed in is a Validator, then the user-defined Validate method
// is executed, and its errors are mapped to the context. This middleware
// performs no error handling: it merely detects them and maps them.
func Validate(obj interface{}) martini.Handler {
	return func(context martini.Context, req *http.Request) {
		errors := newErrors()
		validateStruct(errors, obj)

		if validator, ok := obj.(Validator); ok {
			validator.Validate(errors, req)
		}
		context.Map(*errors)

	}
}

func validateStruct(errors *Errors, obj interface{}) {
	typ := reflect.TypeOf(obj)
	val := reflect.ValueOf(obj)

	if typ.Kind() == reflect.Ptr {
		typ = typ.Elem()
		val = val.Elem()
	}

	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)

		// Allow ignored fields in the struct
		if field.Tag.Get("form") == "-" {
			continue
		}

		fieldValue := val.Field(i).Interface()
		zero := reflect.Zero(field.Type).Interface()

		if strings.Index(field.Tag.Get("binding"), "required") > -1 {
			if field.Type.Kind() == reflect.Struct {
				validateStruct(errors, fieldValue)
			} else if reflect.DeepEqual(zero, fieldValue) {
				errors.Fields[field.Name] = RequireError
			}
		}
	}
}

// ErrorHandler simply counts the number of errors in the
// context and, if more than 0, writes a 400 Bad Request
// response and a JSON payload describing the errors with
// the "Content-Type" set to "application/json".
// Middleware remaining on the stack will not even see the request
// if, by this point, there are any errors.
// This is a "default" handler, of sorts, and you are
// welcome to use your own instead. The Bind middleware
// invokes this automatically for convenience.
func ErrorHandler(errs Errors, resp http.ResponseWriter) {
	if errs.Count() > 0 {
		resp.Header().Set("Content-Type", "application/json; charset=utf-8")
		resp.WriteHeader(http.StatusBadRequest)
		errOutput, _ := json.Marshal(errs)
		resp.Write(errOutput)
		return
	}
}

// This sets the value in a struct of an indeterminate type to the
// matching value from the request (via Form middleware) in the
// same type, so that not all deserialized values have to be strings.
// Supported types are string, int, float, and bool.
func setWithProperType(typeField reflect.StructField, val string, structField reflect.Value, nameInTag string, errors *Errors) {
	switch typeField.Type.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if val == "" {
			val = "0"
		}
		intVal, err := strconv.Atoi(val)
		if err != nil {
			errors.Fields[nameInTag] = IntegerTypeError
		} else {
			structField.SetInt(int64(intVal))
		}
	case reflect.Bool:
		if val == "" {
			val = "false"
		}
		boolVal, err := strconv.ParseBool(val)
		if err != nil {
			errors.Fields[nameInTag] = BooleanTypeError
		} else {
			structField.SetBool(boolVal)
		}
	case reflect.Float32:
		if val == "" {
			val = "0.0"
		}
		floatVal, err := strconv.ParseFloat(val, 32)
		if err != nil {
			errors.Fields[nameInTag] = FloatTypeError
		} else {
			structField.SetFloat(floatVal)
		}
	case reflect.Float64:
		if val == "" {
			val = "0.0"
		}
		floatVal, err := strconv.ParseFloat(val, 64)
		if err != nil {
			errors.Fields[nameInTag] = FloatTypeError
		} else {
			structField.SetFloat(floatVal)
		}
	case reflect.String:
		structField.SetString(val)
	}
}

// Don't pass in pointers to bind to. Can lead to bugs. See:
// https://github.com/codegangsta/martini-contrib/issues/40
// https://github.com/codegangsta/martini-contrib/pull/34#issuecomment-29683659
func ensureNotPointer(obj interface{}) {
	if reflect.TypeOf(obj).Kind() == reflect.Ptr {
		panic("Pointers are not accepted as binding models")
	}
}

// Performs validation and combines errors from validation
// with errors from deserialization, then maps both the
// resulting struct and the errors to the context.
func validateAndMap(obj reflect.Value, context martini.Context, errors *Errors) {
	context.Invoke(Validate(obj.Interface()))
	errors.combine(getErrors(context))
	context.Map(*errors)
	context.Map(obj.Elem().Interface())
}

func newErrors() *Errors {
	return &Errors{make(map[string]string), make(map[string]string)}
}

func getErrors(context martini.Context) Errors {
	return context.Get(reflect.TypeOf(Errors{})).Interface().(Errors)
}

func (this *Errors) combine(other Errors) {
	for key, val := range other.Fields {
		if _, exists := this.Fields[key]; !exists {
			this.Fields[key] = val
		}
	}
	for key, val := range other.Overall {
		if _, exists := this.Overall[key]; !exists {
			this.Overall[key] = val
		}
	}
}

// Total errors is the sum of errors with the request overall
// and errors on individual fields.
func (self Errors) Count() int {
	return len(self.Overall) + len(self.Fields)
}

type (
	// Errors represents the contract of the response body when the
	// binding step fails before getting to the application.
	Errors struct {
		Overall map[string]string `json:"overall"`
		Fields  map[string]string `json:"fields"`
	}

	// Implement the Validator interface to define your own input
	// validation before the request even gets to your application.
	// The Validate method will be executed during the validation phase.
	Validator interface {
		Validate(*Errors, *http.Request)
	}
)

const (
	RequireError         string = "Required"
	DeserializationError string = "DeserializationError"
	ReaderError          string = "ReaderError"
	IntegerTypeError     string = "IntegerTypeError"
	BooleanTypeError     string = "BooleanTypeError"
	FloatTypeError       string = "FloatTypeError"
)
<|endoftext|>