<commit_before>package geofence_test

import (
	"bytes"
	"fmt"
	"os"
	"strings"
	"testing"

	"github.com/buckhx/diglet/geo"
	"github.com/buckhx/gofence/geofence"
)

const (
	TEST_ZOOM = 14
)

var (
	ues            *geo.Feature
	s2f            geofence.GeoFence
	tracts, result []*geo.Feature
	museums        = map[string]geo.Coordinate{
		"guggenheim":      {40.7830, -73.9590},
		"met":             {40.7788, -73.9621},
		"moma":            {40.7615, -73.9777},
		"whitney":         {40.7396, -74.0089},
		"old whitney":     {40.7732, -73.9641},
		"natural history": {40.7806, -73.9747},
		"brooklyn":        {40.6713, -73.9638},
		"louvre":          {48.8611, 2.3364},
	}
)

func TestFences(t *testing.T) {
	tests := []struct {
		museum   string
		contains bool
	}{
		{"guggenheim", true},
		{"met", true},
		{"old whitney", true},
		{"whitney", false},
		{"moma", false},
		{"natural history", false},
		{"brooklyn", false},
		{"louvre", false},
	}
	idx := geofence.NewFenceIndex()
	for _, fn := range geofence.FenceLabels {
		fence, err := geofence.GetFence(fn, TEST_ZOOM)
		if err != nil {
			// City fences need NYC_BOROS_PATH and we don't always want to test them
			t.Logf("Skipping %q because - %s", fn, err)
			continue
		}
		idx.Set(fn, fence)
		fence.Add(ues)
		for _, test := range tests {
			// Search test
			c := museums[test.museum]
			if (len(fence.Get(c)) == 0) == test.contains {
				t.Errorf("Invalid search %q %q %s", fn, test.museum, c)
			}
			// Index test
			if matchs, err := idx.Search(fn, c); err != nil {
				t.Errorf("Error index search %q - $s", fn, err)
			} else if (len(matchs) == 0) == test.contains {
				t.Errorf("Invalid index search %q %q %s", fn, test.museum, c)
			}
			// Encoding test
			p := &geofence.PointMessage{
				Type:       "Feature",
				Properties: geofence.Properties{"name": []byte(test.museum)}, //TODO fix this
				Geometry:   geofence.PointGeometry{Type: "Point", Coordinates: []float64{c.Lon, c.Lat}},
			}
			b := bytes.NewBuffer(nil)
			err = geofence.WriteJson(b, p)
			if err != nil {
				t.Errorf("Error writing json %s", err)
			}
			res, err := geofence.GeojsonSearch(idx, fn, b.Bytes())
			if err != nil {
				t.Errorf("Error GeojsonSearch %s", err)
			}
			if (len(res.Fences) == 0) == test.contains {
				t.Errorf("Invalid GeojsonSearch %q %q %s", fn, test.museum, c)
			}
		}
	}
}

func BenchmarkBrute(b *testing.B) {
	fence := geofence.NewBruteFence()
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkCity(b *testing.B) {
	fence, err := geofence.NewCityFence()
	if err != nil {
		fmt.Printf("Skipping benchmark for 'CityFence' because %s", err)
		return
	}
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkBbox(b *testing.B) {
	fence := geofence.NewBboxFence()
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkCityBbox(b *testing.B) {
	fence, err := geofence.NewCityBboxFence()
	if err != nil {
		fmt.Printf("Skipping benchmark for 'CityBboxFence' because %s", err)
		return
	}
	if err != nil {
		return
	}
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkQfence(b *testing.B) {
	fence := geofence.NewQfence(TEST_ZOOM)
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkRfence(b *testing.B) {
	fence := geofence.NewRfence()
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkS2fence(b *testing.B) {
	for n := 0; n < b.N; n++ {
		// interior @ Z18
		result = s2f.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func TestMain(m *testing.M) {
	for _, arg := range os.Args {
		// only load tracts if benching
		if strings.Contains(arg, "bench") {
			path := os.Getenv("NYC_TRACTS_PATH")
			if path == "" {
				panic("Missing NYC_TRACTS_PATH envvar")
			}
			features, err := loadGeojson(path)
			if err != nil {
				panic(err)
			}
			tracts = features
			fmt.Println("Loading s2fence...")
			s2f = geofence.NewS2fence(TEST_ZOOM)
			for _, tract := range tracts {
				//fmt.Printf("s2fence adding feature %d\n", i)
				s2f.Add(tract)
			}
			fmt.Println("Loaded s2fence!")
			break
		}
	}
	ues = getUpperEastSide()
	os.Exit(m.Run())
}

func loadGeojson(path string) (features []*geo.Feature, err error) {
	source, err := geo.NewGeojsonSource(path, nil).Publish()
	if err != nil {
		return
	}
	for feature := range source {
		features = append(features, feature)
	}
	return
}

func getUpperEastSide() (ues *geo.Feature) {
	shp := geo.NewShape()
	for _, p := range [][]float64{
		{-73.9493, 40.7852}, // w
		{-73.9665, 40.7615}, // s
		{-73.9730, 40.7642}, // e
		{-73.9557, 40.7879}, // n
		{-73.9493, 40.7852}, // w
	} {
		c := geo.Coordinate{p[1], p[0]} //swapped
		shp.Add(c)
	}
	ues = geo.NewPolygonFeature(shp)
	ues.Properties = map[string]interface{}{"BoroName": "Manhattan", "NTAName": "Upper East Side"} // for city
	return
}
<commit_msg>.Add microbenchmarking<commit_after>package geofence_test

import (
	"bytes"
	"fmt"
	"os"
	"strings"
	"testing"

	"github.com/buckhx/diglet/geo"
	"github.com/buckhx/gofence/geofence"
)

const (
	TEST_ZOOM = 14
)

var (
	ues            *geo.Feature
	s2f            geofence.GeoFence
	tracts, result []*geo.Feature
	museums        = map[string]geo.Coordinate{
		"guggenheim":      {40.7830, -73.9590},
		"met":             {40.7788, -73.9621},
		"moma":            {40.7615, -73.9777},
		"whitney":         {40.7396, -74.0089},
		"old whitney":     {40.7732, -73.9641},
		"natural history": {40.7806, -73.9747},
		"brooklyn":        {40.6713, -73.9638},
		"louvre":          {48.8611, 2.3364},
	}
)

func TestFences(t *testing.T) {
	tests := []struct {
		museum   string
		contains bool
	}{
		{"guggenheim", true},
		{"met", true},
		{"old whitney", true},
		{"whitney", false},
		{"moma", false},
		{"natural history", false},
		{"brooklyn", false},
		{"louvre", false},
	}
	idx := geofence.NewFenceIndex()
	for _, fn := range geofence.FenceLabels {
		fence, err := geofence.GetFence(fn, TEST_ZOOM)
		if err != nil {
			// City fences need NYC_BOROS_PATH and we don't always want to test them
			t.Logf("Skipping %q because - %s", fn, err)
			continue
		}
		idx.Set(fn, fence)
		fence.Add(ues)
		for _, test := range tests {
			// Search test
			c := museums[test.museum]
			if (len(fence.Get(c)) == 0) == test.contains {
				t.Errorf("Invalid search %q %q %s", fn, test.museum, c)
			}
			// Index test
			if matchs, err := idx.Search(fn, c); err != nil {
				t.Errorf("Error index search %q - $s", fn, err)
			} else if (len(matchs) == 0) == test.contains {
				t.Errorf("Invalid index search %q %q %s", fn, test.museum, c)
			}
			// Encoding test
			p := &geofence.PointMessage{
				Type:       "Feature",
				Properties: geofence.Properties{"name": []byte(test.museum)}, //TODO fix this
				Geometry:   geofence.PointGeometry{Type: "Point", Coordinates: []float64{c.Lon, c.Lat}},
			}
			b := bytes.NewBuffer(nil)
			err = geofence.WriteJson(b, p)
			if err != nil {
				t.Errorf("Error writing json %s", err)
			}
			res, err := geofence.GeojsonSearch(idx, fn, b.Bytes())
			if err != nil {
				t.Errorf("Error GeojsonSearch %s", err)
			}
			if (len(res.Fences) == 0) == test.contains {
				t.Errorf("Invalid GeojsonSearch %q %q %s", fn, test.museum, c)
			}
		}
	}
}

func BenchmarkBruteGet(b *testing.B) {
	fence := geofence.NewBruteFence()
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkCityGet(b *testing.B) {
	fence, err := geofence.NewCityFence()
	if err != nil {
		fmt.Printf("Skipping benchmark for 'CityFence' because %s", err)
		return
	}
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkBboxGet(b *testing.B) {
	fence := geofence.NewBboxFence()
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkCityBboxGet(b *testing.B) {
	fence, err := geofence.NewCityBboxFence()
	if err != nil {
		fmt.Printf("Skipping benchmark for 'CityBboxFence' because %s", err)
		return
	}
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkQfenceGet(b *testing.B) {
	fence := geofence.NewQfence(TEST_ZOOM)
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkRfenceGet(b *testing.B) {
	fence := geofence.NewRfence()
	for _, tract := range tracts {
		fence.Add(tract)
	}
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		result = fence.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkS2fenceGet(b *testing.B) {
	for n := 0; n < b.N; n++ {
		// interior @ Z18
		result = s2f.Get(museums["old whitney"])
		if len(result) != 1 {
			b.Fatal("Incorrect Get() result")
		}
	}
}

func BenchmarkBruteAdd(b *testing.B) {
	fence := geofence.NewBruteFence()
	for n := 0; n < b.N; n++ {
		tract := tracts[n%len(tracts)]
		fence.Add(tract)
	}
}

func BenchmarkCityAdd(b *testing.B) {
	fence, err := geofence.NewCityFence()
	if err != nil {
		fmt.Printf("Skipping benchmark for 'CityFence' because %s", err)
		return
	}
	for n := 0; n < b.N; n++ {
		tract := tracts[n%len(tracts)]
		fence.Add(tract)
	}
}

func BenchmarkBboxAdd(b *testing.B) {
	fence := geofence.NewBboxFence()
	for n := 0; n < b.N; n++ {
		tract := tracts[n%len(tracts)]
		fence.Add(tract)
	}
}

func BenchmarkCityBboxAdd(b *testing.B) {
	fence, err := geofence.NewCityBboxFence()
	if err != nil {
		fmt.Printf("Skipping benchmark for 'CityBboxFence' because %s", err)
		return
	}
	for n := 0; n < b.N; n++ {
		tract := tracts[n%len(tracts)]
		fence.Add(tract)
	}
}

func BenchmarkQfenceAdd(b *testing.B) {
	fence := geofence.NewQfence(TEST_ZOOM)
	for n := 0; n < b.N; n++ {
		tract := tracts[n%len(tracts)]
		fence.Add(tract)
	}
}

func BenchmarkRfenceAdd(b *testing.B) {
	fence := geofence.NewRfence()
	for n := 0; n < b.N; n++ {
		tract := tracts[n%len(tracts)]
		fence.Add(tract)
	}
}

func BenchmarkS2fenceAdd(b *testing.B) {
	fence := geofence.NewS2fence(TEST_ZOOM)
	for n := 0; n < b.N; n++ {
		tract := tracts[n%len(tracts)]
		fence.Add(tract)
	}
}

func TestMain(m *testing.M) {
	for _, arg := range os.Args {
		// only load tracts if benching
		if strings.Contains(arg, "bench") {
			path := os.Getenv("NYC_TRACTS_PATH")
			if path == "" {
				panic("Missing NYC_TRACTS_PATH envvar")
			}
			features, err := loadGeojson(path)
			if err != nil {
				panic(err)
			}
			tracts = features
			fmt.Println("Loading s2fence...")
			s2f = geofence.NewS2fence(TEST_ZOOM)
			for _, tract := range tracts {
				//fmt.Printf("s2fence adding feature %d\n", i)
				s2f.Add(tract)
			}
			fmt.Println("Loaded s2fence!")
			break
		}
	}
	ues = getUpperEastSide()
	os.Exit(m.Run())
}

func loadGeojson(path string) (features []*geo.Feature, err error) {
	source, err := geo.NewGeojsonSource(path, nil).Publish()
	if err != nil {
		return
	}
	for feature := range source {
		features = append(features, feature)
	}
	return
}

func getUpperEastSide() (ues *geo.Feature) {
	shp := geo.NewShape()
	for _, p := range [][]float64{
		{-73.9493, 40.7852}, // w
		{-73.9665, 40.7615}, // s
		{-73.9730, 40.7642}, // e
		{-73.9557, 40.7879}, // n
		{-73.9493, 40.7852}, // w
	} {
		c := geo.Coordinate{p[1], p[0]} //swapped
		shp.Add(c)
	}
	ues = geo.NewPolygonFeature(shp)
	ues.Properties = map[string]interface{}{"BoroName": "Manhattan", "NTAName": "Upper East Side"} // for city
	return
}
<|endoftext|>


<commit_before>package main

import (
    "github.com/ant0ine/go-json-rest/rest"
    "github.com/tbruyelle/hipchat-go/hipchat"
    "bytes"
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "os"
    "strconv"
    "strings"
    "sync"
    "time"
)

/*
To-do list
---------
Trains active
Manually depart a train
Derail a train
Start a train at a designated time
Tag people when the train leaves
Propose a train that starts if enough people join -> X
-----
Keep track of usage statistics
Look into making your own log to log things

53 so far
Look into moving to AWS
*/

var authKey string = ""
var roomName string = ""

var station *Station = &Station{
	Lock: &sync.Mutex{},
	Trains: make(map[string]*Train),
}

type WebhookMessage struct {
    Item struct {
        MessageStruct struct {
        	From struct {
        		MentionName string `json:"mention_name"`
        	}
        	Message string `json:"message"`
        } `json:"message"`

    }  `json:"item"`
}

type Train struct {
	Lock *sync.Mutex
	LeavingTimer *time.Timer
	ReminderTimer *time.Timer
	MapDestination string
	DisplayDestination string
	Passengers []string
	PassengerSet map[string]struct{}
}

func NewTrain(conductor string, departure int, dest string) *Train {
	timer := time.NewTimer(time.Minute * time.Duration(departure))
	timer2 := time.NewTimer(time.Minute * time.Duration(departure - 1))
	users := []string{conductor}
	trainMap := make(map[string]struct{})
	trainMap[conductor] = struct{}{}
	return &Train{
		Lock: &sync.Mutex{},
		LeavingTimer: timer,
		ReminderTimer: timer2,
		MapDestination: strings.ToLower(dest),
		DisplayDestination: dest,
		Passengers: users,
		PassengerSet: trainMap,
	}
}

func (t *Train) NewPassenger(pass string) error {
	t.Lock.Lock()
	defer t.Lock.Unlock()
	_, ok := t.PassengerSet[pass]
	if !ok {
		t.PassengerSet[pass] = struct{}{}
		t.Passengers = append(t.Passengers, pass)
		return nil
	} else {
		log.Printf("Passenger %s is already on the train\n", pass)
		return fmt.Errorf("Passenger %s is already on the train", pass)
	}
}

func (t *Train) PassengerString() string {
	t.Lock.Lock()
	defer t.Lock.Unlock()
	var buffer bytes.Buffer
	for i, v := range t.Passengers {
	   buffer.WriteString(v)
	   if i != len(t.Passengers) - 1 {
	    	buffer.WriteString(", ")
	    }
	   if i == len(t.Passengers) - 2 {
	    	buffer.WriteString("and ")
	   }
	}
	return buffer.String()

}

type Station struct {
	Lock *sync.Mutex
	Trains map[string]*Train
}

func (s *Station) AddTrain(t *Train) error {
	s.Lock.Lock()
	defer s.Lock.Unlock()
	_, ok := s.Trains[t.MapDestination]
	if !ok {
		s.Trains[t.MapDestination] = t
		return nil
	} else {
		log.Printf("Train to %s already exists", t.DisplayDestination)
		return fmt.Errorf("Train to %s already exists", t.DisplayDestination)
	}
}

func (s *Station) DeleteTrain(dest string) error {
	s.Lock.Lock()
	defer s.Lock.Unlock()
	_, ok := s.Trains[dest]
	if ok {
		 delete(s.Trains, dest)
		 return nil
	} else {
		log.Printf("The train to %s doesn't exist so it can't be removed", dest)
		return fmt.Errorf("The train to %s doesn't exist so it can't be removed", dest)
	}
}

func PostMessage(msg string) {
	c := hipchat.NewClient(authKey)
	msgReq := &hipchat.NotificationRequest{Message: msg}
	_, err := c.Room.Notification(roomName, msgReq)
	if err != nil {
		panic(err)
	}
}

func MonitorTrain(train *Train) {
	for {
		select {
	    case <- train.LeavingTimer.C:
	    	var buffer bytes.Buffer
	    	start := fmt.Sprintf("The train to %v has left the station with ", train.DisplayDestination)
	    	buffer.WriteString(start)
	    	buffer.WriteString(train.PassengerString())
	    	buffer.WriteString(" on it!")
	    	PostMessage(buffer.String())
	    	station.DeleteTrain(train.MapDestination)
	    	return
	    case <- train.ReminderTimer.C:
            PostMessage(fmt.Sprintf("Reminder, the next train to %v leaves in one minute", train.DisplayDestination))
	    default:
		}
	}
}

func GetDestinationAndTime(start int, messageParts []string, getTime bool) (string, int, error) {
	var dest bytes.Buffer
	for i := start; i < len(messageParts); i++ {
		if getTime {
			num, err := strconv.Atoi(messageParts[i])
			if err == nil && i == len(messageParts) - 1 {
				return dest.String(), num, nil
			}
		}
		if i > start {
			dest.WriteString(" ")
		}
		dest.WriteString(messageParts[i])
	}
	if !getTime {
		return dest.String(), 0, nil
	}
	return "", 0, fmt.Errorf("Couldn't parse dest and/or time to departure")
}

func Handler(w rest.ResponseWriter, r *rest.Request) {
	var webMsg WebhookMessage
	decoder := json.NewDecoder(r.Body)
	err := decoder.Decode(&webMsg)
	if err != nil {
		log.Printf(err.Error())
		PostMessage(err.Error())
		return
	}

	author := webMsg.Item.MessageStruct.From.MentionName
	insufficientParams := fmt.Sprintf("%v messed up and forgot to provide the sufficient number of params", author)
	messageParts := strings.Split(webMsg.Item.MessageStruct.Message, " ")

	var msg string
	if len(messageParts) < 2 {
		PostMessage(insufficientParams)
		return
	}
	cmd := strings.ToLower(messageParts[1])
	malformed := "Your command is malformed or not found, please view the help message (/train help) for more details"
	notFound := "That train doesn't exist, please try again"
	switch cmd {
	case "help":
		msg = "Usage: /train start <destination> <#minutes> || /train join <destination> || /train passengers <destination>"
		PostMessage(msg)
	case "passengers":
		dest, _, err := GetDestinationAndTime(2, messageParts, false)
		if err != nil {
			PostMessage(err.Error())
			break
		}
		train, ok := station.Trains[strings.ToLower(dest)]
		if !ok {
			PostMessage(notFound)
		} else {
			if len(train.Passengers) == 1 {
				msg = fmt.Sprintf("%v is on the train to %v", train.PassengerString(), train.DisplayDestination)
			} else {
				msg = fmt.Sprintf("%v are on the train to %v", train.PassengerString(), train.DisplayDestination)
			}
			PostMessage(msg)
		}
	case "join":
		dest, _, err := GetDestinationAndTime(2, messageParts, false)
		if err != nil {
			PostMessage(err.Error())
			break
		}
		train, ok := station.Trains[strings.ToLower(dest)]
		if ok {
			err := train.NewPassenger(author)
			if err == nil {
				msg = fmt.Sprintf("%s jumped on the train to %s", author, train.DisplayDestination)
				PostMessage(msg)
			} else {
				msg = err.Error()
				PostMessage(msg)
			}
		} else {
			PostMessage(notFound)
		}
	case "start":
		dest, length, err := GetDestinationAndTime(2, messageParts, true)
		if err != nil {
			PostMessage(malformed)
			break
		}
		if length <= 0 {
			msg = fmt.Sprintf("Please specify a time greater than 0 mins")
			PostMessage(msg)
			break
		}
		_, ok := station.Trains[strings.ToLower(dest)]
		if ok {
			msg = fmt.Sprintf("There's already a train to %v!", dest)
			PostMessage(msg)
			break
		} else {
			train := NewTrain(author, length, dest)
			err = station.AddTrain(train)
			if err != nil {
				PostMessage(err.Error())
				break
			} else {
				msg = fmt.Sprintf("%s has started a train to %v that leaves in %v minutes!", author, train.DisplayDestination, length)
				PostMessage(msg)
				go MonitorTrain(train)
			}
		}
	default:
		PostMessage(malformed)
	}
}

func ValidityHandler(w rest.ResponseWriter, r *rest.Request) {
	str := "Everything is OK!"
	w.WriteJson(&str)
}

func main() {
   	api := rest.NewApi()
    api.Use(rest.DefaultDevStack...)

    router, err := rest.MakeRouter(
  		rest.Get("/", ValidityHandler),
    	rest.Post("/train", Handler),
    )

    api.SetApp(router)
    ip := os.Getenv("OPENSHIFT_GO_IP")
    port := os.Getenv("OPENSHIFT_GO_PORT")
    if port == "" {
    	port = "8080"
    }
    bind := fmt.Sprintf("%s:%s",ip,port)
	err = http.ListenAndServe(bind, api.MakeHandler())
	if err != nil {
    	log.Println(err)
    }
}<commit_msg>Add support for getting a list of active trains<commit_after>package main

import (
    "github.com/ant0ine/go-json-rest/rest"
    "github.com/tbruyelle/hipchat-go/hipchat"
    "bytes"
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "os"
    "strconv"
    "strings"
    "sync"
    "time"
)

/*
To-do list
---------
Manually depart a train
Derail a train
Start a train at a designated time
Tag people when the train leaves
Propose a train that starts if enough people join -> X
-----
Keep track of usage statistics
Look into making your own log to log things

53 so far
Look into moving to AWS
*/

var authKey string = ""
var roomName string = ""

var station *Station = &Station{
	Lock: &sync.Mutex{},
	Trains: make(map[string]*Train),
}

type WebhookMessage struct {
    Item struct {
        MessageStruct struct {
        	From struct {
        		MentionName string `json:"mention_name"`
        	}
        	Message string `json:"message"`
        } `json:"message"`

    }  `json:"item"`
}

type Train struct {
	Lock *sync.Mutex
	LeavingTimer *time.Timer
	ReminderTimer *time.Timer
	MapDestination string
	DisplayDestination string
	Passengers []string
	PassengerSet map[string]struct{}
}

func NewTrain(conductor string, departure int, dest string) *Train {
	timer := time.NewTimer(time.Minute * time.Duration(departure))
	timer2 := time.NewTimer(time.Minute * time.Duration(departure - 1))
	users := []string{conductor}
	trainMap := make(map[string]struct{})
	trainMap[conductor] = struct{}{}
	return &Train{
		Lock: &sync.Mutex{},
		LeavingTimer: timer,
		ReminderTimer: timer2,
		MapDestination: strings.ToLower(dest),
		DisplayDestination: dest,
		Passengers: users,
		PassengerSet: trainMap,
	}
}

func (t *Train) NewPassenger(pass string) error {
	t.Lock.Lock()
	defer t.Lock.Unlock()
	_, ok := t.PassengerSet[pass]
	if !ok {
		t.PassengerSet[pass] = struct{}{}
		t.Passengers = append(t.Passengers, pass)
		return nil
	} else {
		log.Printf("Passenger %s is already on the train\n", pass)
		return fmt.Errorf("Passenger %s is already on the train", pass)
	}
}

func (t *Train) PassengerString() string {
	t.Lock.Lock()
	defer t.Lock.Unlock()
	var buffer bytes.Buffer
	for i, v := range t.Passengers {
	   buffer.WriteString(v)
	   if i != len(t.Passengers) - 1 {
	    	buffer.WriteString(", ")
	    }
	   if i == len(t.Passengers) - 2 {
	    	buffer.WriteString("and ")
	   }
	}
	return buffer.String()

}

type Station struct {
	Lock *sync.Mutex
	Trains map[string]*Train
}

func (s *Station) AddTrain(t *Train) error {
	s.Lock.Lock()
	defer s.Lock.Unlock()
	_, ok := s.Trains[t.MapDestination]
	if !ok {
		s.Trains[t.MapDestination] = t
		return nil
	} else {
		log.Printf("Train to %s already exists", t.DisplayDestination)
		return fmt.Errorf("Train to %s already exists", t.DisplayDestination)
	}
}

func (s *Station) DeleteTrain(dest string) error {
	s.Lock.Lock()
	defer s.Lock.Unlock()
	_, ok := s.Trains[dest]
	if ok {
		 delete(s.Trains, dest)
		 return nil
	} else {
		log.Printf("The train to %s doesn't exist so it can't be removed", dest)
		return fmt.Errorf("The train to %s doesn't exist so it can't be removed", dest)
	}
}

func PostMessage(msg string) {
	c := hipchat.NewClient(authKey)
	msgReq := &hipchat.NotificationRequest{Message: msg}
	_, err := c.Room.Notification(roomName, msgReq)
	if err != nil {
		panic(err)
	}
}

func MonitorTrain(train *Train) {
	for {
		select {
	    case <- train.LeavingTimer.C:
	    	var buffer bytes.Buffer
	    	start := fmt.Sprintf("The train to %v has left the station with ", train.DisplayDestination)
	    	buffer.WriteString(start)
	    	buffer.WriteString(train.PassengerString())
	    	buffer.WriteString(" on it!")
	    	PostMessage(buffer.String())
	    	station.DeleteTrain(train.MapDestination)
	    	return
	    case <- train.ReminderTimer.C:
            PostMessage(fmt.Sprintf("Reminder, the next train to %v leaves in one minute", train.DisplayDestination))
	    default:
		}
	}
}

func GetDestinationAndTime(start int, messageParts []string, getTime bool) (string, int, error) {
	var dest bytes.Buffer
	for i := start; i < len(messageParts); i++ {
		if getTime {
			num, err := strconv.Atoi(messageParts[i])
			if err == nil && i == len(messageParts) - 1 {
				return dest.String(), num, nil
			}
		}
		if i > start {
			dest.WriteString(" ")
		}
		dest.WriteString(messageParts[i])
	}
	if !getTime {
		return dest.String(), 0, nil
	}
	return "", 0, fmt.Errorf("Couldn't parse dest and/or time to departure")
}

func Handler(w rest.ResponseWriter, r *rest.Request) {
	var webMsg WebhookMessage
	decoder := json.NewDecoder(r.Body)
	err := decoder.Decode(&webMsg)
	if err != nil {
		log.Printf(err.Error())
		PostMessage(err.Error())
		return
	}

	author := webMsg.Item.MessageStruct.From.MentionName
	insufficientParams := fmt.Sprintf("%v messed up and forgot to provide the sufficient number of params", author)
	messageParts := strings.Split(webMsg.Item.MessageStruct.Message, " ")

	var msg string
	if len(messageParts) < 2 {
		PostMessage(insufficientParams)
		return
	}
	cmd := strings.ToLower(messageParts[1])
	malformed := "Your command is malformed or not found, please view the help message (/train help) for more details"
	notFound := "That train doesn't exist, please try again"
	switch cmd {
	case "help":
		msg = "Usage: /train start <destination> <#minutes> || /train join <destination> || /train passengers <destination> || /train active"
		PostMessage(msg)
	case "passengers":
		dest, _, err := GetDestinationAndTime(2, messageParts, false)
		if err != nil {
			PostMessage(err.Error())
			break
		}
		train, ok := station.Trains[strings.ToLower(dest)]
		if !ok {
			PostMessage(notFound)
		} else {
			if len(train.Passengers) == 1 {
				msg = fmt.Sprintf("%v is on the train to %v", train.PassengerString(), train.DisplayDestination)
			} else {
				msg = fmt.Sprintf("%v are on the train to %v", train.PassengerString(), train.DisplayDestination)
			}
			PostMessage(msg)
		}
	case "join":
		dest, _, err := GetDestinationAndTime(2, messageParts, false)
		if err != nil {
			PostMessage(err.Error())
			break
		}
		train, ok := station.Trains[strings.ToLower(dest)]
		if ok {
			err := train.NewPassenger(author)
			if err == nil {
				msg = fmt.Sprintf("%s jumped on the train to %s", author, train.DisplayDestination)
				PostMessage(msg)
			} else {
				msg = err.Error()
				PostMessage(msg)
			}
		} else {
			PostMessage(notFound)
		}
	case "start":
		dest, length, err := GetDestinationAndTime(2, messageParts, true)
		if err != nil {
			PostMessage(malformed)
			break
		}
		if length <= 0 {
			msg = fmt.Sprintf("Please specify a time greater than 0 mins")
			PostMessage(msg)
			break
		}
		_, ok := station.Trains[strings.ToLower(dest)]
		if ok {
			msg = fmt.Sprintf("There's already a train to %v!", dest)
			PostMessage(msg)
			break
		} else {
			train := NewTrain(author, length, dest)
			err = station.AddTrain(train)
			if err != nil {
				PostMessage(err.Error())
				break
			} else {
				msg = fmt.Sprintf("%s has started a train to %v that leaves in %v minutes!", author, train.DisplayDestination, length)
				PostMessage(msg)
				go MonitorTrain(train)
			}
		}
	case "active":
		if len(messageParts) != 2 {
			PostMessage(malformed)
			break
		}
		if len(station.Trains) == 0 {
			msg = fmt.Sprintf("There are currently no active trains")
			PostMessage(msg)
		} else {
			var finalMsg bytes.Buffer
			finalMsg.WriteString("There are trains to: ")
			i := 0
			for _, v := range station.Trains {
				if len(station.Trains) == 1 {
					msg = fmt.Sprintf("There is currently a train to %v (with %v on it)", v.DisplayDestination, v.PassengerString())
					PostMessage(msg)
					return
				} else {
					finalMsg.WriteString(fmt.Sprintf("%v (with %v on it)", v.DisplayDestination, v.PassengerString()))
				}
				if i == len(station.Trains) - 2 {
					finalMsg.WriteString("and ")
	 		    }
				if i != len(station.Trains) - 1 {
					finalMsg.WriteString(", ")
				}
				i++

			}
			PostMessage(finalMsg.String())
		}
	default:
		PostMessage(malformed)
	}
}

func ValidityHandler(w rest.ResponseWriter, r *rest.Request) {
	str := "Everything is OK!"
	w.WriteJson(&str)
}

func main() {
   	api := rest.NewApi()
    api.Use(rest.DefaultDevStack...)

    router, err := rest.MakeRouter(
  		rest.Get("/", ValidityHandler),
    	rest.Post("/train", Handler),
    )

    api.SetApp(router)
    ip := os.Getenv("OPENSHIFT_GO_IP")
    port := os.Getenv("OPENSHIFT_GO_PORT")
    if port == "" {
    	port = "8080"
    }
    bind := fmt.Sprintf("%s:%s",ip,port)
	err = http.ListenAndServe(bind, api.MakeHandler())
	if err != nil {
    	log.Println(err)
    }
}<|endoftext|>


<commit_before>package dynamodb

import (
	"sync"
	"time"

	"github.com/Clever/leakybucket"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/dynamodb"
)

var _ leakybucket.Bucket = &bucket{}

type bucket struct {
	name                string
	capacity, remaining uint
	reset               time.Time
	rate                time.Duration
	db                  bucketDB
	mutex               sync.Mutex
}

// Capacity ...
func (b *bucket) Capacity() uint {
	return b.capacity
}

// Remaining space in the bucket.
func (b *bucket) Remaining() uint {
	return b.remaining
}

// Reset returns when the bucket will be drained.
func (b *bucket) Reset() time.Time {
	return b.reset
}

// Add to the bucket.
func (b *bucket) Add(amount uint) (leakybucket.BucketState, error) {
	b.mutex.Lock()
	defer b.mutex.Unlock()
	// Storage.Create guarantees the DB Bucket with a configured TTL. For long running executions it
	// is possible old buckets will get deleted, so we use `findOrCreate` rather than `bucket`
	dbBucket, err := b.db.findOrCreateBucket(b.name, b.rate)
	if err != nil {
		return b.state(), err
	}
	if dbBucket.expired() {
		dbBucket, err = b.db.resetBucket(*dbBucket, b.rate)
		if err != nil {
			return b.state(), err
		}
	}
	// update local state
	b.remaining = b.capacity - min(dbBucket.Value, b.capacity)
	b.reset = dbBucket.Expiration
	if amount > b.remaining {
		return b.state(), leakybucket.ErrorFull
	}
	updatedDBBucket, err := b.db.incrementBucketValue(b.name, amount, b.capacity)
	if err != nil {
		if err == errBucketCapacityExceeded {
			return b.state(), leakybucket.ErrorFull
		}
		return b.state(), err
	}
	// ensure we can't overflow
	b.remaining = b.capacity - min(updatedDBBucket.Value, b.capacity)
	return b.state(), nil
}

func (b *bucket) state() leakybucket.BucketState {
	return leakybucket.BucketState{
		Capacity:  b.Capacity(),
		Remaining: b.Remaining(),
		Reset:     b.Reset(),
	}
}

var _ leakybucket.Storage = &Storage{}

// Storage is a dyanamodb-based, thread-safe leaky bucket factory.
type Storage struct {
	db bucketDB
}

// Create a bucket. It will determine the current state of the bucket based on:
// - The corresponding bucket in the database
// - From scratch using the values provided
func (s *Storage) Create(name string, capacity uint, rate time.Duration) (leakybucket.Bucket, error) {
	bucket := &bucket{
		name:      name,
		capacity:  capacity,
		remaining: capacity,
		reset:     time.Now().Add(rate),
		rate:      rate,
		db:        s.db,
	}
	dbBucket, err := s.db.findOrCreateBucket(name, rate)
	if err != nil {
		return nil, err
	}
	// guarantee the bucket is in a good state
	if dbBucket.expired() {
		// adding 0 will reset the persisted bucket
		if _, err := bucket.Add(0); err != nil {
			return nil, err
		}
	}
	bucket.remaining = max(capacity-dbBucket.Value, 0)
	bucket.reset = dbBucket.Expiration

	return bucket, nil
}

// New initializes the connection to dynamodb
func New(tableName string, s *session.Session, itemTTL time.Duration) (*Storage, error) {
	ddb := dynamodb.New(s)

	db := bucketDB{
		ddb:       ddb,
		tableName: tableName,
		ttl:       itemTTL,
	}

	// fail early if the table doesn't exist or we have any other issues with the DynamoDB API
	if _, err := ddb.DescribeTable(&dynamodb.DescribeTableInput{
		TableName: aws.String(tableName),
	}); err != nil {
		return nil, err
	}

	return &Storage{
		db: db,
	}, nil
}

func max(a, b uint) uint {
	if a > b {
		return a
	}
	return b
}

func min(a, b uint) uint {
	if a < b {
		return a
	}
	return b
}
<commit_msg>package doc. comment for New<commit_after>/*
Package dynamodb provides a leaky bucket implementation backed by AWS DynamoDB

For additional details please refer to: https://github.com/Clever/leakybucket/tree/master/dynamodb
*/
package dynamodb

import (
	"sync"
	"time"

	"github.com/Clever/leakybucket"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/dynamodb"
)

var _ leakybucket.Bucket = &bucket{}

type bucket struct {
	name                string
	capacity, remaining uint
	reset               time.Time
	rate                time.Duration
	db                  bucketDB
	mutex               sync.Mutex
}

// Capacity ...
func (b *bucket) Capacity() uint {
	return b.capacity
}

// Remaining space in the bucket.
func (b *bucket) Remaining() uint {
	return b.remaining
}

// Reset returns when the bucket will be drained.
func (b *bucket) Reset() time.Time {
	return b.reset
}

// Add to the bucket.
func (b *bucket) Add(amount uint) (leakybucket.BucketState, error) {
	b.mutex.Lock()
	defer b.mutex.Unlock()
	// Storage.Create guarantees the DB Bucket with a configured TTL. For long running executions it
	// is possible old buckets will get deleted, so we use `findOrCreate` rather than `bucket`
	dbBucket, err := b.db.findOrCreateBucket(b.name, b.rate)
	if err != nil {
		return b.state(), err
	}
	if dbBucket.expired() {
		dbBucket, err = b.db.resetBucket(*dbBucket, b.rate)
		if err != nil {
			return b.state(), err
		}
	}
	// update local state
	b.remaining = b.capacity - min(dbBucket.Value, b.capacity)
	b.reset = dbBucket.Expiration
	if amount > b.remaining {
		return b.state(), leakybucket.ErrorFull
	}
	updatedDBBucket, err := b.db.incrementBucketValue(b.name, amount, b.capacity)
	if err != nil {
		if err == errBucketCapacityExceeded {
			return b.state(), leakybucket.ErrorFull
		}
		return b.state(), err
	}
	// ensure we can't overflow
	b.remaining = b.capacity - min(updatedDBBucket.Value, b.capacity)
	return b.state(), nil
}

func (b *bucket) state() leakybucket.BucketState {
	return leakybucket.BucketState{
		Capacity:  b.Capacity(),
		Remaining: b.Remaining(),
		Reset:     b.Reset(),
	}
}

var _ leakybucket.Storage = &Storage{}

// Storage is a dyanamodb-based, thread-safe leaky bucket factory.
type Storage struct {
	db bucketDB
}

// Create a bucket. It will determine the current state of the bucket based on:
// - The corresponding bucket in the database
// - From scratch using the values provided
func (s *Storage) Create(name string, capacity uint, rate time.Duration) (leakybucket.Bucket, error) {
	bucket := &bucket{
		name:      name,
		capacity:  capacity,
		remaining: capacity,
		reset:     time.Now().Add(rate),
		rate:      rate,
		db:        s.db,
	}
	dbBucket, err := s.db.findOrCreateBucket(name, rate)
	if err != nil {
		return nil, err
	}
	// guarantee the bucket is in a good state
	if dbBucket.expired() {
		// adding 0 will reset the persisted bucket
		if _, err := bucket.Add(0); err != nil {
			return nil, err
		}
	}
	bucket.remaining = max(capacity-dbBucket.Value, 0)
	bucket.reset = dbBucket.Expiration

	return bucket, nil
}

// New initializes the a new bucket storage factory backed by dynamodb. We recommend the session is
// configured with minimal or no retries for a real time use case. Additionally, we recommend
// itemTTL >>> any rate provided in Storage.Create
func New(tableName string, s *session.Session, itemTTL time.Duration) (*Storage, error) {
	ddb := dynamodb.New(s)

	db := bucketDB{
		ddb:       ddb,
		tableName: tableName,
		ttl:       itemTTL,
	}

	// fail early if the table doesn't exist or we have any other issues with the DynamoDB API
	if _, err := ddb.DescribeTable(&dynamodb.DescribeTableInput{
		TableName: aws.String(tableName),
	}); err != nil {
		return nil, err
	}

	return &Storage{
		db: db,
	}, nil
}

func max(a, b uint) uint {
	if a > b {
		return a
	}
	return b
}

func min(a, b uint) uint {
	if a < b {
		return a
	}
	return b
}
<|endoftext|>


<commit_before>package lib

import (
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"net/http"
	"reflect"
	"testing"
)

func TestGetVLANS(t *testing.T) {
	testVLANs := []*brain.VLAN{
		{
			ID:        90210,
			Num:       123,
			UsageType: "recipes",
			IPRanges: []*brain.IPRange{
				{
					ID:      1234,
					Spec:    "192.168.13.0/24",
					VLANNum: 123,
					Zones: []string{
						"test-zone",
					},
					Available: 200.0,
				},
			},
		},
	}
	client, servers, err := mkTestClientAndServers(t, MuxHandlers{
		brain: Mux{
			"/admin/vlans": func(wr http.ResponseWriter, r *http.Request) {
				assertMethod(t, r, "GET")
				writeJSON(t, wr, testVLANs)
			},
		},
	})
	defer servers.Close()
	if err != nil {
		t.Fatal(err)
	}
	err = client.AuthWithCredentials(map[string]string{})
	if err != nil {
		t.Fatal(err)
	}

	vlans, err := client.GetVLANs()
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(vlans, testVLANs) {
		t.Errorf("VLANs returned from GetVLANs were not what was expected.\r\nExpected: %#v\r\nActual:%#v", testVLANs, vlans)
	}
}

func TestGetIPRanges(t *testing.T) {
	testIPRanges := []*brain.IPRange{
		{
			ID:      1234,
			Spec:    "192.168.13.0/24",
			VLANNum: 123,
			Zones: []string{
				"test-zone",
			},
			Available: 200.0,
		},
	}
	client, servers, err := mkTestClientAndServers(t, MuxHandlers{
		brain: Mux{
			"/admin/ip_ranges": func(wr http.ResponseWriter, r *http.Request) {
				assertMethod(t, r, "GET")
				writeJSON(t, wr, testIPRanges)
			},
		},
	})
	defer servers.Close()
	if err != nil {
		t.Fatal(err)
	}
	err = client.AuthWithCredentials(map[string]string{})
	if err != nil {
		t.Fatal(err)
	}

	ipranges, err := client.GetIPRanges()
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(ipranges, testIPRanges) {
		t.Errorf("IPRanges returned from GetIPRanges were not what was expected.\r\nExpected: %#v\r\nActual:%#v", testIPRanges, ipranges)
	}
}

func TestGetIPRange(t *testing.T) {
	testIPRange := brain.IPRange{
		ID:      1234,
		Spec:    "192.168.13.0/24",
		VLANNum: 123,
		Zones: []string{
			"test-zone",
		},
		Available: 200.0,
	}
	client, servers, err := mkTestClientAndServers(t, MuxHandlers{
		brain: Mux{
			"/admin/ip_ranges/1234": func(wr http.ResponseWriter, r *http.Request) {
				assertMethod(t, r, "GET")
				writeJSON(t, wr, testIPRange)
			},
		},
	})
	defer servers.Close()
	if err != nil {
		t.Fatal(err)
	}
	err = client.AuthWithCredentials(map[string]string{})
	if err != nil {
		t.Fatal(err)
	}

	iprange, err := client.GetIPRange(1234)
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(iprange, &testIPRange) {
		t.Errorf("IPRange returned from GetIPRange was not what was expected.\r\nExpected: %#v\r\nActual:%#v", testIPRange, iprange)
	}
}
<commit_msg>Add TestGetHeads<commit_after>package lib

import (
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"net"
	"net/http"
	"reflect"
	"testing"
)

func TestGetVLANS(t *testing.T) {
	testVLANs := []*brain.VLAN{
		{
			ID:        90210,
			Num:       123,
			UsageType: "recipes",
			IPRanges: []*brain.IPRange{
				{
					ID:      1234,
					Spec:    "192.168.13.0/24",
					VLANNum: 123,
					Zones: []string{
						"test-zone",
					},
					Available: 200.0,
				},
			},
		},
	}
	client, servers, err := mkTestClientAndServers(t, MuxHandlers{
		brain: Mux{
			"/admin/vlans": func(wr http.ResponseWriter, r *http.Request) {
				assertMethod(t, r, "GET")
				writeJSON(t, wr, testVLANs)
			},
		},
	})
	defer servers.Close()
	if err != nil {
		t.Fatal(err)
	}
	err = client.AuthWithCredentials(map[string]string{})
	if err != nil {
		t.Fatal(err)
	}

	vlans, err := client.GetVLANs()
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(vlans, testVLANs) {
		t.Errorf("VLANs returned from GetVLANs were not what was expected.\r\nExpected: %#v\r\nActual:%#v", testVLANs, vlans)
	}
}

func TestGetIPRanges(t *testing.T) {
	testIPRanges := []*brain.IPRange{
		{
			ID:      1234,
			Spec:    "192.168.13.0/24",
			VLANNum: 123,
			Zones: []string{
				"test-zone",
			},
			Available: 200.0,
		},
	}
	client, servers, err := mkTestClientAndServers(t, MuxHandlers{
		brain: Mux{
			"/admin/ip_ranges": func(wr http.ResponseWriter, r *http.Request) {
				assertMethod(t, r, "GET")
				writeJSON(t, wr, testIPRanges)
			},
		},
	})
	defer servers.Close()
	if err != nil {
		t.Fatal(err)
	}
	err = client.AuthWithCredentials(map[string]string{})
	if err != nil {
		t.Fatal(err)
	}

	ipranges, err := client.GetIPRanges()
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(ipranges, testIPRanges) {
		t.Errorf("IPRanges returned from GetIPRanges were not what was expected.\r\nExpected: %#v\r\nActual:%#v", testIPRanges, ipranges)
	}
}

func TestGetIPRange(t *testing.T) {
	testIPRange := brain.IPRange{
		ID:      1234,
		Spec:    "192.168.13.0/24",
		VLANNum: 123,
		Zones: []string{
			"test-zone",
		},
		Available: 200.0,
	}
	client, servers, err := mkTestClientAndServers(t, MuxHandlers{
		brain: Mux{
			"/admin/ip_ranges/1234": func(wr http.ResponseWriter, r *http.Request) {
				assertMethod(t, r, "GET")
				writeJSON(t, wr, testIPRange)
			},
		},
	})
	defer servers.Close()
	if err != nil {
		t.Fatal(err)
	}
	err = client.AuthWithCredentials(map[string]string{})
	if err != nil {
		t.Fatal(err)
	}

	iprange, err := client.GetIPRange(1234)
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(iprange, &testIPRange) {
		t.Errorf("IPRange returned from GetIPRange was not what was expected.\r\nExpected: %#v\r\nActual:%#v", testIPRange, iprange)
	}
}
func TestGetHeads(t *testing.T) {
	testHeads := []*brain.Head{
		{
			ID:       315,
			UUID:     "234833-2493-3423-324235",
			Label:    "test-head315",
			ZoneName: "awesomecoolguyzone",

			Architecture:  "x86_64",
			CCAddress:     &net.IP{214, 233, 32, 31},
			Note:          "melons",
			Memory:        241000,
			UsageStrategy: "",
			Models:        []string{"generic", "intel"},

			MemoryFree:          123400,
			IsOnline:            true,
			UsedCores:           9,
			VirtualMachineCount: 3,
		}, {
			ID:       239,
			UUID:     "235670-2493-3423-324235",
			Label:    "test-head239",
			ZoneName: "awesomecoolguyzone",

			Architecture:  "x86_64",
			CCAddress:     &net.IP{24, 43, 32, 49},
			Note:          "more than a hundred years old",
			Memory:        241000,
			UsageStrategy: "",
			Models:        []string{"generic", "intel"},

			MemoryFree:          234000,
			IsOnline:            true,
			UsedCores:           1,
			VirtualMachineCount: 1,
		},
	}
	client, servers, err := mkTestClientAndServers(t, MuxHandlers{
		brain: Mux{
			"/admin/heads": func(wr http.ResponseWriter, r *http.Request) {
				assertMethod(t, r, "GET")
				writeJSON(t, wr, testHeads)
			},
		},
	})
	defer servers.Close()
	if err != nil {
		t.Fatal(err)
	}

	err = client.AuthWithCredentials(map[string]string{})
	if err != nil {
		t.Fatal(err)
	}

	heads, err := client.GetHeads()
	if err != nil {
		t.Error(err)
	}
	seenFirst := false
	seenSecond := false
	for _, h := range heads {
		if h.Label == testHeads[0].Label {
			seenFirst = true
		}
		if h.Label == testHeads[1].Label {
			seenSecond = true
		}
	}
	if !seenFirst {
		t.Errorf("didn't see %s", testHeads[0].Label)
	} else if !seenSecond {
		t.Errorf("didn't see %s", testHeads[1].Label)
	}
}
<|endoftext|>


<commit_before>// Package aes provides simple wrappers for encrypting and decrypting with
// AES256 and Galois Counter Mode (GCM) as AEAD.
package aes

import (
	"crypto/aes"
	"crypto/cipher"
)

// EncryptAesGcm encrypts a byte slice with the given 256bit key
// and nonce using Galois Conter Mode as AEAD.
// The nonce has to be 12 bytes long and will be prepended to the ciphertext.
func EncryptAesGcm(key []byte, nonce []byte, msg []byte) []byte {
	block, err := aes.NewCipher(key)
	check(err)

	aesGcm, err := cipher.NewGCM(block)
	check(err)

	ciphertext := aesGcm.Seal(nil, nonce, msg, nil)
	ciphertext = append(nonce, ciphertext...)

	return ciphertext
}

// DecryptAesGcm decrypts a byte slice that has been encrypted with
// EncryptAesGcm.
func DecryptAesGcm(key []byte, msg []byte) []byte {
	block, err := aes.NewCipher(key)
	check(err)

	aesGcm, err := cipher.NewGCM(block)
	check(err)

	plaintext, err := aesGcm.Open(nil, msg[:12], msg[12:], nil)
	check(err)

	return plaintext
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>Update aes.go<commit_after>// Package aes provides simple wrappers for encrypting and decrypting with
// AES256 and Galois Counter Mode (GCM) as AEAD.
package aes

import (
	"crypto/aes"
	"crypto/cipher"
)

// EncryptAesGcm encrypts a byte slice with the given 256bit key
// and nonce using Galois Counter Mode as AEAD.
// The nonce has to be 12 bytes long and will be prepended to the ciphertext.
func EncryptAesGcm(key []byte, nonce []byte, msg []byte) []byte {
	block, err := aes.NewCipher(key)
	check(err)

	aesGcm, err := cipher.NewGCM(block)
	check(err)

	ciphertext := aesGcm.Seal(nil, nonce, msg, nil)
	ciphertext = append(nonce, ciphertext...)

	return ciphertext
}

// DecryptAesGcm decrypts a byte slice that has been encrypted with
// EncryptAesGcm.
func DecryptAesGcm(key []byte, msg []byte) []byte {
	block, err := aes.NewCipher(key)
	check(err)

	aesGcm, err := cipher.NewGCM(block)
	check(err)

	plaintext, err := aesGcm.Open(nil, msg[:12], msg[12:], nil)
	check(err)

	return plaintext
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"log"
	"net"
	"runtime"
	"sync"
	"sync/atomic"
	"time"

	"github.com/absolute8511/go-nsq"
)

var (
	runfor     = flag.Duration("runfor", 10*time.Second, "duration of time to run")
	sleepfor   = flag.Duration("sleepfor", 1*time.Second, " time to sleep between pub")
	keepAlive  = flag.Bool("keepalive", true, "keep alive for connection")
	tcpAddress = flag.String("nsqd-tcp-address", "127.0.0.1:4150", "<addr>:<port> to connect to nsqd")
	topic      = flag.String("topic", "sub_bench", "topic to receive messages on")
	size       = flag.Int("size", 200, "size of messages")
	batchSize  = flag.Int("batch-size", 20, "batch size of messages")
	deadline   = flag.String("deadline", "", "deadline to start the benchmark run")
)

var totalMsgCount int64

func main() {
	flag.Parse()
	var wg sync.WaitGroup

	log.SetPrefix("[bench_writer] ")

	msg := make([]byte, *size)
	batch := make([][]byte, *batchSize)
	for i := range batch {
		batch[i] = msg
	}
	conn, err := net.DialTimeout("tcp", *tcpAddress, time.Second)
	if err != nil {
		log.Println(err.Error())
	} else {
		conn.Write(nsq.MagicV2)
		nsq.CreateTopic(*topic, 0).WriteTo(conn)
		resp, err := nsq.ReadResponse(conn)
		if err != nil {
			log.Println(err.Error())
		} else {
			frameType, data, err := nsq.UnpackResponse(resp)
			if err != nil {
				log.Println(err.Error())
			} else if frameType == nsq.FrameTypeError {
				log.Println(string(data))
			}
		}
		conn.Close()
	}

	goChan := make(chan int)
	rdyChan := make(chan int)
	for j := 0; j < runtime.GOMAXPROCS(0); j++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			pubWorker(*runfor, *tcpAddress, *batchSize, batch, *topic, rdyChan, goChan)
		}()
		<-rdyChan
	}

	if *deadline != "" {
		t, err := time.Parse("2006-01-02 15:04:05", *deadline)
		if err != nil {
			log.Fatal(err)
		}
		d := t.Sub(time.Now())
		log.Printf("sleeping until %s (%s)", t, d)
		time.Sleep(d)
	}

	start := time.Now()
	close(goChan)
	wg.Wait()
	end := time.Now()
	duration := end.Sub(start)
	tmc := atomic.LoadInt64(&totalMsgCount)
	log.Printf("duration: %s - %.03fmb/s - %.03fops/s - %.03fus/op",
		duration,
		float64(tmc*int64(*size))/duration.Seconds()/1024/1024,
		float64(tmc)/duration.Seconds(),
		float64(duration/time.Microsecond)/(float64(tmc)+0.01))
}

func checkShouldClose(err error) bool {
	if err != nil {
		log.Printf("err: %v\n", err)
		return true
	}
	return false
}

func pubWorker(td time.Duration, tcpAddr string, batchSize int, batch [][]byte, topic string, rdyChan chan int, goChan chan int) {
	shouldClose := !*keepAlive
	conn, err := net.DialTimeout("tcp", tcpAddr, time.Second)
	if err != nil {
		log.Println(err.Error())
		shouldClose = true
	} else {
		conn.Write(nsq.MagicV2)
	}
	rdyChan <- 1
	<-goChan
	var msgCount int64
	endTime := time.Now().Add(td)
	rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
	for {
		if time.Now().After(endTime) {
			break
		}
		time.Sleep(*sleepfor)
		if shouldClose || !*keepAlive {
			if conn != nil {
				conn.Close()
			}
			conn, err = net.DialTimeout("tcp", tcpAddr, time.Second)
			shouldClose = checkShouldClose(err)
			if shouldClose {
				continue
			}
			_, err = conn.Write(nsq.MagicV2)
			shouldClose = checkShouldClose(err)
			if shouldClose {
				continue
			}
			rw = bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
		}
		conn.SetReadDeadline(time.Now().Add(5 * time.Second))
		cmd, _ := nsq.MultiPublish(topic, batch)
		_, err := cmd.WriteTo(rw)
		shouldClose = checkShouldClose(err)
		if shouldClose {
			continue
		}
		err = rw.Flush()
		shouldClose = checkShouldClose(err)
		if shouldClose {
			continue
		}
		resp, err := nsq.ReadResponse(rw)
		shouldClose = checkShouldClose(err)
		if shouldClose {
			continue
		}
		frameType, data, err := nsq.UnpackResponse(resp)
		shouldClose = checkShouldClose(err)
		if shouldClose {
			continue
		}
		conn.SetReadDeadline(time.Time{})
		if frameType == nsq.FrameTypeError {
			log.Println("frame unexpected:" + string(data))
			shouldClose = true
		}
		msgCount += int64(len(batch))
		if time.Now().After(endTime) {
			break
		}
	}
	atomic.AddInt64(&totalMsgCount, msgCount)
}
<commit_msg>only sleep for 10us above<commit_after>package main

import (
	"bufio"
	"flag"
	"log"
	"net"
	"runtime"
	"sync"
	"sync/atomic"
	"time"

	"github.com/absolute8511/go-nsq"
)

var (
	runfor     = flag.Duration("runfor", 10*time.Second, "duration of time to run")
	sleepfor   = flag.Duration("sleepfor", 1*time.Second, " time to sleep between pub")
	keepAlive  = flag.Bool("keepalive", true, "keep alive for connection")
	tcpAddress = flag.String("nsqd-tcp-address", "127.0.0.1:4150", "<addr>:<port> to connect to nsqd")
	topic      = flag.String("topic", "sub_bench", "topic to receive messages on")
	size       = flag.Int("size", 200, "size of messages")
	batchSize  = flag.Int("batch-size", 20, "batch size of messages")
	deadline   = flag.String("deadline", "", "deadline to start the benchmark run")
)

var totalMsgCount int64

func main() {
	flag.Parse()
	var wg sync.WaitGroup

	log.SetPrefix("[bench_writer] ")

	msg := make([]byte, *size)
	batch := make([][]byte, *batchSize)
	for i := range batch {
		batch[i] = msg
	}
	conn, err := net.DialTimeout("tcp", *tcpAddress, time.Second)
	if err != nil {
		log.Println(err.Error())
	} else {
		conn.Write(nsq.MagicV2)
		nsq.CreateTopic(*topic, 0).WriteTo(conn)
		resp, err := nsq.ReadResponse(conn)
		if err != nil {
			log.Println(err.Error())
		} else {
			frameType, data, err := nsq.UnpackResponse(resp)
			if err != nil {
				log.Println(err.Error())
			} else if frameType == nsq.FrameTypeError {
				log.Println(string(data))
			}
		}
		conn.Close()
	}

	goChan := make(chan int)
	rdyChan := make(chan int)
	for j := 0; j < runtime.GOMAXPROCS(0); j++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			pubWorker(*runfor, *tcpAddress, *batchSize, batch, *topic, rdyChan, goChan)
		}()
		<-rdyChan
	}

	if *deadline != "" {
		t, err := time.Parse("2006-01-02 15:04:05", *deadline)
		if err != nil {
			log.Fatal(err)
		}
		d := t.Sub(time.Now())
		log.Printf("sleeping until %s (%s)", t, d)
		time.Sleep(d)
	}

	start := time.Now()
	close(goChan)
	wg.Wait()
	end := time.Now()
	duration := end.Sub(start)
	tmc := atomic.LoadInt64(&totalMsgCount)
	log.Printf("duration: %s - %.03fmb/s - %.03fops/s - %.03fus/op",
		duration,
		float64(tmc*int64(*size))/duration.Seconds()/1024/1024,
		float64(tmc)/duration.Seconds(),
		float64(duration/time.Microsecond)/(float64(tmc)+0.01))
}

func checkShouldClose(err error) bool {
	if err != nil {
		log.Printf("err: %v\n", err)
		return true
	}
	return false
}

func pubWorker(td time.Duration, tcpAddr string, batchSize int, batch [][]byte, topic string, rdyChan chan int, goChan chan int) {
	shouldClose := !*keepAlive
	conn, err := net.DialTimeout("tcp", tcpAddr, time.Second)
	if err != nil {
		log.Println(err.Error())
		shouldClose = true
	} else {
		conn.Write(nsq.MagicV2)
	}
	rdyChan <- 1
	<-goChan
	var msgCount int64
	endTime := time.Now().Add(td)
	rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
	for {
		if time.Now().After(endTime) {
			break
		}
		if (*sleepfor).Nanoseconds() > int64(10000) {
			time.Sleep(*sleepfor)
		}
		if shouldClose || !*keepAlive {
			if conn != nil {
				conn.Close()
			}
			conn, err = net.DialTimeout("tcp", tcpAddr, time.Second)
			shouldClose = checkShouldClose(err)
			if shouldClose {
				continue
			}
			_, err = conn.Write(nsq.MagicV2)
			shouldClose = checkShouldClose(err)
			if shouldClose {
				continue
			}
			rw = bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
		}
		conn.SetReadDeadline(time.Now().Add(5 * time.Second))
		cmd, _ := nsq.MultiPublish(topic, batch)
		_, err := cmd.WriteTo(rw)
		shouldClose = checkShouldClose(err)
		if shouldClose {
			continue
		}
		err = rw.Flush()
		shouldClose = checkShouldClose(err)
		if shouldClose {
			continue
		}
		resp, err := nsq.ReadResponse(rw)
		shouldClose = checkShouldClose(err)
		if shouldClose {
			continue
		}
		frameType, data, err := nsq.UnpackResponse(resp)
		shouldClose = checkShouldClose(err)
		if shouldClose {
			continue
		}
		conn.SetReadDeadline(time.Time{})
		if frameType == nsq.FrameTypeError {
			log.Println("frame unexpected:" + string(data))
			shouldClose = true
		}
		msgCount += int64(len(batch))
		if time.Now().After(endTime) {
			break
		}
	}
	atomic.AddInt64(&totalMsgCount, msgCount)
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"
	"github.com/applariat/go-apl/pkg/apl"
	"github.com/spf13/cobra"
)

// NewDeploymentsOverridesCommand
func NewDeploymentsOverridesCommand() *cobra.Command {

	var componentsMap ComponentStringMap

	cmd := &cobra.Command{
		Use:   "override",
		Short: fmt.Sprintf("Override a component artifact"),
		Long:  "",

		PreRunE: func(cmd *cobra.Command, args []string) error {

			// If there is a file, no other checking is needed
			if isInputFileDefined() {
				return nil
			}

			var missingFlags []string

			if len(componentsMap.Values) <= 0 {
				missingFlags = append(missingFlags, "--component")
			}

			if len(missingFlags) > 0 {
				return fmt.Errorf("Missing required flags: %s", missingFlags)
			}

			return nil
		},

		Run: func(ccmd *cobra.Command, args []string) {
			aplSvc := apl.NewClient()

			in := &apl.DeploymentUpdateInput{}

			if !isInputFileDefined() {

				// Create the []apl.Components
				c := []apl.DeploymentComponent{}
				for _, cmp := range componentsMap.Values {

					artifact := deploymentArtifactFactory(aplSvc, cmp.StackArtifactIDs)

					dc := apl.DeploymentComponent{
						StackComponentID: cmp.StackComponentID,
						Services: []apl.Service{
							{
								Name: cmp.ServiceName,
								Build: apl.Build{
									Artifact: artifact,
								},
								Run: apl.Run{
									Instances: cmp.Instances,
								},
							},
						},
					}

					c = append(c, dc)

				}

				in = &apl.DeploymentUpdateInput{
					Command:    "override",
					Components: c,
				}

			}

			runUpdateCommand(args, in, aplSvc.Deployments.Update)
		},
	}

	cmd.Flags().Var(&componentsMap, "component", componentsMap.Usage())
	return cmd
}
<commit_msg>Fix usage text for DeploymentOverride command<commit_after>package app

import (
	"fmt"
	"github.com/applariat/go-apl/pkg/apl"
	"github.com/spf13/cobra"
)

// NewDeploymentsOverridesCommand
func NewDeploymentsOverridesCommand() *cobra.Command {

	var (
		componentsMap ComponentStringMap
	)

	cmd := &cobra.Command{
		Use:   "override [ID]",
		Short: fmt.Sprintf("Override a component artifact"),
		Long:  "",

		PreRunE: func(cmd *cobra.Command, args []string) error {
			err := checkCommandHasIDInArgs(args, "credential")
			if err != nil {
				return err
			}
			// If there is a file, no other checking is needed
			if isInputFileDefined() {
				return nil
			}

			var missingFlags []string

			if len(componentsMap.Values) <= 0 {
				missingFlags = append(missingFlags, "--component")
			}

			if len(missingFlags) > 0 {
				return fmt.Errorf("Missing required flags: %s", missingFlags)
			}

			return nil
		},

		Run: func(ccmd *cobra.Command, args []string) {
			aplSvc := apl.NewClient()

			in := &apl.DeploymentUpdateInput{}

			if !isInputFileDefined() {

				// Create the []apl.Components
				c := []apl.DeploymentComponent{}
				for _, cmp := range componentsMap.Values {

					artifact := deploymentArtifactFactory(aplSvc, cmp.StackArtifactIDs)

					dc := apl.DeploymentComponent{
						StackComponentID: cmp.StackComponentID,
						Services: []apl.Service{
							{
								Name: cmp.ServiceName,
								Build: apl.Build{
									Artifact: artifact,
								},
								Run: apl.Run{
									Instances: cmp.Instances,
								},
							},
						},
					}

					c = append(c, dc)

				}

				in = &apl.DeploymentUpdateInput{
					Command:    "override",
					Components: c,
				}

			}

			runUpdateCommand(args, in, aplSvc.Deployments.Update)
		},
	}

	cmd.Flags().Var(&componentsMap, "component", componentsMap.Usage())
	return cmd
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/cloudfoundry/bosh-agent/bootstrapper"
	"io/ioutil"
	"os"
)

func main() {
	if len(os.Args) != 4 {
		argv0 := "bootstrapper"
		fmt.Printf("usage: %s <certFile> <keyFile> <caPEM>\n", argv0)
		fmt.Println()
		fmt.Printf("try this: %s bootstrapper/spec/support/certs/bootstrapper.crt bootstrapper/spec/support/certs/bootstrapper.key bootstrapper/spec/support/certs/rootCA.pem\n", argv0)
		os.Exit(1)
	}

	pem, err := ioutil.ReadFile(os.Args[3])
	if err != nil {
		fmt.Printf("main(): %s\n", err)
		os.Exit(1)
	}

	k := &bootstrapper.Bootstrapper{
		CertFile:  os.Args[1],
		KeyFile:   os.Args[2],
		CACertPem: (string)(pem),
	}

	err = k.Listen(4443)
	if err != nil {
		fmt.Printf("main(): %s\n", err)
		os.Exit(1)
	}
	k.WaitForServerToExit()
}
<commit_msg>Add distinguished names as a required parameter<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"github.com/cloudfoundry/bosh-agent/bootstrapper"
)

func main() {
	if len(os.Args) != 5 {
		argv0 := os.Args[0]
		fmt.Printf("ERROR - Wrong number of arguments\n\n")
		fmt.Printf("usage: %s <certFile> <keyFile> <caPEM> <allowed distinguished names>\n", argv0)
		fmt.Println()
		fmt.Printf("try this:\n")
		fmt.Printf("%s \\\n", argv0)
		fmt.Printf("   bootstrapper/spec/support/certs/bootstrapper.crt       \\\n")
		fmt.Printf("   bootstrapper/spec/support/certs/bootstrapper.key       \\\n")
		fmt.Printf("   bootstrapper/spec/support/certs/rootCA.pem             \\\n")
		fmt.Printf("   o=bosh.director\n")
		os.Exit(1)
	}

	certFile := os.Args[1]
	keyFile := os.Args[2]
	pemString := os.Args[3]
	allowedName := os.Args[4]

	pem, err := ioutil.ReadFile(pemString)
	if err != nil {
		fmt.Printf("main(): %s\n", err)
		os.Exit(1)
	}

	k := &bootstrapper.Bootstrapper{
		CertFile:     certFile,
		KeyFile:      keyFile,
		CACertPem:    (string)(pem),
		AllowedNames: []string{allowedName},

		Logger: log.New(os.Stderr, "", log.LstdFlags),
	}

	err = k.Listen(4443)
	if err != nil {
		fmt.Printf("main(): %s\n", err)
		os.Exit(1)
	}
	k.WaitForServerToExit()
}
<|endoftext|>


<commit_before>/*-
Copyright (c) 2016, Jörg Pernfuß <joerg.pernfuss@1und1.de>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package main

import (
	"encoding/hex"
	"sync"
	"time"

	"github.com/mjolnir42/scrypth64"
	"github.com/satori/go.uuid"
)

//
//
// supervisor internal storage format for tokens
type svToken struct {
	validFrom    time.Time
	expiresAt    time.Time
	binToken     []byte
	binExpiresAt []byte
	salt         []byte
}

// read/write locked map of tokens
type svTokenMap struct {
	// token(hex.string) -> svToken
	TMap  map[string]svToken
	mutex sync.RWMutex
}

func (t *svTokenMap) read(token string) *svToken {
	t.rlock()
	defer t.runlock()
	if tok, ok := t.TMap[token]; ok {
		return &tok
	}
	return nil
}

func (t *svTokenMap) insert(token, valid, expires, salt string) error {
	var (
		err                     error
		valTime, expTime        time.Time
		bExpTime, bSalt, bToken []byte
	)
	// convert input data into the different formats required to
	// perform later actions without conversions
	if valTime, err = time.Parse(rfc3339Milli, valid); err != nil {
		return err
	}
	if expTime, err = time.Parse(rfc3339Milli, expires); err != nil {
		return err
	}
	if bExpTime, err = expTime.MarshalBinary(); err != nil {
		return err
	}
	if bToken, err = hex.DecodeString(token); err != nil {
		return err
	}
	if bSalt, err = hex.DecodeString(salt); err != nil {
		return err
	}
	// whiteout unstable subsecond timestamp part with "random" value
	copy(bExpTime[9:], []byte{0xde, 0xad, 0xca, 0xfe})
	// acquire write lock
	t.lock()
	defer t.unlock()

	// insert token
	t.TMap[token] = svToken{
		validFrom:    valTime,
		expiresAt:    expTime,
		binToken:     bToken,
		binExpiresAt: bExpTime,
		salt:         bSalt,
	}
	return nil
}

// set writelock
func (t *svTokenMap) lock() {
	t.mutex.Lock()
}

// set readlock
func (t *svTokenMap) rlock() {
	t.mutex.RLock()
}

// release writelock
func (t *svTokenMap) unlock() {
	t.mutex.Unlock()
}

// release readlock
func (t *svTokenMap) runlock() {
	t.mutex.RUnlock()
}

//
//
// supervisor internal storage format for credentials
type svCredential struct {
	id          uuid.UUID
	validFrom   time.Time
	expiresAt   time.Time
	cryptMCF    scrypth64.Mcf
	resetActive bool
	isActive    bool
}

type svCredMap struct {
	// username -> svCredential
	CMap  map[string]svCredential
	mutex sync.RWMutex
}

func (c *svCredMap) read(user string) *svCredential {
	c.rlock()
	defer c.runlock()
	if cred, ok := c.CMap[user]; ok {
		return &cred
	}
	return nil
}

func (c *svCredMap) insert(user string, uid uuid.UUID, valid, expires time.Time, mcf scrypth64.Mcf) {
	c.lock()
	defer c.unlock()
	c.CMap[user] = svCredential{
		id:          uid,
		validFrom:   valid,
		expiresAt:   expires,
		cryptMCF:    mcf,
		resetActive: false,
		isActive:    true,
	}
}

func (c *svCredMap) restore(user string, uid uuid.UUID, valid, expires time.Time, mcf scrypth64.Mcf, reset, active bool) {
	c.lock()
	defer c.unlock()
	c.CMap[user] = svCredential{
		id:          uid,
		validFrom:   valid,
		expiresAt:   expires,
		cryptMCF:    mcf,
		resetActive: reset,
		isActive:    active,
	}
}

// set writelock
func (c *svCredMap) lock() {
	c.mutex.Lock()
}

// set readlock
func (c *svCredMap) rlock() {
	c.mutex.RLock()
}

// release writelock
func (c *svCredMap) unlock() {
	c.mutex.Unlock()
}

// release readlock
func (c *svCredMap) runlock() {
	c.mutex.RUnlock()
}

//
//
// read/write locked map of key exchanges
type svKexMap struct {
	// kexid(uuid.string) -> auth.Kex
	KMap  map[string]auth.Kex
	mutex sync.RWMutex
}

// the nonce information would normally mean returning
// a copy is problematic, but since these keys are only
// used for one client/server exchange, they are never
// put back
func (k *svKexMap) read(kexRequest string) *auth.Kex {
	k.rlock()
	defer k.runlock()
	if kex, ok := k.KMap[kexRequest]; ok {
		return &kex
	}
	return nil
}

func (k *svKexMap) insert(kex auth.Kex) {
	k.lock()
	defer k.unlock()

	k.KMap[kex.Request.String()] = kex
}

func (k *svKexMap) remove(kexRequest string) {
	k.lock()
	defer k.unlock()

	delete(k.KMap, kexRequest)
}

// set writelock
func (k *svKexMap) lock() {
	k.mutex.Lock()
}

// set readlock
func (k *svKexMap) rlock() {
	k.mutex.RLock()
}

// release writelock
func (k *svKexMap) unlock() {
	k.mutex.Unlock()
}

// release readlock
func (k *svKexMap) runlock() {
	k.mutex.RUnlock()
}

//
//
// read/write locked map of global permissions
type svPermMapGlobal struct {
	// user(uuid.string) -> permission(uuid.string) -> true
	GMap  map[string]map[string]bool
	mutex sync.RWMutex
}

func (g *svPermMapGlobal) lock() {
}

func (g *svPermMapGlobal) rlock() {
}

func (g *svPermMapGlobal) unlock() {
}

func (g *svPermMapGlobal) runlock() {
}

//
//
// read/write locked map of limited permissions
type svPermMapLimited struct {
	// user(uuid.string) -> permission(uuid.string) -> repository(uuid.string)
	LMap  map[string]map[string][]string
	mutex sync.RWMutex
}

func (l *svPermMapLimited) lock() {
}

func (l *svPermMapLimited) rlock() {
}

func (l *svPermMapLimited) unlock() {
}

func (l *svPermMapLimited) runlock() {
}

//
//
// read/write locked permission id map
type svPermMap struct {
	// permission name -> permission uuid
	PMap  map[string]string
	mutex sync.RWMutex
}

func (p *svPermMap) lock() {
}

func (p *svPermMap) rlock() {
}

func (p *svPermMap) unlock() {
}

func (p *svPermMap) runlock() {
}

//
//
// read/write locked user id map
type svUserMap struct {
	// user name -> user uuid
	UMap  map[string]string
	mutex sync.RWMutex
}

func (u *svUserMap) lock() {
}

func (u *svUserMap) rlock() {
}

func (u *svUserMap) unlock() {
}

func (u *svUserMap) runlock() {
}

//
//
// read/write locked team map
type svTeamMap struct {
	// user uuid -> team uuid
	TMap  map[string]string
	mutex sync.RWMutex
}

func (t *svTeamMap) lock() {
}

func (t *svTeamMap) rlock() {
}

func (t *svTeamMap) unlock() {
}

func (t *svTeamMap) runlock() {
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Implement global permission map<commit_after>/*-
Copyright (c) 2016, Jörg Pernfuß <joerg.pernfuss@1und1.de>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package main

import (
	"encoding/hex"
	"sync"
	"time"

	"github.com/mjolnir42/scrypth64"
	"github.com/satori/go.uuid"
)

//
//
// supervisor internal storage format for tokens
type svToken struct {
	validFrom    time.Time
	expiresAt    time.Time
	binToken     []byte
	binExpiresAt []byte
	salt         []byte
}

// read/write locked map of tokens
type svTokenMap struct {
	// token(hex.string) -> svToken
	TMap  map[string]svToken
	mutex sync.RWMutex
}

func (t *svTokenMap) read(token string) *svToken {
	t.rlock()
	defer t.runlock()
	if tok, ok := t.TMap[token]; ok {
		return &tok
	}
	return nil
}

func (t *svTokenMap) insert(token, valid, expires, salt string) error {
	var (
		err                     error
		valTime, expTime        time.Time
		bExpTime, bSalt, bToken []byte
	)
	// convert input data into the different formats required to
	// perform later actions without conversions
	if valTime, err = time.Parse(rfc3339Milli, valid); err != nil {
		return err
	}
	if expTime, err = time.Parse(rfc3339Milli, expires); err != nil {
		return err
	}
	if bExpTime, err = expTime.MarshalBinary(); err != nil {
		return err
	}
	if bToken, err = hex.DecodeString(token); err != nil {
		return err
	}
	if bSalt, err = hex.DecodeString(salt); err != nil {
		return err
	}
	// whiteout unstable subsecond timestamp part with "random" value
	copy(bExpTime[9:], []byte{0xde, 0xad, 0xca, 0xfe})
	// acquire write lock
	t.lock()
	defer t.unlock()

	// insert token
	t.TMap[token] = svToken{
		validFrom:    valTime,
		expiresAt:    expTime,
		binToken:     bToken,
		binExpiresAt: bExpTime,
		salt:         bSalt,
	}
	return nil
}

// set writelock
func (t *svTokenMap) lock() {
	t.mutex.Lock()
}

// set readlock
func (t *svTokenMap) rlock() {
	t.mutex.RLock()
}

// release writelock
func (t *svTokenMap) unlock() {
	t.mutex.Unlock()
}

// release readlock
func (t *svTokenMap) runlock() {
	t.mutex.RUnlock()
}

//
//
// supervisor internal storage format for credentials
type svCredential struct {
	id          uuid.UUID
	validFrom   time.Time
	expiresAt   time.Time
	cryptMCF    scrypth64.Mcf
	resetActive bool
	isActive    bool
}

type svCredMap struct {
	// username -> svCredential
	CMap  map[string]svCredential
	mutex sync.RWMutex
}

func (c *svCredMap) read(user string) *svCredential {
	c.rlock()
	defer c.runlock()
	if cred, ok := c.CMap[user]; ok {
		return &cred
	}
	return nil
}

func (c *svCredMap) insert(user string, uid uuid.UUID, valid, expires time.Time, mcf scrypth64.Mcf) {
	c.lock()
	defer c.unlock()
	c.CMap[user] = svCredential{
		id:          uid,
		validFrom:   valid,
		expiresAt:   expires,
		cryptMCF:    mcf,
		resetActive: false,
		isActive:    true,
	}
}

func (c *svCredMap) restore(user string, uid uuid.UUID, valid, expires time.Time, mcf scrypth64.Mcf, reset, active bool) {
	c.lock()
	defer c.unlock()
	c.CMap[user] = svCredential{
		id:          uid,
		validFrom:   valid,
		expiresAt:   expires,
		cryptMCF:    mcf,
		resetActive: reset,
		isActive:    active,
	}
}

// set writelock
func (c *svCredMap) lock() {
	c.mutex.Lock()
}

// set readlock
func (c *svCredMap) rlock() {
	c.mutex.RLock()
}

// release writelock
func (c *svCredMap) unlock() {
	c.mutex.Unlock()
}

// release readlock
func (c *svCredMap) runlock() {
	c.mutex.RUnlock()
}

//
//
// read/write locked map of key exchanges
type svKexMap struct {
	// kexid(uuid.string) -> auth.Kex
	KMap  map[string]auth.Kex
	mutex sync.RWMutex
}

// the nonce information would normally mean returning
// a copy is problematic, but since these keys are only
// used for one client/server exchange, they are never
// put back
func (k *svKexMap) read(kexRequest string) *auth.Kex {
	k.rlock()
	defer k.runlock()
	if kex, ok := k.KMap[kexRequest]; ok {
		return &kex
	}
	return nil
}

func (k *svKexMap) insert(kex auth.Kex) {
	k.lock()
	defer k.unlock()

	k.KMap[kex.Request.String()] = kex
}

func (k *svKexMap) remove(kexRequest string) {
	k.lock()
	defer k.unlock()

	delete(k.KMap, kexRequest)
}

// set writelock
func (k *svKexMap) lock() {
	k.mutex.Lock()
}

// set readlock
func (k *svKexMap) rlock() {
	k.mutex.RLock()
}

// release writelock
func (k *svKexMap) unlock() {
	k.mutex.Unlock()
}

// release readlock
func (k *svKexMap) runlock() {
	k.mutex.RUnlock()
}

//
//
// read/write locked map of global permissions
type svPermMapGlobal struct {
	// user(uuid.string) -> permission(uuid.string) -> true
	GMap  map[string]map[string]bool
	mutex sync.RWMutex
}

func (g *svPermMapGlobal) grant(user, permission string) {
	g.lock()
	defer g.unlock()

	// zero value for maps is nil
	if m, ok := g.GMap[user]; !ok {
		g.GMap[user] = make(map[string]bool)
	} else if m == nil {
		g.GMap[user] = make(map[string]bool)
	}

	// grant permission
	g.GMap[user][permission] = true
}

func (g *svPermMapGlobal) revoke(user, permission string) {
	g.lock()
	defer g.unlock()

	// user has no permissions
	if m, ok := g.GMap[user]; !ok {
		return
	} else if m == nil {
		return
	}

	// revoke permission
	delete(g.GMap[user], permission)
}

// ATTENTION: named return parameter
func (g *svPermMapGlobal) assess(user, permission string) (verdict bool) {
	g.rlock()
	defer g.runlock()
	// map[]map[] is volatile
	defer func() {
		if r := recover(); r != nil {
			verdict = false
		}
	}()
	verdict = false

	if m, ok := g.GMap[user]; !ok {
		g.GMap[user] = make(map[string]bool)
		return
	} else if m == nil {
		g.GMap[user] = make(map[string]bool)
		return
	}

	// let zero value `false` work for us
	verdict = g.GMap[user][permission]
	return
}

func (g *svPermMapGlobal) lock() {
	g.mutex.Lock()
}

func (g *svPermMapGlobal) rlock() {
	g.mutex.RLock()
}

func (g *svPermMapGlobal) unlock() {
	g.mutex.Unlock()
}

func (g *svPermMapGlobal) runlock() {
	g.mutex.RUnlock()
}

//
//
// read/write locked map of limited permissions
type svPermMapLimited struct {
	// user(uuid.string) -> permission(uuid.string) -> repository(uuid.string)
	LMap  map[string]map[string][]string
	mutex sync.RWMutex
}

func (l *svPermMapLimited) lock() {
}

func (l *svPermMapLimited) rlock() {
}

func (l *svPermMapLimited) unlock() {
}

func (l *svPermMapLimited) runlock() {
}

//
//
// read/write locked permission id map
type svPermMap struct {
	// permission name -> permission uuid
	PMap  map[string]string
	mutex sync.RWMutex
}

func (p *svPermMap) lock() {
}

func (p *svPermMap) rlock() {
}

func (p *svPermMap) unlock() {
}

func (p *svPermMap) runlock() {
}

//
//
// read/write locked user id map
type svUserMap struct {
	// user name -> user uuid
	UMap  map[string]string
	mutex sync.RWMutex
}

func (u *svUserMap) lock() {
}

func (u *svUserMap) rlock() {
}

func (u *svUserMap) unlock() {
}

func (u *svUserMap) runlock() {
}

//
//
// read/write locked team map
type svTeamMap struct {
	// user uuid -> team uuid
	TMap  map[string]string
	mutex sync.RWMutex
}

func (t *svTeamMap) lock() {
}

func (t *svTeamMap) rlock() {
}

func (t *svTeamMap) unlock() {
}

func (t *svTeamMap) runlock() {
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>// Copyright 2013 Google, Inc.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"github.com/docopt/docopt-go"
	"github.com/kylelemons/go-gypsy/yaml"
	"log"
	"os"
	"reflect"
)

/*
res_map = {
        "time.total": ['Benchmark Time Summary', 'Total'],
        "problem.dim.x": ['Global Problem Dimensions', 'Global nx'],
        "problem.dim.y": ['Global Problem Dimensions', 'Global ny'],
        "problem.dim.z": ['Global Problem Dimensions', 'Global nz'],
        "gflops": ['DDOT Timing Variations', 'HPCG result is VALID with a GFLOP/s rating of'],
        "local.dim.x": ['Local Domain Dimensions', 'nx'],
        "local.dim.y": ['Local Domain Dimensions', 'ny'],
        "local.dim.z": ['Local Domain Dimensions', 'nz'],
        "mach.num_proc": ['Machine Summary', 'Distributed Processes'],
        "mach.threads_per_proc": ['Machine Summary', 'Threads per processes'],
    }
*/

func nodeToMap(node yaml.Node) yaml.Map {
	m, ok := node.(yaml.Map)
	if !ok {
		panic(fmt.Sprintf("%v is not of type map", node))
	}
	return m
}

func nodeToList(node yaml.Node) yaml.List {
	m, ok := node.(yaml.List)
	if !ok {
		panic(fmt.Sprintf("%v is not of type list", node))
	}
	return m
}

func readLastLine(fname string) {
	file, err := os.Open(fname)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	fi, err := file.Stat()
	if err != nil {
		fmt.Println(err)
	}

	buf := make([]byte, 32)
	n, err := file.ReadAt(buf, fi.Size()-int64(len(buf)))
	if err != nil {
		fmt.Println(err)
	}
	buf = buf[:n]
	fmt.Printf("%s", buf)

}

func main() {
	usage := `evaluate HPCG output

Usage:
  eval-hpcg [options] <file>
  eval-hpcg -h | --help
  eval-hpcg --version

Options:
  -h --help     Show this screen.
  --version     Show version.
`

	arguments, _ := docopt.Parse(usage, nil, true, "Naval Fate 2.0", false)
	fmt.Println(arguments)
	file := arguments["<file>"].(string)
	file_descr, err := os.Open(file)
	if err != nil {
		panic(err)
	}
	defer file_descr.Close()

	fi, err := file_descr.Stat()
	if err != nil {
		fmt.Println(err)
	}
	buf := make([]byte, fi.Size())
	n, err := file_descr.ReadAt(buf, fi.Size()-int64(len(buf)))
	if err != nil {
		fmt.Println(err)
	}
	buf = buf[:n]
	fmt.Printf("%s", buf)
	config, err := yaml.ReadFile(file)
	if err != nil {
		log.Fatalf("readfile(%q): %s", file, err)
	}
	param := "Benchmark Time Summary"
	subparam := "Total"
	val := nodeToMap(config.Root)[param]
	subval := nodeToMap(val)[subparam]
	fmt.Println(reflect.TypeOf(val))
	if err != nil {
		log.Fatalf("read_param(%s): %s", param, err)
	}

	fmt.Printf("%s = %s\n", param, val)
	fmt.Printf("%s = %s\n", subparam, subval)
}
<commit_msg>2d fetching<commit_after>// Copyright 2013 Google, Inc.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
    "bytes"
	"fmt"
	"github.com/docopt/docopt-go"
	"github.com/kylelemons/go-gypsy/yaml"
	"log"
	"os"
)

/*
res_map = {
        "time.total": ['Benchmark Time Summary', 'Total'],
        "problem.dim.x": ['Global Problem Dimensions', 'Global nx'],
        "problem.dim.y": ['Global Problem Dimensions', 'Global ny'],
        "problem.dim.z": ['Global Problem Dimensions', 'Global nz'],
        "gflops": ['DDOT Timing Variations', 'HPCG result is VALID with a GFLOP/s rating of'],
        "local.dim.x": ['Local Domain Dimensions', 'nx'],
        "local.dim.y": ['Local Domain Dimensions', 'ny'],
        "local.dim.z": ['Local Domain Dimensions', 'nz'],
        "mach.num_proc": ['Machine Summary', 'Distributed Processes'],
        "mach.threads_per_proc": ['Machine Summary', 'Threads per processes'],
    }
*/

func nodeToMap(node yaml.Node) yaml.Map {
	m, ok := node.(yaml.Map)
	if !ok {
		panic(fmt.Sprintf("%v is not of type map", node))
	}
	return m
}

func nodeToList(node yaml.Node) yaml.List {
	m, ok := node.(yaml.List)
	if !ok {
		panic(fmt.Sprintf("%v is not of type list", node))
	}
	return m
}

function ParseHPCG(string file) (yaml.Node ya) {
	file_descr, err := os.Open(file)
	if err != nil {
		panic(err)
	}
	defer file_descr.Close()

	fi, err := file_descr.Stat()
	if err != nil {
		fmt.Println(err)
	}
	buf := make([]byte, fi.Size())
	n, err := file_descr.ReadAt(buf, 19)
	buf = buf[:n]
    reader := bytes.NewReader(buf)
	config, err := yaml.Parse(reader)
	if err != nil {
		log.Fatalf("readfile(%q): %s", file, err)
	}
    return config
}

func main() {
	usage := `evaluate HPCG output

Usage:
  eval-hpcg [options] <file>
  eval-hpcg -h | --help
  eval-hpcg --version

Options:
  -h --help     Show this screen.
  --version     Show version.
`

	arguments, _ := docopt.Parse(usage, nil, true, "0.1", false)
	file := arguments["<file>"].(string)
    ya := ParseHPCG(file)
	param := "Benchmark Time Summary"
	subparam := "Total"
	val := nodeToMap(config)[param]
	subval := nodeToMap(val)[subparam]
	if err != nil {
		log.Fatalf("read_param(%s): %s", param, err)
	}

	fmt.Printf("%s = %s\n", param, val)
	fmt.Printf("%s = %s\n", subparam, subval)
}
<|endoftext|>


<commit_before>package test

import (
	"errors"
	"fmt"
	"math/rand"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"syscall"
	"testing"
	"time"
)

const (
	retryCount = 4
	isParallel = true
)

type cmdFunc func() ([]byte, error)

// try is designed with command line executions in mind
func try(blockName string, t *t, f cmdFunc, maxTime time.Duration) {
	start := time.Now()
	var outp []byte
	var err error

	for {
		if t.failed {
			return
		}
		if time.Since(start) > maxTime {
			_, file, line, _ := runtime.Caller(1)
			fname := filepath.Base(file)
			if err != nil {
				t.Fatalf("%v:%v, %v (failed after %v with '%v'), output: '%v'", fname, line, blockName, time.Since(start), err, string(outp))
			}
			return
		}
		outp, err = f()
		if err == nil {
			return
		}
		time.Sleep(1000 * time.Millisecond)
	}
}

func once(blockName string, t *testing.T, f cmdFunc) {
	outp, err := f()
	if err != nil {
		t.Fatalf("%v with '%v', output: %v", blockName, err, string(outp))
	}
}

type server struct {
	cmd           *exec.Cmd
	t             *t
	envName       string
	portNum       int
	containerName string
	opts          options
}

func getFrame(skipFrames int) runtime.Frame {
	// We need the frame at index skipFrames+2, since we never want runtime.Callers and getFrame
	targetFrameIndex := skipFrames + 2

	// Set size to targetFrameIndex+2 to ensure we have room for one more caller than we need
	programCounters := make([]uintptr, targetFrameIndex+2)
	n := runtime.Callers(0, programCounters)

	frame := runtime.Frame{Function: "unknown"}
	if n > 0 {
		frames := runtime.CallersFrames(programCounters[:n])
		for more, frameIndex := true, 0; more && frameIndex <= targetFrameIndex; frameIndex++ {
			var frameCandidate runtime.Frame
			frameCandidate, more = frames.Next()
			if frameIndex == targetFrameIndex {
				frame = frameCandidate
			}
		}
	}

	return frame
}

// taken from https://stackoverflow.com/questions/35212985/is-it-possible-get-information-about-caller-function-in-golang
// MyCaller returns the caller of the function that called it :)
func myCaller() string {
	// Skip GetCallerFunctionName and the function to get the caller of
	return getFrame(2).Function
}

type options struct {
	auth string // eg. jwt
}

func newServer(t *t, opts ...options) server {
	min := 8000
	max := 60000
	portnum := rand.Intn(max-min) + min
	fname := strings.Split(myCaller(), ".")[2]

	// kill container, ignore error because it might not exist,
	// we dont care about this that much
	exec.Command("docker", "kill", fname).CombinedOutput()
	exec.Command("docker", "rm", fname).CombinedOutput()

	// create env and set proxy address
	exec.Command("micro", "env", "add", fname, fmt.Sprintf("127.0.0.1:%v", portnum)).CombinedOutput()

	cmd := exec.Command("docker", "run", "--name", fname,
		fmt.Sprintf("-p=%v:8081", portnum), "micro", "server")
	if len(opts) == 1 && opts[0].auth == "jwt" {

		base64 := "base64 -w0"
		if runtime.GOOS == "darwin" {
			base64 = "base64 -b0"
		}
		priv := "cat /tmp/sshkey | " + base64
		privKey, err := exec.Command("bash", "-c", priv).Output()
		if err != nil {
			panic(string(privKey))
		}

		pub := "cat /tmp/sshkey.pub | " + base64
		pubKey, err := exec.Command("bash", "-c", pub).Output()
		if err != nil {
			panic(string(pubKey))
		}
		cmd = exec.Command("docker", "run", "--name", fname,
			fmt.Sprintf("-p=%v:8081", portnum),
			"-e", "MICRO_AUTH=jwt",
			"-e", "MICRO_AUTH_PRIVATE_KEY="+strings.Trim(string(privKey), "\n"),
			"-e", "MICRO_AUTH_PUBLIC_KEY="+strings.Trim(string(pubKey), "\n"),
			"micro", "server")
	}
	//fmt.Println("docker", "run", "--name", fname, fmt.Sprintf("-p=%v:8081", portnum), "micro", "server")
	opt := options{}
	if len(opts) > 0 {
		opt = opts[0]
	}
	return server{
		cmd:           cmd,
		t:             t,
		envName:       fname,
		containerName: fname,
		portNum:       portnum,
		opts:          opt,
	}
}

func (s server) launch() {
	go func() {
		if err := s.cmd.Start(); err != nil {
			s.t.t.Fatal(err)
		}
	}()

	try("Calling micro server", s.t, func() ([]byte, error) {
		outp, err := exec.Command("micro", s.envFlag(), "list", "services").CombinedOutput()
		if !strings.Contains(string(outp), "runtime") ||
			!strings.Contains(string(outp), "registry") ||
			!strings.Contains(string(outp), "api") ||
			!strings.Contains(string(outp), "broker") ||
			!strings.Contains(string(outp), "config") ||
			!strings.Contains(string(outp), "debug") ||
			!strings.Contains(string(outp), "proxy") ||
			!strings.Contains(string(outp), "auth") ||
			!strings.Contains(string(outp), "store") {
			return outp, errors.New("Not ready")
		}

		// temp solution to envs not being added
		if err == nil {
			exec.Command("micro", "env", "add", s.envName, fmt.Sprintf("127.0.0.1:%v", s.portNum))
		}

		return outp, err
	}, 60*time.Second)

	time.Sleep(5 * time.Second)
}

func (s server) close() {
	exec.Command("docker", "kill", s.containerName).CombinedOutput()
	if s.cmd.Process != nil {
		s.cmd.Process.Signal(syscall.SIGKILL)
	}
}

func (s server) envFlag() string {
	return fmt.Sprintf("-env=%v", s.envName)
}

type t struct {
	counter int
	failed  bool
	format  string
	values  []interface{}
	t       *testing.T
}

func (t *t) Fatal(values ...interface{}) {
	t.t.Log(values...)
	t.failed = true
	t.values = values
}

func (t *t) Log(values ...interface{}) {
	t.t.Log(values...)
}

func (t *t) Fatalf(format string, values ...interface{}) {
	t.t.Log(fmt.Sprintf(format, values...))
	t.failed = true
	t.values = values
	t.format = format
}

func (t *t) Parallel() {
	if t.counter == 0 && isParallel {
		t.t.Parallel()
	}
	t.counter++
}

func newT(te *testing.T) *t {
	return &t{t: te}
}

// trySuite is designed to retry a TestXX function
func trySuite(t *testing.T, f func(t *t), times int) {
	tee := newT(t)
	for i := 0; i < times; i++ {
		f(tee)
		if !tee.failed {
			return
		}
		if i != times-1 {
			tee.failed = false
		}
		time.Sleep(200 * time.Millisecond)
	}
	if tee.failed {
		if len(tee.format) > 0 {
			t.Fatalf(tee.format, tee.values...)
		} else {
			t.Fatal(tee.values...)
		}
	}
}
<commit_msg>test: only register env on launch success<commit_after>package test

import (
	"errors"
	"fmt"
	"math/rand"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"syscall"
	"testing"
	"time"
)

const (
	retryCount = 4
	isParallel = true
)

type cmdFunc func() ([]byte, error)

// try is designed with command line executions in mind
func try(blockName string, t *t, f cmdFunc, maxTime time.Duration) {
	start := time.Now()
	var outp []byte
	var err error

	for {
		if t.failed {
			return
		}
		if time.Since(start) > maxTime {
			_, file, line, _ := runtime.Caller(1)
			fname := filepath.Base(file)
			if err != nil {
				t.Fatalf("%v:%v, %v (failed after %v with '%v'), output: '%v'", fname, line, blockName, time.Since(start), err, string(outp))
			}
			return
		}
		outp, err = f()
		if err == nil {
			return
		}
		time.Sleep(1000 * time.Millisecond)
	}
}

func once(blockName string, t *testing.T, f cmdFunc) {
	outp, err := f()
	if err != nil {
		t.Fatalf("%v with '%v', output: %v", blockName, err, string(outp))
	}
}

type server struct {
	cmd           *exec.Cmd
	t             *t
	envName       string
	portNum       int
	containerName string
	opts          options
}

func getFrame(skipFrames int) runtime.Frame {
	// We need the frame at index skipFrames+2, since we never want runtime.Callers and getFrame
	targetFrameIndex := skipFrames + 2

	// Set size to targetFrameIndex+2 to ensure we have room for one more caller than we need
	programCounters := make([]uintptr, targetFrameIndex+2)
	n := runtime.Callers(0, programCounters)

	frame := runtime.Frame{Function: "unknown"}
	if n > 0 {
		frames := runtime.CallersFrames(programCounters[:n])
		for more, frameIndex := true, 0; more && frameIndex <= targetFrameIndex; frameIndex++ {
			var frameCandidate runtime.Frame
			frameCandidate, more = frames.Next()
			if frameIndex == targetFrameIndex {
				frame = frameCandidate
			}
		}
	}

	return frame
}

// taken from https://stackoverflow.com/questions/35212985/is-it-possible-get-information-about-caller-function-in-golang
// MyCaller returns the caller of the function that called it :)
func myCaller() string {
	// Skip GetCallerFunctionName and the function to get the caller of
	return getFrame(2).Function
}

type options struct {
	auth string // eg. jwt
}

func newServer(t *t, opts ...options) server {
	min := 8000
	max := 60000
	portnum := rand.Intn(max-min) + min
	fname := strings.Split(myCaller(), ".")[2]

	// kill container, ignore error because it might not exist,
	// we dont care about this that much
	exec.Command("docker", "kill", fname).CombinedOutput()
	exec.Command("docker", "rm", fname).CombinedOutput()

	cmd := exec.Command("docker", "run", "--name", fname,
		fmt.Sprintf("-p=%v:8081", portnum), "micro", "server")
	if len(opts) == 1 && opts[0].auth == "jwt" {

		base64 := "base64 -w0"
		if runtime.GOOS == "darwin" {
			base64 = "base64 -b0"
		}
		priv := "cat /tmp/sshkey | " + base64
		privKey, err := exec.Command("bash", "-c", priv).Output()
		if err != nil {
			panic(string(privKey))
		}

		pub := "cat /tmp/sshkey.pub | " + base64
		pubKey, err := exec.Command("bash", "-c", pub).Output()
		if err != nil {
			panic(string(pubKey))
		}
		cmd = exec.Command("docker", "run", "--name", fname,
			fmt.Sprintf("-p=%v:8081", portnum),
			"-e", "MICRO_AUTH=jwt",
			"-e", "MICRO_AUTH_PRIVATE_KEY="+strings.Trim(string(privKey), "\n"),
			"-e", "MICRO_AUTH_PUBLIC_KEY="+strings.Trim(string(pubKey), "\n"),
			"micro", "server")
	}
	//fmt.Println("docker", "run", "--name", fname, fmt.Sprintf("-p=%v:8081", portnum), "micro", "server")
	opt := options{}
	if len(opts) > 0 {
		opt = opts[0]
	}
	return server{
		cmd:           cmd,
		t:             t,
		envName:       fname,
		containerName: fname,
		portNum:       portnum,
		opts:          opt,
	}
}

func (s server) launch() {
	go func() {
		if err := s.cmd.Start(); err != nil {
			s.t.t.Fatal(err)
		}
	}()

	try("Calling micro server", s.t, func() ([]byte, error) {
		outp, err := exec.Command("micro", s.envFlag(), "list", "services").CombinedOutput()
		if !strings.Contains(string(outp), "runtime") ||
			!strings.Contains(string(outp), "registry") ||
			!strings.Contains(string(outp), "api") ||
			!strings.Contains(string(outp), "broker") ||
			!strings.Contains(string(outp), "config") ||
			!strings.Contains(string(outp), "debug") ||
			!strings.Contains(string(outp), "proxy") ||
			!strings.Contains(string(outp), "auth") ||
			!strings.Contains(string(outp), "store") {
			return outp, errors.New("Not ready")
		}

		// add the env once it's running
		if err == nil {
			exec.Command("micro", "env", "add", s.envName, fmt.Sprintf("127.0.0.1:%v", s.portNum))
		}

		return outp, err
	}, 60*time.Second)

	time.Sleep(10 * time.Second)
}

func (s server) close() {
	exec.Command("docker", "kill", s.containerName).CombinedOutput()
	if s.cmd.Process != nil {
		s.cmd.Process.Signal(syscall.SIGKILL)
	}
}

func (s server) envFlag() string {
	return fmt.Sprintf("-env=%v", s.envName)
}

type t struct {
	counter int
	failed  bool
	format  string
	values  []interface{}
	t       *testing.T
}

func (t *t) Fatal(values ...interface{}) {
	t.t.Log(values...)
	t.failed = true
	t.values = values
}

func (t *t) Log(values ...interface{}) {
	t.t.Log(values...)
}

func (t *t) Fatalf(format string, values ...interface{}) {
	t.t.Log(fmt.Sprintf(format, values...))
	t.failed = true
	t.values = values
	t.format = format
}

func (t *t) Parallel() {
	if t.counter == 0 && isParallel {
		t.t.Parallel()
	}
	t.counter++
}

func newT(te *testing.T) *t {
	return &t{t: te}
}

// trySuite is designed to retry a TestXX function
func trySuite(t *testing.T, f func(t *t), times int) {
	tee := newT(t)
	for i := 0; i < times; i++ {
		f(tee)
		if !tee.failed {
			return
		}
		if i != times-1 {
			tee.failed = false
		}
		time.Sleep(200 * time.Millisecond)
	}
	if tee.failed {
		if len(tee.format) > 0 {
			t.Fatalf(tee.format, tee.values...)
		} else {
			t.Fatal(tee.values...)
		}
	}
}
<|endoftext|>