<commit_before>package main

import (
	"log"

	chronograph "github.com/gebv/hey"
)

func main() {
	chrono, err := chronograph.New()
	if err != nil {
		log.Fatalln(err)
	}

	// создаём пользователя 1
	user1 := chronograph.User{}
	err = chrono.NewUser(&user1)
	checkErr(err)

	// создаём трэд нотификаций пользователя
	notify1 := chronograph.Thread{
		ThreadlineEnabled: true,
	}
	checkErr(err)

	// create thread for user 1 notifications
	err = chrono.NewThread(&notify1)
	checkErr(err)

	// трэд можно читать без подписки на него,
	// но если мы хотим знать последнее прочитанное уведомление,
	// должны подписаться
	// подписываем пользователя 1 на уведомления
	err = chrono.Observe(user1.UserID, notify1.ThreadID)
	checkErr(err)

	obs, err := chrono.Observers(notify1.ThreadID, 0, 1)
	checkErr(err)
	if len(obs) != 1 {
		log.Fatalln("observe not work", len(obs))
	}

	// создаём событие в трэде
	note := NewNotification("Событие", "Новое сообщение!")
	note.ThreadID = notify1.ThreadID
	err = chrono.NewEvent(&note)
	checkErr(err)

	// достаем последние события
	events, err := chrono.RecentActivity(user1.UserID, notify1.ThreadID, 0, 10)
	checkErr(err)
	if len(events) != 1 {
		log.Fatalln("длинна событий != 1", len(events))
	}
	if _, ok := events[0].Data.(*NotificationData); !ok {
		log.Fatalln("ошибка декодирования данных")
	}

	// добавляем произвольные данные к событию, видные только данному
	// пользователю
	bookmark := NewBookmark(user1.UserID, note.EventID, true)
	err = chrono.SetRelatedData(&bookmark)
	checkErr(err)

	// чтобы достать события с пользовательской информацией нужно сначала
	// достать события, а затем вызвать
	eventObseres, err := chrono.GetRelatedDatas(user1.UserID, note)
	checkErr(err)
	if len(eventObseres) != 1 {
		log.Fatalln("не хватает")
	}

	if bm, ok := eventObseres[0].RelatedData.Data.(*Bookmark); ok {
		if !bm.Bookmarked {
			log.Fatalln("не добавилось в избранное")
		}
	} else {
		log.Fatalln("ошибка декодинга")
	}

	log.Println("done")
}

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>fix limit offset<commit_after>package main

import (
	"log"

	chronograph "github.com/gebv/hey"
)

func main() {
	chrono, err := chronograph.New()
	if err != nil {
		log.Fatalln(err)
	}

	// создаём пользователя 1
	user1 := chronograph.User{}
	err = chrono.NewUser(&user1)
	checkErr(err)

	// создаём трэд нотификаций пользователя
	notify1 := chronograph.Thread{
		ThreadlineEnabled: true,
	}
	checkErr(err)

	// create thread for user 1 notifications
	err = chrono.NewThread(&notify1)
	checkErr(err)

	// трэд можно читать без подписки на него,
	// но если мы хотим знать последнее прочитанное уведомление,
	// должны подписаться
	// подписываем пользователя 1 на уведомления
	err = chrono.Observe(user1.UserID, notify1.ThreadID)
	checkErr(err)

	obs, err := chrono.Observers(notify1.ThreadID, 0, 1)
	checkErr(err)
	if len(obs) != 1 {
		log.Fatalln("observe not work", len(obs))
	}

	// создаём событие в трэде
	note := NewNotification("Событие", "Новое сообщение!")
	note.ThreadID = notify1.ThreadID
	err = chrono.NewEvent(&note)
	checkErr(err)

	// достаем последние события
	events, err := chrono.RecentActivity(user1.UserID, notify1.ThreadID, 10, 0)
	checkErr(err)
	if len(events) != 1 {
		log.Fatalln("длинна событий != 1", len(events))
	}
	if _, ok := events[0].Data.(*NotificationData); !ok {
		log.Fatalln("ошибка декодирования данных")
	}

	// добавляем произвольные данные к событию, видные только данному
	// пользователю
	bookmark := NewBookmark(user1.UserID, note.EventID, true)
	err = chrono.SetRelatedData(&bookmark)
	checkErr(err)

	// чтобы достать события с пользовательской информацией нужно сначала
	// достать события, а затем вызвать
	eventObseres, err := chrono.GetRelatedDatas(user1.UserID, note)
	checkErr(err)
	if len(eventObseres) != 1 {
		log.Fatalln("не хватает")
	}

	if bm, ok := eventObseres[0].RelatedData.Data.(*Bookmark); ok {
		if !bm.Bookmarked {
			log.Fatalln("не добавилось в избранное")
		}
	} else {
		log.Fatalln("ошибка декодинга")
	}

	log.Println("done")
}

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


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

package main

import (
	"expvar"
	"flag"
	"fmt"
	"log"
	"sync"
	"text/template"
	"time"

	"net/http"

	"github.com/tomahawk28/cell"
)

var (
	httpAddr        = flag.String("http", ":8040", "Listen Address")
	cellAdvisorAddr = flag.String("celladdr", "10.82.26.12", "CellAdvisor Address")
	numsport        = flag.Uint("numsport", 4, "The number of ports ")
	pollPeriod      = flag.Duration("poll", 30*time.Second, "Poll Period")
)

var (
	screenCache = ScreenCache{time.Now(), []byte{}, sync.RWMutex{}}
	mu          = sync.Mutex{}
	tmpl        = template.Must(template.ParseFiles("template.html"))
)

var (
	sendSuccessCount    = expvar.NewInt("sendSuccessCount")
	receiveSucessCount  = expvar.NewInt("receiveSucessCount")
	sendPendingCount    = expvar.NewInt("sendPendingCount")
	receivePendingCount = expvar.NewInt("receivePendingCount")
)

type Request struct {
	command string
	args    map[string]string
	result  chan []byte
}

type ScreenCache struct {
	last  time.Time
	cache []byte
	mu    sync.RWMutex
}

func Poller(in <-chan *Request, cell *cell.CellAdvisor, thread_number int) {
	done := make(chan struct{})
	defer close(done)
	var err error
	for {
		select {
		case r := <-in:
			log.Println("Thread ", thread_number, ":", r.command)
			switch r.command {
			case "keyp":
				scpicmd := fmt.Sprintf("KEYP:%s", r.args["value"])
				_, err = cell.SendSCPI(scpicmd)
				sendResult(done, r.result, []byte{})
			case "touch":
				scpicmd := fmt.Sprintf("KEYP %s %s", r.args["x"], r.args["y"])
				_, err = cell.SendSCPI(scpicmd)
				sendResult(done, r.result, []byte{})
			case "screen":
				go func() {
					screenCache.mu.Lock()
					defer screenCache.mu.Unlock()
					if time.Now().Sub(screenCache.last).Seconds() > 1 {
						screenCache.last = time.Now()
						screenCache.cache, err = cell.GetScreen()
						if err != nil {
							log.Println(err.Error())
						}
					}
					sendResult(done, r.result, screenCache.cache)
				}()
			case "heartbeat":
				msg, err := cell.GetStatusMessage()
				if err != nil {
					log.Println(err.Error())
				}
				sendResult(done, r.result, msg)
			}
		case <-time.After(time.Second * 15):
			mu.Lock()
			msg, err := cell.GetStatusMessage()
			if err != nil {
				log.Println(err.Error())
			}
			log.Println("Hearbeat:", thread_number, string(msg))
			mu.Unlock()
		}
		//Check Error Status == EOF

		if err != nil && err.Error() == "EOF" {
			return
		}
	}
}

func NewRequest(command string, args map[string]string) *Request {
	return &Request{command, args, make(chan []byte)}
}

func sendResult(done <-chan struct{}, pipe chan<- []byte, result []byte) {
	select {
	case pipe <- result:
		sendSuccessCount.Add(1)
	case <-time.After(time.Second * 3):
		log.Println("Sending Timeout")
		sendPendingCount.Add(1)
	case <-done:
		return
	}
}
func receiveResult(pipe <-chan []byte) []byte {
	select {
	case result := <-pipe:
		receiveSucessCount.Add(1)
		return result
	case <-time.After(time.Second * 5):
		log.Println("Receive Timeout")
		receivePendingCount.Add(1)
	}
	return []byte{}
}

func main() {

	flag.Parse()
	// 4 Ports ready for work
	cell_list := make([]cell.CellAdvisor, *numsport)

	for i, _ := range cell_list {
		cell_list[i] = cell.NewCellAdvisor(*cellAdvisorAddr)
	}

	request_channel := make(chan *Request, len(cell_list))
	for i, _ := range cell_list {
		go Poller(request_channel, &cell_list[i], i)
	}

	http.HandleFunc("/screen", func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "image/jpeg")
		request_object := NewRequest("screen", nil)
		request_channel <- request_object

		w.Write(receiveResult(request_object.result))
	})
	http.HandleFunc("/touch", func(w http.ResponseWriter, req *http.Request) {
		query := req.URL.Query()
		x, y := query.Get("x"), query.Get("y")
		if x != "" && y != "" {
			request_object := NewRequest("touch", map[string]string{"x": x, "y": y})
			request_channel <- request_object
			w.Write(receiveResult(request_object.result))
		} else {
			fmt.Fprintf(w, "Coordination not given")
			w.WriteHeader(http.StatusBadRequest)
		}
	})
	http.HandleFunc("/keyp", func(w http.ResponseWriter, req *http.Request) {
		err := req.ParseForm()
		if err != nil {
			fmt.Fprintf(w, "Form Parse error")
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		value := req.FormValue("value")

		if value != "" {
			request_object := NewRequest("keyp", map[string]string{"value": value})
			request_channel <- request_object
			w.Write(receiveResult(request_object.result))

		} else {
			fmt.Fprintf(w, "Keypad name not given")
			w.WriteHeader(http.StatusBadRequest)
		}
	})
	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		err := tmpl.Execute(w, nil)
		if err != nil {
			panic(err)
		}
	})
	fs := http.FileServer(http.Dir("static"))
	http.Handle("/static/", http.StripPrefix("/static/", fs))
	log.Fatal(http.ListenAndServe(*httpAddr, nil))
}
<commit_msg>use poll period timeout vars<commit_after>//JDSU CellAdvisor Web-Live Program
//Copyright (C) 2015 Jihyuk Bok <tomahawk28@gmail.com>
//
//Permission is hereby granted, free of charge, to any person obtaining
//a copy of this software and associated documentation files (the "Software"),
//to deal in the Software without restriction, including without limitation
//the rights to use, copy, modify, merge, publish, distribute, sublicense,
//and/or sell copies of the Software, and to permit persons to whom the
//Software is furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included
//in all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
//DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
//TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
//OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

package main

import (
	"expvar"
	"flag"
	"fmt"
	"log"
	"sync"
	"text/template"
	"time"

	"net/http"

	"github.com/tomahawk28/cell"
)

var (
	httpAddr        = flag.String("http", ":8040", "Listen Address")
	cellAdvisorAddr = flag.String("celladdr", "10.82.26.12", "CellAdvisor Address")
	numsport        = flag.Uint("numsport", 4, "The number of ports ")
	pollPeriod      = flag.Duration("poll", 10*time.Second, "Poll Period")
)

var (
	screenCache = ScreenCache{time.Now(), []byte{}, sync.RWMutex{}}
	mu          = sync.Mutex{}
	tmpl        = template.Must(template.ParseFiles("template.html"))
)

var (
	sendSuccessCount    = expvar.NewInt("sendSuccessCount")
	receiveSucessCount  = expvar.NewInt("receiveSucessCount")
	sendPendingCount    = expvar.NewInt("sendPendingCount")
	receivePendingCount = expvar.NewInt("receivePendingCount")
)

type Request struct {
	command string
	args    map[string]string
	result  chan []byte
}

type ScreenCache struct {
	last  time.Time
	cache []byte
	mu    sync.RWMutex
}

func Poller(in <-chan *Request, cell *cell.CellAdvisor, thread_number int) {
	done := make(chan struct{})
	defer close(done)
	var err error
	var msg []byte
	for {
		select {
		case r := <-in:
			log.Println("Thread ", thread_number, ":", r.command)
			switch r.command {
			case "keyp":
				scpicmd := fmt.Sprintf("KEYP:%s", r.args["value"])
				_, err = cell.SendSCPI(scpicmd)
				sendResult(done, r.result, []byte{})
			case "touch":
				scpicmd := fmt.Sprintf("KEYP %s %s", r.args["x"], r.args["y"])
				_, err = cell.SendSCPI(scpicmd)
				sendResult(done, r.result, []byte{})
			case "screen":
				go func() {
					screenCache.mu.Lock()
					defer screenCache.mu.Unlock()
					if time.Now().Sub(screenCache.last).Seconds() > 1 {
						screenCache.last = time.Now()
						screenCache.cache, err = cell.GetScreen()
						if err != nil {
							log.Println(err.Error())
						}
					}
					sendResult(done, r.result, screenCache.cache)
				}()
			case "heartbeat":
				msg, err = cell.GetStatusMessage()
				if err != nil {
					log.Println(err.Error())
				}
				sendResult(done, r.result, msg)
			}
		case <-time.After(*pollPeriod):
			mu.Lock()
			msg, err = cell.GetStatusMessage()
			if err != nil {
				log.Println(err.Error())
			}
			log.Println("Hearbeat:", thread_number, string(msg))
			mu.Unlock()
		}
		//Check Error Status == EOF

		if err != nil && err.Error() == "EOF" {
			return
		}
	}
}

func NewRequest(command string, args map[string]string) *Request {
	return &Request{command, args, make(chan []byte)}
}

func sendResult(done <-chan struct{}, pipe chan<- []byte, result []byte) {
	select {
	case pipe <- result:
		sendSuccessCount.Add(1)
	case <-time.After(time.Second * 3):
		log.Println("Sending Timeout")
		sendPendingCount.Add(1)
	case <-done:
		return
	}
}
func receiveResult(pipe <-chan []byte) []byte {
	select {
	case result := <-pipe:
		receiveSucessCount.Add(1)
		return result
	case <-time.After(time.Second * 5):
		log.Println("Receive Timeout")
		receivePendingCount.Add(1)
	}
	return []byte{}
}

func main() {

	flag.Parse()
	// 4 Ports ready for work
	cell_list := make([]cell.CellAdvisor, *numsport)

	for i, _ := range cell_list {
		cell_list[i] = cell.NewCellAdvisor(*cellAdvisorAddr)
	}

	request_channel := make(chan *Request, len(cell_list))
	for i, _ := range cell_list {
		go Poller(request_channel, &cell_list[i], i)
	}

	http.HandleFunc("/screen", func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "image/jpeg")
		request_object := NewRequest("screen", nil)
		request_channel <- request_object

		w.Write(receiveResult(request_object.result))
	})
	http.HandleFunc("/touch", func(w http.ResponseWriter, req *http.Request) {
		query := req.URL.Query()
		x, y := query.Get("x"), query.Get("y")
		if x != "" && y != "" {
			request_object := NewRequest("touch", map[string]string{"x": x, "y": y})
			request_channel <- request_object
			w.Write(receiveResult(request_object.result))
		} else {
			fmt.Fprintf(w, "Coordination not given")
			w.WriteHeader(http.StatusBadRequest)
		}
	})
	http.HandleFunc("/keyp", func(w http.ResponseWriter, req *http.Request) {
		err := req.ParseForm()
		if err != nil {
			fmt.Fprintf(w, "Form Parse error")
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		value := req.FormValue("value")

		if value != "" {
			request_object := NewRequest("keyp", map[string]string{"value": value})
			request_channel <- request_object
			w.Write(receiveResult(request_object.result))

		} else {
			fmt.Fprintf(w, "Keypad name not given")
			w.WriteHeader(http.StatusBadRequest)
		}
	})
	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		err := tmpl.Execute(w, nil)
		if err != nil {
			panic(err)
		}
	})
	fs := http.FileServer(http.Dir("static"))
	http.Handle("/static/", http.StripPrefix("/static/", fs))
	log.Fatal(http.ListenAndServe(*httpAddr, nil))
}
<|endoftext|>


<commit_before>package server

import (
	"bytes"
	_ "embed" // Necessary to use go:embed
	"errors"
	"fmt"
	"strconv"

	pb "github.com/google/go-tpm-tools/proto/attest"
)

// Expected Firmware/PCR0 Event Types.
//
// Taken from TCG PC Client Platform Firmware Profile Specification,
// Table 14 Events.
const (
	NoAction     uint32 = 0x00000003
	Separator    uint32 = 0x00000004
	SCRTMVersion uint32 = 0x00000008
	NonhostInfo  uint32 = 0x00000011
)

var (
	// GCENonHostInfoSignature identifies the GCE Non-Host info event, which
	// indicates if memory encryption is enabled. This event is 32-bytes consisting
	// of the below signature (16 bytes), followed by a byte indicating whether
	// it is confidential, followed by 15 reserved bytes.
	GCENonHostInfoSignature = []byte("GCE NonHostInfo\x00")
	// GceVirtualFirmwarePrefix is the little-endian UCS-2 encoded string
	// "GCE Virtual Firmware v" without a null terminator. All GCE firmware
	// versions are UCS-2 encoded, start with this prefix, contain the firmware
	// version encoded as an integer, and end with a null terminator.
	GceVirtualFirmwarePrefix = []byte{0x47, 0x00, 0x43, 0x00,
		0x45, 0x00, 0x20, 0x00, 0x56, 0x00, 0x69, 0x00, 0x72, 0x00,
		0x74, 0x00, 0x75, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00,
		0x46, 0x00, 0x69, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x77, 0x00,
		0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00, 0x76, 0x00}
)

// Standard Secure Boot certificates (DER encoded)
var (
	//go:embed secure-boot/GcePk.crt
	GceDefaultPKCert []byte
	//go:embed secure-boot/MicCorKEKCA2011_2011-06-24.crt
	MicrosoftKEKCA2011Cert []byte
	//go:embed secure-boot/MicWinProPCA2011_2011-10-19.crt
	WindowsProductionPCA2011Cert []byte
	//go:embed secure-boot/MicCorUEFCA2011_2011-06-27.crt
	MicrosoftUEFICA2011Cert []byte
)

// Revoked Signing certificates (DER encoded)
var (
	//go:embed secure-boot/canonical-boothole.crt
	RevokedCanonicalBootholeCert []byte
	//go:embed secure-boot/debian-boothole.crt
	RevokedDebianBootholeCert []byte
	//go:embed secure-boot/cisco-boothole.crt
	RevokedCiscoCert []byte
)

// ConvertSCRTMVersionToGCEFirmwareVersion attempts to parse the Firmware
// Version of a GCE VM from the bytes of the version string of the SCRTM. This
// data should come from a valid and verified EV_S_CRTM_VERSION event.
func ConvertSCRTMVersionToGCEFirmwareVersion(version []byte) (uint32, error) {
	prefixLen := len(GceVirtualFirmwarePrefix)
	if (len(version) <= prefixLen) || (len(version)%2 != 0) {
		return 0, fmt.Errorf("length of GCE version (%d) is invalid", len(version))
	}
	if !bytes.Equal(version[:prefixLen], GceVirtualFirmwarePrefix) {
		return 0, errors.New("prefix for GCE version is missing")
	}
	asciiVersion := []byte{}
	for i, b := range version[prefixLen:] {
		// Skip the UCS-2 null bytes and the null terminator
		if b == '\x00' {
			continue
		}
		// All odd bytes in our UCS-2 string should be Null
		if i%2 != 0 {
			return 0, errors.New("invalid UCS-2 in the version string")
		}
		asciiVersion = append(asciiVersion, b)
	}

	versionNum, err := strconv.Atoi(string(asciiVersion))
	if err != nil {
		return 0, fmt.Errorf("when parsing GCE firmware version: %w", err)
	}
	return uint32(versionNum), nil
}

// ConvertGCEFirmwareVersionToSCRTMVersion creates the corresponding SCRTM
// version string from a numerical GCE firmware version. The returned string
// is UCS2 encoded with a null terminator. A version of 0 corresponds to an
// empty string (representing old GCE VMs that just used an empty string).
func ConvertGCEFirmwareVersionToSCRTMVersion(version uint32) []byte {
	if version == 0 {
		return []byte{}
	}
	versionString := GceVirtualFirmwarePrefix
	for _, b := range []byte(strconv.Itoa(int(version))) {
		// Convert ACSII to little-endian UCS-2
		versionString = append(versionString, b, 0)
	}
	// Add the null terminator
	return append(versionString, 0, 0)
}

// ParseGCENonHostInfo attempts to parse the Confidential VM
// technology used by a GCE VM from the GCE Non-Host info event. This data
// should come from a valid and verified EV_NONHOST_INFO event.
func ParseGCENonHostInfo(nonHostInfo []byte) (pb.GCEConfidentialTechnology, error) {
	prefixLen := len(GCENonHostInfoSignature)
	if len(nonHostInfo) < (prefixLen + 1) {
		return pb.GCEConfidentialTechnology_NONE, fmt.Errorf("length of GCE Non-Host info (%d) is too short", len(nonHostInfo))
	}

	if !bytes.Equal(nonHostInfo[:prefixLen], GCENonHostInfoSignature) {
		return pb.GCEConfidentialTechnology_NONE, errors.New("prefix for GCE Non-Host info is missing")
	}
	tech := nonHostInfo[prefixLen]
	return pb.GCEConfidentialTechnology(tech), nil
}
<commit_msg>server: Check for unknown GCE Technology<commit_after>package server

import (
	"bytes"
	_ "embed" // Necessary to use go:embed
	"errors"
	"fmt"
	"strconv"

	pb "github.com/google/go-tpm-tools/proto/attest"
)

// Expected Firmware/PCR0 Event Types.
//
// Taken from TCG PC Client Platform Firmware Profile Specification,
// Table 14 Events.
const (
	NoAction     uint32 = 0x00000003
	Separator    uint32 = 0x00000004
	SCRTMVersion uint32 = 0x00000008
	NonhostInfo  uint32 = 0x00000011
)

var (
	// GCENonHostInfoSignature identifies the GCE Non-Host info event, which
	// indicates if memory encryption is enabled. This event is 32-bytes consisting
	// of the below signature (16 bytes), followed by a byte indicating whether
	// it is confidential, followed by 15 reserved bytes.
	GCENonHostInfoSignature = []byte("GCE NonHostInfo\x00")
	// GceVirtualFirmwarePrefix is the little-endian UCS-2 encoded string
	// "GCE Virtual Firmware v" without a null terminator. All GCE firmware
	// versions are UCS-2 encoded, start with this prefix, contain the firmware
	// version encoded as an integer, and end with a null terminator.
	GceVirtualFirmwarePrefix = []byte{0x47, 0x00, 0x43, 0x00,
		0x45, 0x00, 0x20, 0x00, 0x56, 0x00, 0x69, 0x00, 0x72, 0x00,
		0x74, 0x00, 0x75, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00,
		0x46, 0x00, 0x69, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x77, 0x00,
		0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00, 0x76, 0x00}
)

// Standard Secure Boot certificates (DER encoded)
var (
	//go:embed secure-boot/GcePk.crt
	GceDefaultPKCert []byte
	//go:embed secure-boot/MicCorKEKCA2011_2011-06-24.crt
	MicrosoftKEKCA2011Cert []byte
	//go:embed secure-boot/MicWinProPCA2011_2011-10-19.crt
	WindowsProductionPCA2011Cert []byte
	//go:embed secure-boot/MicCorUEFCA2011_2011-06-27.crt
	MicrosoftUEFICA2011Cert []byte
)

// Revoked Signing certificates (DER encoded)
var (
	//go:embed secure-boot/canonical-boothole.crt
	RevokedCanonicalBootholeCert []byte
	//go:embed secure-boot/debian-boothole.crt
	RevokedDebianBootholeCert []byte
	//go:embed secure-boot/cisco-boothole.crt
	RevokedCiscoCert []byte
)

// ConvertSCRTMVersionToGCEFirmwareVersion attempts to parse the Firmware
// Version of a GCE VM from the bytes of the version string of the SCRTM. This
// data should come from a valid and verified EV_S_CRTM_VERSION event.
func ConvertSCRTMVersionToGCEFirmwareVersion(version []byte) (uint32, error) {
	prefixLen := len(GceVirtualFirmwarePrefix)
	if (len(version) <= prefixLen) || (len(version)%2 != 0) {
		return 0, fmt.Errorf("length of GCE version (%d) is invalid", len(version))
	}
	if !bytes.Equal(version[:prefixLen], GceVirtualFirmwarePrefix) {
		return 0, errors.New("prefix for GCE version is missing")
	}
	asciiVersion := []byte{}
	for i, b := range version[prefixLen:] {
		// Skip the UCS-2 null bytes and the null terminator
		if b == '\x00' {
			continue
		}
		// All odd bytes in our UCS-2 string should be Null
		if i%2 != 0 {
			return 0, errors.New("invalid UCS-2 in the version string")
		}
		asciiVersion = append(asciiVersion, b)
	}

	versionNum, err := strconv.Atoi(string(asciiVersion))
	if err != nil {
		return 0, fmt.Errorf("when parsing GCE firmware version: %w", err)
	}
	return uint32(versionNum), nil
}

// ConvertGCEFirmwareVersionToSCRTMVersion creates the corresponding SCRTM
// version string from a numerical GCE firmware version. The returned string
// is UCS2 encoded with a null terminator. A version of 0 corresponds to an
// empty string (representing old GCE VMs that just used an empty string).
func ConvertGCEFirmwareVersionToSCRTMVersion(version uint32) []byte {
	if version == 0 {
		return []byte{}
	}
	versionString := GceVirtualFirmwarePrefix
	for _, b := range []byte(strconv.Itoa(int(version))) {
		// Convert ACSII to little-endian UCS-2
		versionString = append(versionString, b, 0)
	}
	// Add the null terminator
	return append(versionString, 0, 0)
}

// ParseGCENonHostInfo attempts to parse the Confidential VM
// technology used by a GCE VM from the GCE Non-Host info event. This data
// should come from a valid and verified EV_NONHOST_INFO event.
func ParseGCENonHostInfo(nonHostInfo []byte) (pb.GCEConfidentialTechnology, error) {
	prefixLen := len(GCENonHostInfoSignature)
	if len(nonHostInfo) < (prefixLen + 1) {
		return pb.GCEConfidentialTechnology_NONE, fmt.Errorf("length of GCE Non-Host info (%d) is too short", len(nonHostInfo))
	}

	if !bytes.Equal(nonHostInfo[:prefixLen], GCENonHostInfoSignature) {
		return pb.GCEConfidentialTechnology_NONE, errors.New("prefix for GCE Non-Host info is missing")
	}
	tech := nonHostInfo[prefixLen]
	if tech > byte(pb.GCEConfidentialTechnology_AMD_SEV_ES) {
		return pb.GCEConfidentialTechnology_NONE, fmt.Errorf("unknown GCE Confidential Technology: %d", tech)
	}
	return pb.GCEConfidentialTechnology(tech), nil
}
<|endoftext|>


<commit_before>package nv

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"reflect"
	"sort"

	xdr "github.com/davecgh/go-xdr/xdr2"
)

func Encode(i interface{}) ([]byte, error) {
	if i == nil {
		return nil, errors.New("can not encode a nil pointer")
	}

	v := reflect.ValueOf(i)
	if !v.IsValid() {
		return nil, fmt.Errorf("type '%s' is invalid", v.Kind().String())
	}

	var err error
	buff := bytes.NewBuffer(nil)
	if err = binary.Write(buff, binary.BigEndian, encoding{Encoding: 1, Endianess: 1}); err != nil {
		return nil, err
	}

	if err = encodeList(buff, v); err != nil {
		return nil, err
	}

	return buff.Bytes(), nil
}

func encodeList(w io.Writer, v reflect.Value) error {
	var err error
	if err = binary.Write(w, binary.BigEndian, header{Flag: _UNIQUE_NAME}); err != nil {
		return err
	}

	v = deref(v)
	switch v.Kind() {
	case reflect.Struct:
		_, err = encodeStruct(v, w)
	case reflect.Map:
		keys := make([]string, len(v.MapKeys()))
		for i, k := range v.MapKeys() {
			keys[i] = k.Interface().(string)
		}
		sort.Strings(keys)

		for _, name := range keys {
			_, err = encodeItem(w, name, nil, v.MapIndex(reflect.ValueOf(name)))
			if err != nil {
				return err
			}
		}
		err = binary.Write(w, binary.BigEndian, uint64(0))
	default:
		return fmt.Errorf("invalid type '%s', must be a struct", v.Kind().String())
	}

	return err
}

func encodeStruct(v reflect.Value, w io.Writer) (int, error) {
	var err error
	size := 0

	forEachField(v, func(i int, field reflect.Value) bool {
		// Skip fields that can't be set (e.g. unexported)
		if !field.CanSet() {
			return true
		}
		name := v.Type().Field(i).Name
		tags := getTags(i, v)
		if len(tags) > 0 && tags[0] != "" {
			name = tags[0]
		}

		if _, err = encodeItem(w, name, tags, field); err != nil {
			return false
		}
		return true
	})

	if err != nil {
		return 0, err
	}

	if err = binary.Write(w, binary.BigEndian, uint64(0)); err != nil {
		return 0, err
	}
	return size + 8, nil
}

func encodeItem(w io.Writer, name string, tags []string, field reflect.Value) ([]byte, error) {
	field = deref(field)
	var types = map[reflect.Kind]dataType{
		reflect.Bool:    _BOOLEAN_VALUE,
		reflect.Float32: _DOUBLE,
		reflect.Float64: _DOUBLE,
		reflect.Int16:   _INT16,
		reflect.Int32:   _INT32,
		reflect.Int64:   _INT64,
		reflect.Int8:    _INT8,
		reflect.Int:     _INT32,
		reflect.Map:     _NVLIST,
		reflect.String:  _STRING,
		reflect.Struct:  _NVLIST,
		reflect.Uint16:  _UINT16,
		reflect.Uint32:  _UINT32,
		reflect.Uint64:  _UINT64,
		reflect.Uint8:   _UINT8,
		reflect.Uint:    _UINT32,
	}

	var sliceTypes = map[reflect.Kind]dataType{
		reflect.Bool:   _BOOLEAN_ARRAY,
		reflect.Int16:  _INT16_ARRAY,
		reflect.Int32:  _INT32_ARRAY,
		reflect.Int64:  _INT64_ARRAY,
		reflect.Int8:   _INT8_ARRAY,
		reflect.Int:    _INT32_ARRAY,
		reflect.Map:    _NVLIST_ARRAY,
		reflect.String: _STRING_ARRAY,
		reflect.Struct: _NVLIST_ARRAY,
		reflect.Uint16: _UINT16_ARRAY,
		reflect.Uint32: _UINT32_ARRAY,
		reflect.Uint64: _UINT64_ARRAY,
		reflect.Uint8:  _UINT8_ARRAY,
		reflect.Uint:   _UINT32_ARRAY,
	}
	var tagType dataType
	if len(tags) > 1 {
		if tags[1] == "byte" {
			tagType = _BYTE
		} else if tags[1] == "uint8" {
			tagType = _UINT8
		}
	}

	p := pair{
		Name:      name,
		NElements: 1,
	}

	var ok bool
	p.Type, ok = types[field.Kind()]

	switch field.Kind() {
	case reflect.Bool:
		if field.Type().Name() == "Boolean" {
			p.Type = _BOOLEAN
		}
	case reflect.Interface:
		return encodeItem(w, name, tags, reflect.ValueOf(field.Interface()))
	case reflect.Slice, reflect.Array:
		p.Type, ok = sliceTypes[field.Type().Elem().Kind()]
		switch tagType {
		case _BYTE:
			p.Type = _BYTE_ARRAY
		case _UINT8:
			p.Type = _UINT8_ARRAY
		}
	case reflect.Int64:
		if field.Type().String() == "time.Duration" {
			p.Type = _HRTIME
		}
	case reflect.Uint8:
		switch tagType {
		case _BYTE:
			p.Type = _BYTE
		case _UINT8:
			p.Type = _UINT8
		}
	}

	if !ok {
		return nil, fmt.Errorf("unknown type: %v", field.Kind())
	}

	p.data = field.Interface()
	value := p.data
	vbuf := &bytes.Buffer{}
	switch p.Type {
	case _BOOLEAN:
		p.NElements = 0
	case _BYTE:
		value = int8(value.(uint8))
	case _UINT8:
		value = int(int8(value.(uint8)))
	case _BYTE_ARRAY:
		p.NElements = uint32(len(value.([]byte)))
		n := int(p.NElements)
		arrType := reflect.ArrayOf(n, reflect.TypeOf(byte(0)))
		arr := reflect.New(arrType).Elem()
		for i, b := range value.([]byte) {
			arr.Index(i).SetUint(uint64(b))
		}
		value = arr.Interface()
	case _BOOLEAN_ARRAY:
		p.NElements = uint32(len(value.([]bool)))
	case _INT8_ARRAY:
		p.NElements = uint32(len(value.([]int8)))
	case _INT16_ARRAY:
		p.NElements = uint32(len(value.([]int16)))
	case _INT32_ARRAY:
		p.NElements = uint32(len(value.([]int32)))
	case _INT64_ARRAY:
		p.NElements = uint32(len(value.([]int64)))
	case _UINT8_ARRAY:
		// this one is weird since UINT8s are encoded as char
		// aka int32s... :(
		p.NElements = uint32(len(value.([]uint8)))
		n := int(p.NElements)
		sliceType := reflect.SliceOf(reflect.TypeOf(int32(0)))
		slice := reflect.MakeSlice(sliceType, n, n)
		for i, b := range value.([]uint8) {
			slice.Index(i).SetInt(int64(int8(b)))
		}
		value = slice.Interface()
	case _UINT16_ARRAY:
		p.NElements = uint32(len(value.([]uint16)))
	case _UINT32_ARRAY:
		p.NElements = uint32(len(value.([]uint32)))
	case _UINT64_ARRAY:
		p.NElements = uint32(len(value.([]uint64)))
	case _STRING_ARRAY:
		p.NElements = uint32(len(value.([]string)))
		arrType := reflect.ArrayOf(int(p.NElements), reflect.TypeOf(""))
		arr := reflect.New(arrType).Elem()
		for i, b := range value.([]string) {
			arr.Index(i).SetString(b)
		}
		value = arr.Interface()
	case _NVLIST:
		if err := encodeList(vbuf, reflect.ValueOf(value)); err != nil {
			return nil, err
		}
		p.data = vbuf.Bytes()
	case _NVLIST_ARRAY:
		p.NElements = uint32(len(value.([]map[string]interface{})))
		for _, l := range value.([]map[string]interface{}) {
			if err := encodeList(vbuf, reflect.ValueOf(l)); err != nil {
				return nil, err
			}
		}
		p.data = vbuf.Bytes()
	}

	if vbuf.Len() == 0 && p.Type != _BOOLEAN {
		_, err := xdr.NewEncoder(vbuf).Encode(value)
		if err != nil {
			return nil, err
		}
	}

	p.EncodedSize = uint32(p.encodedSize())
	p.DecodedSize = uint32(p.decodedSize())

	pbuf := &bytes.Buffer{}
	_, err := xdr.NewEncoder(pbuf).Encode(p)
	if err != nil {
		return nil, err
	}

	_, err = pbuf.WriteTo(w)
	if err != nil {
		return nil, err
	}
	_, err = vbuf.WriteTo(w)
	if err != nil {
		return nil, err
	}

	return nil, nil
}
<commit_msg>remove always ignored []byte return from encodeItem<commit_after>package nv

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"reflect"
	"sort"

	xdr "github.com/davecgh/go-xdr/xdr2"
)

func Encode(i interface{}) ([]byte, error) {
	if i == nil {
		return nil, errors.New("can not encode a nil pointer")
	}

	v := reflect.ValueOf(i)
	if !v.IsValid() {
		return nil, fmt.Errorf("type '%s' is invalid", v.Kind().String())
	}

	var err error
	buff := bytes.NewBuffer(nil)
	if err = binary.Write(buff, binary.BigEndian, encoding{Encoding: 1, Endianess: 1}); err != nil {
		return nil, err
	}

	if err = encodeList(buff, v); err != nil {
		return nil, err
	}

	return buff.Bytes(), nil
}

func encodeList(w io.Writer, v reflect.Value) error {
	var err error
	if err = binary.Write(w, binary.BigEndian, header{Flag: _UNIQUE_NAME}); err != nil {
		return err
	}

	v = deref(v)
	switch v.Kind() {
	case reflect.Struct:
		_, err = encodeStruct(v, w)
	case reflect.Map:
		keys := make([]string, len(v.MapKeys()))
		for i, k := range v.MapKeys() {
			keys[i] = k.Interface().(string)
		}
		sort.Strings(keys)

		for _, name := range keys {
			v := v.MapIndex(reflect.ValueOf(name))
			if err := encodeItem(w, name, nil, v); err != nil {
				return err
			}
		}
		err = binary.Write(w, binary.BigEndian, uint64(0))
	default:
		return fmt.Errorf("invalid type '%s', must be a struct", v.Kind().String())
	}

	return err
}

func encodeStruct(v reflect.Value, w io.Writer) (int, error) {
	var err error
	size := 0

	forEachField(v, func(i int, field reflect.Value) bool {
		// Skip fields that can't be set (e.g. unexported)
		if !field.CanSet() {
			return true
		}
		name := v.Type().Field(i).Name
		tags := getTags(i, v)
		if len(tags) > 0 && tags[0] != "" {
			name = tags[0]
		}

		if err = encodeItem(w, name, tags, field); err != nil {
			return false
		}
		return true
	})

	if err != nil {
		return 0, err
	}

	if err = binary.Write(w, binary.BigEndian, uint64(0)); err != nil {
		return 0, err
	}
	return size + 8, nil
}

func encodeItem(w io.Writer, name string, tags []string, field reflect.Value) error {
	field = deref(field)
	var types = map[reflect.Kind]dataType{
		reflect.Bool:    _BOOLEAN_VALUE,
		reflect.Float32: _DOUBLE,
		reflect.Float64: _DOUBLE,
		reflect.Int16:   _INT16,
		reflect.Int32:   _INT32,
		reflect.Int64:   _INT64,
		reflect.Int8:    _INT8,
		reflect.Int:     _INT32,
		reflect.Map:     _NVLIST,
		reflect.String:  _STRING,
		reflect.Struct:  _NVLIST,
		reflect.Uint16:  _UINT16,
		reflect.Uint32:  _UINT32,
		reflect.Uint64:  _UINT64,
		reflect.Uint8:   _UINT8,
		reflect.Uint:    _UINT32,
	}

	var sliceTypes = map[reflect.Kind]dataType{
		reflect.Bool:   _BOOLEAN_ARRAY,
		reflect.Int16:  _INT16_ARRAY,
		reflect.Int32:  _INT32_ARRAY,
		reflect.Int64:  _INT64_ARRAY,
		reflect.Int8:   _INT8_ARRAY,
		reflect.Int:    _INT32_ARRAY,
		reflect.Map:    _NVLIST_ARRAY,
		reflect.String: _STRING_ARRAY,
		reflect.Struct: _NVLIST_ARRAY,
		reflect.Uint16: _UINT16_ARRAY,
		reflect.Uint32: _UINT32_ARRAY,
		reflect.Uint64: _UINT64_ARRAY,
		reflect.Uint8:  _UINT8_ARRAY,
		reflect.Uint:   _UINT32_ARRAY,
	}
	var tagType dataType
	if len(tags) > 1 {
		if tags[1] == "byte" {
			tagType = _BYTE
		} else if tags[1] == "uint8" {
			tagType = _UINT8
		}
	}

	p := pair{
		Name:      name,
		NElements: 1,
	}

	var ok bool
	p.Type, ok = types[field.Kind()]

	switch field.Kind() {
	case reflect.Bool:
		if field.Type().Name() == "Boolean" {
			p.Type = _BOOLEAN
		}
	case reflect.Interface:
		return encodeItem(w, name, tags, reflect.ValueOf(field.Interface()))
	case reflect.Slice, reflect.Array:
		p.Type, ok = sliceTypes[field.Type().Elem().Kind()]
		switch tagType {
		case _BYTE:
			p.Type = _BYTE_ARRAY
		case _UINT8:
			p.Type = _UINT8_ARRAY
		}
	case reflect.Int64:
		if field.Type().String() == "time.Duration" {
			p.Type = _HRTIME
		}
	case reflect.Uint8:
		switch tagType {
		case _BYTE:
			p.Type = _BYTE
		case _UINT8:
			p.Type = _UINT8
		}
	}

	if !ok {
		return fmt.Errorf("unknown type: %v", field.Kind())
	}

	p.data = field.Interface()
	value := p.data
	vbuf := &bytes.Buffer{}
	switch p.Type {
	case _BOOLEAN:
		p.NElements = 0
	case _BYTE:
		value = int8(value.(uint8))
	case _UINT8:
		value = int(int8(value.(uint8)))
	case _BYTE_ARRAY:
		p.NElements = uint32(len(value.([]byte)))
		n := int(p.NElements)
		arrType := reflect.ArrayOf(n, reflect.TypeOf(byte(0)))
		arr := reflect.New(arrType).Elem()
		for i, b := range value.([]byte) {
			arr.Index(i).SetUint(uint64(b))
		}
		value = arr.Interface()
	case _BOOLEAN_ARRAY:
		p.NElements = uint32(len(value.([]bool)))
	case _INT8_ARRAY:
		p.NElements = uint32(len(value.([]int8)))
	case _INT16_ARRAY:
		p.NElements = uint32(len(value.([]int16)))
	case _INT32_ARRAY:
		p.NElements = uint32(len(value.([]int32)))
	case _INT64_ARRAY:
		p.NElements = uint32(len(value.([]int64)))
	case _UINT8_ARRAY:
		// this one is weird since UINT8s are encoded as char
		// aka int32s... :(
		p.NElements = uint32(len(value.([]uint8)))
		n := int(p.NElements)
		sliceType := reflect.SliceOf(reflect.TypeOf(int32(0)))
		slice := reflect.MakeSlice(sliceType, n, n)
		for i, b := range value.([]uint8) {
			slice.Index(i).SetInt(int64(int8(b)))
		}
		value = slice.Interface()
	case _UINT16_ARRAY:
		p.NElements = uint32(len(value.([]uint16)))
	case _UINT32_ARRAY:
		p.NElements = uint32(len(value.([]uint32)))
	case _UINT64_ARRAY:
		p.NElements = uint32(len(value.([]uint64)))
	case _STRING_ARRAY:
		p.NElements = uint32(len(value.([]string)))
		arrType := reflect.ArrayOf(int(p.NElements), reflect.TypeOf(""))
		arr := reflect.New(arrType).Elem()
		for i, b := range value.([]string) {
			arr.Index(i).SetString(b)
		}
		value = arr.Interface()
	case _NVLIST:
		if err := encodeList(vbuf, reflect.ValueOf(value)); err != nil {
			return err
		}
		p.data = vbuf.Bytes()
	case _NVLIST_ARRAY:
		p.NElements = uint32(len(value.([]map[string]interface{})))
		for _, l := range value.([]map[string]interface{}) {
			if err := encodeList(vbuf, reflect.ValueOf(l)); err != nil {
				return err
			}
		}
		p.data = vbuf.Bytes()
	}

	if vbuf.Len() == 0 && p.Type != _BOOLEAN {
		_, err := xdr.NewEncoder(vbuf).Encode(value)
		if err != nil {
			return err
		}
	}

	p.EncodedSize = uint32(p.encodedSize())
	p.DecodedSize = uint32(p.decodedSize())

	pbuf := &bytes.Buffer{}
	_, err := xdr.NewEncoder(pbuf).Encode(p)
	if err != nil {
		return err
	}

	_, err = pbuf.WriteTo(w)
	if err != nil {
		return err
	}
	_, err = vbuf.WriteTo(w)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package handler

import (
	"image"

	"github.com/jfbus/impressionist/action"
	"github.com/jfbus/impressionist/log"
	"golang.org/x/net/context"
)

type Job struct {
	Ctx         context.Context
	ActionChain action.ActionChain
	res         chan JobResponse
}

type JobResponse struct {
	i   image.Image
	err error
}

var queue chan Job

func InitWorkers(n int) {
	log.Infof("Starting %d workers", n)
	queue = make(chan Job)
	for i := 0; i < n; i++ {
		go work(queue)
	}
}

func work(queue chan Job) {
	for {
		j := <-queue
		i, err := j.ActionChain.Apply(j.Ctx)
		j.res <- JobResponse{i, err}
	}
}

func Work(j Job) (image.Image, error) {
	j.res = make(chan JobResponse)
	queue <- j
	r := <-j.res
	return r.i, r.err
}
<commit_msg>handle timeout on worker queue insert<commit_after>package handler

import (
	"image"

	"github.com/jfbus/impressionist/action"
	ctxt "github.com/jfbus/impressionist/context"
	"github.com/jfbus/impressionist/log"
	"golang.org/x/net/context"
)

type Job struct {
	Ctx         context.Context
	ActionChain action.ActionChain
	res         chan JobResponse
}

type JobResponse struct {
	i   image.Image
	err error
}

var queue chan Job

func InitWorkers(n int) {
	log.Infof("Starting %d workers", n)
	queue = make(chan Job)
	for i := 0; i < n; i++ {
		go work(queue)
	}
}

func work(queue chan Job) {
	for j := range queue {
		i, err := j.ActionChain.Apply(j.Ctx)
		j.res <- JobResponse{i, err}
	}
}

func Work(j Job) (image.Image, error) {
	j.res = make(chan JobResponse)
	select {
	case <-j.Ctx.Done():
		return nil, ctxt.ErrTimeout
	case queue <- j:
	}
	r := <-j.res
	return r.i, r.err
}
<|endoftext|>


<commit_before>package haproxy

import (
	"log"
	"os"
	"os/exec"
	"strconv"
	"sync"
	"time"
)

type Event int
type Action int

const (
	HasStarted Event = 1 << iota
	HasStopped
	HasReloaded
)

const (
	WantsReload Action = 1 << iota
	WantsStop
)

type Server struct {
	Socket     string
	ActionChan chan Action
	cmd        *exec.Cmd
	sync.RWMutex
}

func (h *Server) createProcess() {
	h.cmd = exec.Command("/usr/local/bin/haproxy", "-f", "config/haproxy.conf")
}

func (h *Server) setupStdout() {
	h.cmd.Stdout = os.Stdout
	h.cmd.Stderr = os.Stderr
}

func (h *Server) runProcess() error {
	return h.cmd.Start()
}

func (h *Server) Start(notify chan Event, action chan Action) {
	h.Lock()
	h.createProcess()
	h.setupStdout()

	err := h.runProcess()

	if err != nil {
		log.Fatal(err)
	}

	h.ActionChan = action
	h.Unlock()

	notify <- HasStarted

	// Wait for a stop signal, reload signal, or process death
	for {
		switch <-action {
		case WantsReload:
			h.reloadProcess()
			notify <- HasReloaded
		case WantsStop:
			h.stopProcess()
			notify <- HasStopped
			return
		}
	}
}

func (h *Server) reloadProcess() error {

	h.Lock()

	// Grab pid of current running process
	old := h.cmd
	pid := strconv.Itoa(h.cmd.Process.Pid)

	// Start a new process, telling it to replace the old process
	cmd := exec.Command("/usr/local/bin/haproxy", "-f", "config/haproxy.conf", "-sf", pid)

	// Start the new process and check for errors. We bail out if there is
	// an error and DON'T replace the old process.
	err := cmd.Start()

	if err != nil {
		return err
	}

	// No errors? Replace the old process
	h.cmd = cmd
	h.finishOrKill(10*time.Second, old)

	return nil
}

func (h *Server) finishOrKill(waitFor time.Duration, old *exec.Cmd) {
	// Create a channel and wait for the old process
	// to finish itself
	didFinish := make(chan error, 1)
	go func() {
		didFinish <- old.Wait()
	}()

	// Wait for the didFinish channel or force kill the process
	// if it takes longer than 10 seconds
	select {
	case <-time.After(waitFor):
		log.Println("manually killing process")
		if err := old.Process.Kill(); err != nil {
			log.Println("failed to kill ", err)
		}
	case err := <-didFinish:
		if err != nil {
			log.Println("process finished with error", err)
		}
	}
}

func (h *Server) stopProcess() error {
	return h.cmd.Process.Kill()
}
<commit_msg>constantize binary path<commit_after>package haproxy

import (
	"log"
	"os"
	"os/exec"
	"strconv"
	"sync"
	"time"
)

type Event int
type Action int

const (
	HasStarted Event = 1 << iota
	HasStopped
	HasReloaded
)

const (
	WantsReload Action = 1 << iota
	WantsStop
)

type Server struct {
	Socket     string
	ActionChan chan Action
	cmd        *exec.Cmd
	sync.RWMutex
}

const BinaryPath = "/usr/local/bin/haproxy"

func (h *Server) createProcess() {
	h.cmd = exec.Command(BinaryPath, "-f", "config/haproxy.conf")
}

func (h *Server) setupStdout() {
	h.cmd.Stdout = os.Stdout
	h.cmd.Stderr = os.Stderr
}

func (h *Server) runProcess() error {
	return h.cmd.Start()
}

func (h *Server) Start(notify chan Event, action chan Action) {
	h.Lock()
	h.createProcess()
	h.setupStdout()

	err := h.runProcess()

	if err != nil {
		log.Fatal(err)
	}

	h.ActionChan = action
	h.Unlock()

	notify <- HasStarted

	// Wait for a stop signal, reload signal, or process death
	for {
		switch <-action {
		case WantsReload:
			h.reloadProcess()
			notify <- HasReloaded
		case WantsStop:
			h.stopProcess()
			notify <- HasStopped
			return
		}
	}
}

func (h *Server) reloadProcess() error {

	h.Lock()

	// Grab pid of current running process
	old := h.cmd
	pid := strconv.Itoa(h.cmd.Process.Pid)

	// Start a new process, telling it to replace the old process
	cmd := exec.Command("/usr/local/bin/haproxy", "-f", "config/haproxy.conf", "-sf", pid)

	// Start the new process and check for errors. We bail out if there is
	// an error and DON'T replace the old process.
	err := cmd.Start()

	if err != nil {
		return err
	}

	// No errors? Replace the old process
	h.cmd = cmd
	h.finishOrKill(10*time.Second, old)

	return nil
}

func (h *Server) finishOrKill(waitFor time.Duration, old *exec.Cmd) {
	// Create a channel and wait for the old process
	// to finish itself
	didFinish := make(chan error, 1)
	go func() {
		didFinish <- old.Wait()
	}()

	// Wait for the didFinish channel or force kill the process
	// if it takes longer than 10 seconds
	select {
	case <-time.After(waitFor):
		log.Println("manually killing process")
		if err := old.Process.Kill(); err != nil {
			log.Println("failed to kill ", err)
		}
	case err := <-didFinish:
		if err != nil {
			log.Println("process finished with error", err)
		}
	}
}

func (h *Server) stopProcess() error {
	return h.cmd.Process.Kill()
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 Timo Savola. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package catalog

import (
	"bytes"
	"context"
	"encoding/json"
	"sort"

	"gate.computer/gate/packet"
	"gate.computer/gate/service"
)

const (
	serviceName     = "catalog"
	serviceRevision = "0"
)

type catalog struct {
	r *service.Registry
}

// New catalog of registered services.  The catalog will reflect the changes
// made to the registry, but not its clones.
func New(r *service.Registry) service.Factory {
	return catalog{r}
}

func (c catalog) Properties() service.Properties {
	return service.Properties{
		Service: service.Service{
			Name:     serviceName,
			Revision: serviceRevision,
		},
	}
}

func (c catalog) Discoverable(context.Context) bool {
	return true
}

func (c catalog) CreateInstance(ctx context.Context, config service.InstanceConfig, snapshot []byte) (service.Instance, error) {
	inst := newInstance(c.r, config.Service)
	if err := inst.restore(snapshot); err != nil {
		return nil, err
	}

	return inst, nil
}

const (
	pendingNone byte = iota
	pendingJSON
	pendingError
)

type instance struct {
	service.InstanceBase

	r *service.Registry
	packet.Service

	pending byte
}

func newInstance(r *service.Registry, config packet.Service) *instance {
	return &instance{
		r:       r,
		Service: config,
	}
}

func (inst *instance) restore(snapshot []byte) (err error) {
	if len(snapshot) > 0 {
		inst.pending = snapshot[0]
	}

	return
}

func (inst *instance) Start(ctx context.Context, send chan<- packet.Thunk, abort func(error)) error {
	if inst.pending != pendingNone {
		inst.handleCall(ctx, send)
	}

	return nil
}

func (inst *instance) Handle(ctx context.Context, send chan<- packet.Thunk, p packet.Buf) (packet.Buf, error) {
	if p.Domain() == packet.DomainCall {
		if string(p.Content()) == "json" {
			inst.pending = pendingJSON
		} else {
			inst.pending = pendingError
		}

		inst.handleCall(ctx, send)
	}

	return nil, nil
}

func (inst *instance) handleCall(ctx context.Context, send chan<- packet.Thunk) {
	// TODO: correct buf size in advance
	b := bytes.NewBuffer(packet.MakeCall(inst.Code, 128)[:packet.HeaderSize])

	if inst.pending == pendingJSON {
		res := response{inst.r.Catalog(ctx)}
		sort.Sort(res)

		e := json.NewEncoder(b)
		e.SetIndent("", "\t")
		if err := e.Encode(res); err != nil {
			panic(err)
		}
	}

	select {
	case send <- func() packet.Buf { return b.Bytes() }:
		inst.pending = pendingNone

	case <-ctx.Done():
		return
	}
}

func (inst *instance) Suspend(ctx context.Context) ([]byte, error) {
	if inst.pending != pendingNone {
		return []byte{inst.pending}, nil
	}

	return nil, nil
}

type response struct {
	Services []service.Service `json:"services"`
}

func (r response) Len() int           { return len(r.Services) }
func (r response) Swap(i, j int)      { r.Services[i], r.Services[j] = r.Services[j], r.Services[i] }
func (r response) Less(i, j int) bool { return r.Services[i].Name < r.Services[j].Name }
<commit_msg>service/catalog: reply synchronously<commit_after>// Copyright (c) 2019 Timo Savola. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package catalog

import (
	"bytes"
	"context"
	"encoding/json"
	"sort"

	"gate.computer/gate/packet"
	"gate.computer/gate/service"
)

const (
	serviceName     = "catalog"
	serviceRevision = "0"
)

type catalog struct {
	r *service.Registry
}

// New catalog of registered services.  The catalog will reflect the changes
// made to the registry, but not its clones.
func New(r *service.Registry) service.Factory {
	return catalog{r}
}

func (c catalog) Properties() service.Properties {
	return service.Properties{
		Service: service.Service{
			Name:     serviceName,
			Revision: serviceRevision,
		},
	}
}

func (c catalog) Discoverable(context.Context) bool {
	return true
}

func (c catalog) CreateInstance(ctx context.Context, config service.InstanceConfig, snapshot []byte) (service.Instance, error) {
	return newInstance(c.r, config.Service), nil
}

type instance struct {
	service.InstanceBase

	r *service.Registry
	packet.Service
}

func newInstance(r *service.Registry, config packet.Service) *instance {
	return &instance{
		r:       r,
		Service: config,
	}
}

func (inst *instance) Handle(ctx context.Context, send chan<- packet.Thunk, p packet.Buf) (packet.Buf, error) {
	if p.Domain() != packet.DomainCall {
		return nil, nil
	}

	// TODO: correct buf size in advance
	b := bytes.NewBuffer(packet.MakeCall(inst.Code, 128)[:packet.HeaderSize])

	if string(p.Content()) == "json" {
		res := response{inst.r.Catalog(ctx)}
		sort.Sort(res)

		e := json.NewEncoder(b)
		e.SetIndent("", "\t")
		if err := e.Encode(res); err != nil {
			panic(err)
		}
	}

	return b.Bytes(), nil
}

type response struct {
	Services []service.Service `json:"services"`
}

func (r response) Len() int           { return len(r.Services) }
func (r response) Swap(i, j int)      { r.Services[i], r.Services[j] = r.Services[j], r.Services[i] }
func (r response) Less(i, j int) bool { return r.Services[i].Name < r.Services[j].Name }
<|endoftext|>


<commit_before>package matrix

import (
	"bytes"
	"io"
	"log"
	"os"
	"sync"
	"syscall"
	"testing"

	"github.com/rfjakob/gocryptfs/tests/test_helpers"
)

// https://github.com/rfjakob/gocryptfs/issues/363
//
// Note: this test calls log.Fatal() instead of t.Fatal() because apparently,
// calling t.Fatal() from a goroutine hangs the test.
func TestConcurrentReadWrite(t *testing.T) {
	var wg sync.WaitGroup
	fn := test_helpers.DefaultPlainDir + "/TestConcurrentReadWrite"
	if f, err := os.Create(fn); err != nil {
		t.Fatal(err)
	} else {
		f.Close()
	}
	buf := make([]byte, 100)
	content := []byte("1234567890")
	threads := 10
	loops := 30
	for i := 0; i < threads; i++ {
		// Reader thread
		wg.Add(1)
		go func() {
			fRd, err := os.Open(fn)
			if err != nil {
				log.Fatal(err)
			}
			for j := 0; j < loops; j++ {
				n, err := fRd.ReadAt(buf, 0)
				if err != nil && err != io.EOF {
					log.Fatal(err)
				}
				if n != 0 && n != 10 {
					log.Fatalf("strange read length: %d", n)
				}
			}
			fRd.Close()
			wg.Done()
		}()

		// Writer thread
		wg.Add(1)
		go func() {
			fWr, err := os.OpenFile(fn, os.O_RDWR, 0700)
			if err != nil {
				log.Fatal(err)
			}
			for j := 0; j < loops; j++ {
				err = fWr.Truncate(0)
				if err != nil {
					log.Fatal(err)
				}
				_, err = fWr.WriteAt(content, 0)
				if err != nil {
					log.Fatal(err)
				}
			}
			fWr.Close()
			wg.Done()
		}()
	}
	wg.Wait()
}

// https://github.com/rfjakob/gocryptfs/issues/363
//
// Note: this test calls log.Fatal() instead of t.Fatal() because apparently,
// calling t.Fatal() from a goroutine hangs the test.
func TestConcurrentReadCreate(t *testing.T) {
	fn := test_helpers.DefaultPlainDir + "/TestConcurrentReadCreate"
	content := []byte("1234567890")
	loops := 100
	var wg sync.WaitGroup
	// "Create()" thread
	wg.Add(1)
	go func() {
		for i := 0; i < loops; i++ {
			f, err := os.Create(fn)
			if err != nil {
				log.Fatal(err)
			}
			_, err = f.Write(content)
			if err != nil {
				log.Fatal(err)
			}
			f.Close()
			syscall.Unlink(fn)
		}
		wg.Done()
	}()
	// "Reader" thread
	wg.Add(1)
	go func() {
		buf0 := make([]byte, 100)
		for i := 0; i < loops; i++ {
			f, err := os.Open(fn)
			if err != nil {
				i++
				continue
			}
			n, err := f.Read(buf0)
			if err == io.EOF {
				i++
				continue
			}
			if err != nil {
				log.Fatal(err)
			}
			buf := buf0[:n]
			if bytes.Compare(buf, content) != 0 {
				log.Fatal("content mismatch")
			}
			f.Close()
		}
		wg.Done()
	}()
	wg.Wait()
}
<commit_msg>tests: add TestInoReuse<commit_after>package matrix

import (
	"bytes"
	"io"
	"log"
	"os"
	"sync"
	"syscall"
	"testing"

	"github.com/rfjakob/gocryptfs/tests/test_helpers"
)

// https://github.com/rfjakob/gocryptfs/issues/363
//
// Note: this test calls log.Fatal() instead of t.Fatal() because apparently,
// calling t.Fatal() from a goroutine hangs the test.
func TestConcurrentReadWrite(t *testing.T) {
	var wg sync.WaitGroup
	fn := test_helpers.DefaultPlainDir + "/TestConcurrentReadWrite"
	if f, err := os.Create(fn); err != nil {
		t.Fatal(err)
	} else {
		f.Close()
	}
	buf := make([]byte, 100)
	content := []byte("1234567890")
	threads := 10
	loops := 30
	for i := 0; i < threads; i++ {
		// Reader thread
		wg.Add(1)
		go func() {
			fRd, err := os.Open(fn)
			if err != nil {
				log.Fatal(err)
			}
			for j := 0; j < loops; j++ {
				n, err := fRd.ReadAt(buf, 0)
				if err != nil && err != io.EOF {
					log.Fatal(err)
				}
				if n != 0 && n != 10 {
					log.Fatalf("strange read length: %d", n)
				}
			}
			fRd.Close()
			wg.Done()
		}()

		// Writer thread
		wg.Add(1)
		go func() {
			fWr, err := os.OpenFile(fn, os.O_RDWR, 0700)
			if err != nil {
				log.Fatal(err)
			}
			for j := 0; j < loops; j++ {
				err = fWr.Truncate(0)
				if err != nil {
					log.Fatal(err)
				}
				_, err = fWr.WriteAt(content, 0)
				if err != nil {
					log.Fatal(err)
				}
			}
			fWr.Close()
			wg.Done()
		}()
	}
	wg.Wait()
}

// https://github.com/rfjakob/gocryptfs/issues/363
//
// Note: this test calls log.Fatal() instead of t.Fatal() because apparently,
// calling t.Fatal() from a goroutine hangs the test.
func TestConcurrentReadCreate(t *testing.T) {
	fn := test_helpers.DefaultPlainDir + "/TestConcurrentReadCreate"
	content := []byte("1234567890")
	loops := 100
	var wg sync.WaitGroup
	// "Create()" thread
	wg.Add(1)
	go func() {
		for i := 0; i < loops; i++ {
			f, err := os.Create(fn)
			if err != nil {
				log.Fatal(err)
			}
			_, err = f.Write(content)
			if err != nil {
				log.Fatal(err)
			}
			f.Close()
			syscall.Unlink(fn)
		}
		wg.Done()
	}()
	// "Reader" thread
	wg.Add(1)
	go func() {
		buf0 := make([]byte, 100)
		for i := 0; i < loops; i++ {
			f, err := os.Open(fn)
			if err != nil {
				i++
				continue
			}
			n, err := f.Read(buf0)
			if err == io.EOF {
				i++
				continue
			}
			if err != nil {
				log.Fatal(err)
			}
			buf := buf0[:n]
			if bytes.Compare(buf, content) != 0 {
				log.Fatal("content mismatch")
			}
			f.Close()
		}
		wg.Done()
	}()
	wg.Wait()
}

// TestInoReuse tries to uncover problems when a file gets replaced by
// a directory with the same inode number (and vice versa).
//
// So far, it only has triggered warnings like this
//
//     go-fuse: warning: Inode.Path: inode i4201033 is orphaned, replacing segment with ".go-fuse.5577006791947779410/deleted"
//
// but none of the "blocked waiting for FORGET".
func TestInoReuse(t *testing.T) {
	var wg sync.WaitGroup
	fn := test_helpers.DefaultPlainDir + "/" + t.Name()

	wg.Add(1)
	go func() {
		for i := 0; i < 1000; i++ {
			fd, err := syscall.Creat(fn, 0600)
			if err == syscall.EISDIR {
				continue
			}
			if err != nil {
				t.Error(err)
				break
			}
			var st syscall.Stat_t
			syscall.Fstat(fd, &st)
			if i%2 == 0 {
				syscall.Close(fd)
				syscall.Unlink(fn)
			} else {
				syscall.Unlink(fn)
				syscall.Close(fd)

			}
		}
		wg.Done()
	}()

	wg.Add(1)
	go func() {
		for i := 0; i < 1000; i++ {
			err := syscall.Mkdir(fn, 0700)
			if err == syscall.EEXIST {
				continue
			}
			if err != nil {
				t.Error(err)
				break
			}
			var st syscall.Stat_t
			syscall.Stat(fn, &st)
			syscall.Rmdir(fn)
		}
		wg.Done()
	}()
	wg.Wait()
}
<|endoftext|>


<commit_before>package chromedp

import (
	"bytes"
	"context"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"testing"
	"time"
)

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

	allocCtx, cancel := NewExecAllocator(context.Background(), allocOpts...)
	defer cancel()

	// TODO: test that multiple child contexts are run in different
	// processes and browsers.

	taskCtx, cancel := NewContext(allocCtx)
	defer cancel()

	want := "insert"
	var got string
	if err := Run(taskCtx,
		Navigate(testdataDir+"/form.html"),
		Text("#foo", &got, ByID),
	); err != nil {
		t.Fatal(err)
	}
	if got != want {
		t.Fatalf("want %q, got %q", want, got)
	}

	cancel()

	tempDir := FromContext(taskCtx).Browser.userDataDir
	if _, err := os.Lstat(tempDir); !os.IsNotExist(err) {
		t.Fatalf("temporary user data dir %q not deleted", tempDir)
	}
}

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

	allocCtx, allocCancel := NewExecAllocator(context.Background(), allocOpts...)
	defer allocCancel()

	// TODO: test that multiple child contexts are run in different
	// processes and browsers.

	taskCtx, _ := NewContext(allocCtx)
	if err := Run(taskCtx); err != nil {
		t.Fatal(err)
	}

	// Canceling the pool context should stop all browsers too.
	allocCancel()

	tempDir := FromContext(taskCtx).Browser.userDataDir
	if _, err := os.Lstat(tempDir); !os.IsNotExist(err) {
		t.Fatalf("temporary user data dir %q not deleted", tempDir)
	}
}

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

	// Simulate a scenario where we navigate to a page that never responds,
	// and the browser is closed while it's loading.
	ctx, cancel := testAllocateSeparate(t)
	defer cancel()
	if err := Run(ctx); err != nil {
		t.Fatal(err)
	}

	kill := make(chan struct{}, 1)
	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		kill <- struct{}{}
		<-ctx.Done() // block until the end of the test
	}))
	defer s.Close()
	go func() {
		<-kill
		b := FromContext(ctx).Browser
		if err := b.process.Signal(os.Kill); err != nil {
			t.Error(err)
		}
	}()

	// Run should error with something other than "deadline exceeded" in
	// much less than 5s.
	ctx2, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()
	switch err := Run(ctx2, Navigate(s.URL)); err {
	case nil:
		// TODO: figure out why this happens sometimes on Travis
		// t.Fatal("did not expect a nil error")
	case context.DeadlineExceeded:
		t.Fatalf("did not expect a standard context error: %v", err)
	}
}

func TestSkipNewContext(t *testing.T) {
	ctx, cancel := NewExecAllocator(context.Background(), allocOpts...)
	defer cancel()

	// Using the allocator context directly (without calling NewContext)
	// should be an immediate error.
	err := Run(ctx, Navigate(testdataDir+"/form.html"))

	want := ErrInvalidContext
	if err != want {
		t.Fatalf("want error to be %q, got %q", want, err)
	}
}

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

	tempDir, err := ioutil.TempDir("", "chromedp-runner")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tempDir)

	procCtx, cancel := context.WithCancel(context.Background())
	defer cancel()
	cmd := exec.CommandContext(procCtx, execPath,
		// TODO: deduplicate these with allocOpts in chromedp_test.go
		"--no-first-run",
		"--no-default-browser-check",
		"--headless",
		"--disable-gpu",
		"--no-sandbox",

		// TODO: perhaps deduplicate this code with ExecAllocator
		"--user-data-dir="+tempDir,
		"--remote-debugging-port=0",
		"about:blank",
	)

	stderr, err := cmd.StderrPipe()
	if err != nil {
		t.Fatal(err)
	}
	defer stderr.Close()
	if err := cmd.Start(); err != nil {
		t.Fatal(err)
	}
	wsURL, err := readOutput(stderr, nil, nil)
	if err != nil {
		t.Fatal(err)
	}
	allocCtx, allocCancel := NewRemoteAllocator(context.Background(), wsURL)
	defer allocCancel()

	taskCtx, taskCancel := NewContext(allocCtx)
	defer taskCancel()
	want := "insert"
	var got string
	if err := Run(taskCtx,
		Navigate(testdataDir+"/form.html"),
		Text("#foo", &got, ByID),
	); err != nil {
		t.Fatal(err)
	}
	if got != want {
		t.Fatalf("want %q, got %q", want, got)
	}
	targetID := FromContext(taskCtx).Target.TargetID
	if err := Cancel(taskCtx); err != nil {
		t.Fatal(err)
	}

	// Check that cancel closed the tabs. Don't just count the
	// number of targets, as perhaps the initial blank tab hasn't
	// come up yet.
	targetsCtx, targetsCancel := NewContext(allocCtx)
	defer targetsCancel()
	infos, err := Targets(targetsCtx)
	if err != nil {
		t.Fatal(err)
	}
	for _, info := range infos {
		if info.TargetID == targetID {
			t.Fatalf("target from previous iteration wasn't closed: %v", targetID)
		}
	}
	targetsCancel()

	// Finally, if we kill the browser and the websocket connection drops,
	// Run should error way before the 5s timeout.
	// TODO: a "defer cancel()" here adds a 1s timeout, since we try to
	// close the target twice. Fix that.
	ctx, _ := NewContext(allocCtx)
	ctx, cancel = context.WithTimeout(ctx, 5*time.Second)
	defer cancel()

	// Connect to the browser, then kill it.
	if err := Run(ctx); err != nil {
		t.Fatal(err)
	}
	if err := cmd.Process.Signal(os.Kill); err != nil {
		t.Error(err)
	}
	switch err := Run(ctx, Navigate(testdataDir+"/form.html")); err {
	case nil:
		// TODO: figure out why this happens sometimes on Travis
		// t.Fatal("did not expect a nil error")
	case context.DeadlineExceeded:
		t.Fatalf("did not expect a standard context error: %v", err)
	}
}

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

	allocCtx, cancel := NewExecAllocator(context.Background(),
		// Use a bad listen address, so Chrome exits straight away.
		append([]ExecAllocatorOption{Flag("remote-debugging-address", "_")},
			allocOpts...)...)
	defer cancel()

	ctx, cancel := NewContext(allocCtx)
	defer cancel()

	want := regexp.MustCompile(`failed to start:\n.*Invalid devtools`)
	got := fmt.Sprintf("%v", Run(ctx))
	if !want.MatchString(got) {
		t.Fatalf("want error to match %q, got %q", want, got)
	}
}

func TestCombinedOutput(t *testing.T) {
	t.Skip("FIXME: currently failing on travis and docker")
	t.Parallel()

	buf := new(bytes.Buffer)
	allocCtx, cancel := NewExecAllocator(context.Background(),
		append([]ExecAllocatorOption{
			CombinedOutput(buf),
			Flag("enable-logging", true),
		}, allocOpts...)...)
	defer cancel()

	taskCtx, _ := NewContext(allocCtx)
	if err := Run(taskCtx,
		Navigate(testdataDir+"/consolespam.html"),
	); err != nil {
		t.Fatal(err)
	}
	cancel()
	if !strings.Contains(buf.String(), "DevTools listening on") {
		t.Fatalf("failed to find websocket string in browser output test")
	}
	if want, got := 2000, strings.Count(buf.String(), `"spam"`); want != got {
		t.Fatalf("want %d spam console logs, got %d", want, got)
	}
}

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

	// CombinedOutput used to hang the allocator if Chrome errored straight
	// away, as there was no output to copy and the CombinedOutput would
	// never signal it's done.
	buf := new(bytes.Buffer)
	allocCtx, cancel := NewExecAllocator(context.Background(),
		// Use a bad listen address, so Chrome exits straight away.
		append([]ExecAllocatorOption{
			Flag("remote-debugging-address", "_"),
			CombinedOutput(buf),
		}, allocOpts...)...)
	defer cancel()

	ctx, cancel := NewContext(allocCtx)
	defer cancel()
	got := fmt.Sprint(Run(ctx))
	want := "failed to start"
	if !strings.Contains(got, want) {
		t.Fatalf("got %q, want %q", got, want)
	}
}
<commit_msg>fix and reenable TestCombinedOutput<commit_after>package chromedp

import (
	"bytes"
	"context"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"testing"
	"time"
)

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

	allocCtx, cancel := NewExecAllocator(context.Background(), allocOpts...)
	defer cancel()

	// TODO: test that multiple child contexts are run in different
	// processes and browsers.

	taskCtx, cancel := NewContext(allocCtx)
	defer cancel()

	want := "insert"
	var got string
	if err := Run(taskCtx,
		Navigate(testdataDir+"/form.html"),
		Text("#foo", &got, ByID),
	); err != nil {
		t.Fatal(err)
	}
	if got != want {
		t.Fatalf("want %q, got %q", want, got)
	}

	cancel()

	tempDir := FromContext(taskCtx).Browser.userDataDir
	if _, err := os.Lstat(tempDir); !os.IsNotExist(err) {
		t.Fatalf("temporary user data dir %q not deleted", tempDir)
	}
}

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

	allocCtx, allocCancel := NewExecAllocator(context.Background(), allocOpts...)
	defer allocCancel()

	// TODO: test that multiple child contexts are run in different
	// processes and browsers.

	taskCtx, _ := NewContext(allocCtx)
	if err := Run(taskCtx); err != nil {
		t.Fatal(err)
	}

	// Canceling the pool context should stop all browsers too.
	allocCancel()

	tempDir := FromContext(taskCtx).Browser.userDataDir
	if _, err := os.Lstat(tempDir); !os.IsNotExist(err) {
		t.Fatalf("temporary user data dir %q not deleted", tempDir)
	}
}

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

	// Simulate a scenario where we navigate to a page that never responds,
	// and the browser is closed while it's loading.
	ctx, cancel := testAllocateSeparate(t)
	defer cancel()
	if err := Run(ctx); err != nil {
		t.Fatal(err)
	}

	kill := make(chan struct{}, 1)
	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		kill <- struct{}{}
		<-ctx.Done() // block until the end of the test
	}))
	defer s.Close()
	go func() {
		<-kill
		b := FromContext(ctx).Browser
		if err := b.process.Signal(os.Kill); err != nil {
			t.Error(err)
		}
	}()

	// Run should error with something other than "deadline exceeded" in
	// much less than 5s.
	ctx2, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()
	switch err := Run(ctx2, Navigate(s.URL)); err {
	case nil:
		// TODO: figure out why this happens sometimes on Travis
		// t.Fatal("did not expect a nil error")
	case context.DeadlineExceeded:
		t.Fatalf("did not expect a standard context error: %v", err)
	}
}

func TestSkipNewContext(t *testing.T) {
	ctx, cancel := NewExecAllocator(context.Background(), allocOpts...)
	defer cancel()

	// Using the allocator context directly (without calling NewContext)
	// should be an immediate error.
	err := Run(ctx, Navigate(testdataDir+"/form.html"))

	want := ErrInvalidContext
	if err != want {
		t.Fatalf("want error to be %q, got %q", want, err)
	}
}

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

	tempDir, err := ioutil.TempDir("", "chromedp-runner")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tempDir)

	procCtx, cancel := context.WithCancel(context.Background())
	defer cancel()
	cmd := exec.CommandContext(procCtx, execPath,
		// TODO: deduplicate these with allocOpts in chromedp_test.go
		"--no-first-run",
		"--no-default-browser-check",
		"--headless",
		"--disable-gpu",
		"--no-sandbox",

		// TODO: perhaps deduplicate this code with ExecAllocator
		"--user-data-dir="+tempDir,
		"--remote-debugging-port=0",
		"about:blank",
	)

	stderr, err := cmd.StderrPipe()
	if err != nil {
		t.Fatal(err)
	}
	defer stderr.Close()
	if err := cmd.Start(); err != nil {
		t.Fatal(err)
	}
	wsURL, err := readOutput(stderr, nil, nil)
	if err != nil {
		t.Fatal(err)
	}
	allocCtx, allocCancel := NewRemoteAllocator(context.Background(), wsURL)
	defer allocCancel()

	taskCtx, taskCancel := NewContext(allocCtx)
	defer taskCancel()
	want := "insert"
	var got string
	if err := Run(taskCtx,
		Navigate(testdataDir+"/form.html"),
		Text("#foo", &got, ByID),
	); err != nil {
		t.Fatal(err)
	}
	if got != want {
		t.Fatalf("want %q, got %q", want, got)
	}
	targetID := FromContext(taskCtx).Target.TargetID
	if err := Cancel(taskCtx); err != nil {
		t.Fatal(err)
	}

	// Check that cancel closed the tabs. Don't just count the
	// number of targets, as perhaps the initial blank tab hasn't
	// come up yet.
	targetsCtx, targetsCancel := NewContext(allocCtx)
	defer targetsCancel()
	infos, err := Targets(targetsCtx)
	if err != nil {
		t.Fatal(err)
	}
	for _, info := range infos {
		if info.TargetID == targetID {
			t.Fatalf("target from previous iteration wasn't closed: %v", targetID)
		}
	}
	targetsCancel()

	// Finally, if we kill the browser and the websocket connection drops,
	// Run should error way before the 5s timeout.
	// TODO: a "defer cancel()" here adds a 1s timeout, since we try to
	// close the target twice. Fix that.
	ctx, _ := NewContext(allocCtx)
	ctx, cancel = context.WithTimeout(ctx, 5*time.Second)
	defer cancel()

	// Connect to the browser, then kill it.
	if err := Run(ctx); err != nil {
		t.Fatal(err)
	}
	if err := cmd.Process.Signal(os.Kill); err != nil {
		t.Error(err)
	}
	switch err := Run(ctx, Navigate(testdataDir+"/form.html")); err {
	case nil:
		// TODO: figure out why this happens sometimes on Travis
		// t.Fatal("did not expect a nil error")
	case context.DeadlineExceeded:
		t.Fatalf("did not expect a standard context error: %v", err)
	}
}

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

	allocCtx, cancel := NewExecAllocator(context.Background(),
		// Use a bad listen address, so Chrome exits straight away.
		append([]ExecAllocatorOption{Flag("remote-debugging-address", "_")},
			allocOpts...)...)
	defer cancel()

	ctx, cancel := NewContext(allocCtx)
	defer cancel()

	want := regexp.MustCompile(`failed to start:\n.*Invalid devtools`)
	got := fmt.Sprintf("%v", Run(ctx))
	if !want.MatchString(got) {
		t.Fatalf("want error to match %q, got %q", want, got)
	}
}

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

	buf := new(bytes.Buffer)
	allocCtx, cancel := NewExecAllocator(context.Background(),
		append([]ExecAllocatorOption{
			CombinedOutput(buf),
			Flag("enable-logging", true),
		}, allocOpts...)...)
	defer cancel()

	taskCtx, _ := NewContext(allocCtx)
	if err := Run(taskCtx,
		Navigate(testdataDir+"/consolespam.html"),
	); err != nil {
		t.Fatal(err)
	}
	cancel()
	if !strings.Contains(buf.String(), "DevTools listening on") {
		t.Fatalf("failed to find websocket string in browser output test")
	}
	// Recent chrome versions have started replacing many "spam" messages
	// with "spam 1", "spam 2", and so on. Search for the prefix only.
	if want, got := 2000, strings.Count(buf.String(), `"spam`); want != got {
		t.Fatalf("want %d spam console logs, got %d", want, got)
	}
}

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

	// CombinedOutput used to hang the allocator if Chrome errored straight
	// away, as there was no output to copy and the CombinedOutput would
	// never signal it's done.
	buf := new(bytes.Buffer)
	allocCtx, cancel := NewExecAllocator(context.Background(),
		// Use a bad listen address, so Chrome exits straight away.
		append([]ExecAllocatorOption{
			Flag("remote-debugging-address", "_"),
			CombinedOutput(buf),
		}, allocOpts...)...)
	defer cancel()

	ctx, cancel := NewContext(allocCtx)
	defer cancel()
	got := fmt.Sprint(Run(ctx))
	want := "failed to start"
	if !strings.Contains(got, want) {
		t.Fatalf("got %q, want %q", got, want)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"net/url"
	"strings"

	"context"

	_ "github.com/lib/pq" // Register Postgres driver
)

type postgresqlResource struct {
	url.URL
}

func (r *postgresqlResource) Await(ctx context.Context) error {
	dsnURL := r.URL
	tags := parseTags(dsnURL.Fragment)
	dsnURL.Fragment = ""
	dsn := dsnURL.String()

	db, err := sql.Open(r.URL.Scheme, dsn)
	if err != nil {
		return err
	}
	defer db.Close()

	if err := db.Ping(); err != nil {
		return ErrUnavailable
	}

	if val, ok := tags["tables"]; ok {
		tables := strings.Split(val, ",")
		if err := awaitPostgreSQLTables(db, dsnURL.Path[1:], tables); err != nil {
		}
	}

	return nil
}

func awaitPostgreSQLTables(db *sql.DB, dbName string, tables []string) error {
	if len(tables) == 0 {
		const stmt = `SELECT count(*) FROM information_schema.tables WHERE table_schema=?`
		var tableCnt int
		if err := db.QueryRow(stmt, dbName).Scan(&tableCnt); err != nil {
			return err
		}

		if tableCnt == 0 {
			return ErrUnavailable
		}

		return nil
	}

	const stmt = `SELECT table_name FROM information_schema.tables WHERE table_schema=?`
	rows, err := db.Query(stmt, dbName)
	if err != nil {
		return err
	}
	defer rows.Close()

	var actualTables []string
	for rows.Next() {
		var t string
		if err := rows.Scan(&t); err != nil {
			return err
		}
		actualTables = append(actualTables, t)
	}

	if err := rows.Err(); err != nil {
		return err
	}

	contains := func(l []string, s string) bool {
		for _, i := range l {
			if i == s {
				return true
			}
		}
		return false
	}

	for _, t := range tables {
		if !contains(actualTables, t) {
			return ErrUnavailable
		}
	}

	return nil
}
<commit_msg>Fix discovering tables in postgres<commit_after>package main

import (
	"database/sql"
	"net/url"
	"strings"

	"context"

	_ "github.com/lib/pq" // Register Postgres driver
)

type postgresqlResource struct {
	url.URL
}

func (r *postgresqlResource) Await(ctx context.Context) error {
	dsnURL := r.URL
	tags := parseTags(dsnURL.Fragment)
	dsnURL.Fragment = ""
	dsn := dsnURL.String()

	db, err := sql.Open(r.URL.Scheme, dsn)
	if err != nil {
		return err
	}
	defer db.Close()

	if err := db.Ping(); err != nil {
		return ErrUnavailable
	}

	if val, ok := tags["tables"]; ok {
		tables := strings.Split(val, ",")
		if err := awaitPostgreSQLTables(db, dsnURL.Path[1:], tables); err != nil {
		}
	}

	return nil
}

func awaitPostgreSQLTables(db *sql.DB, dbName string, tables []string) error {
	if len(tables) == 0 {
		const stmt = `SELECT count(*) FROM information_schema.tables WHERE table_catalog=? AND table_schema='public'`
		var tableCnt int
		if err := db.QueryRow(stmt, dbName).Scan(&tableCnt); err != nil {
			return err
		}

		if tableCnt == 0 {
			return ErrUnavailable
		}

		return nil
	}

	const stmt = `SELECT table_name FROM information_schema.tables WHERE table_catalog=? AND table_schema='public'`
	rows, err := db.Query(stmt, dbName)
	if err != nil {
		return err
	}
	defer rows.Close()

	var actualTables []string
	for rows.Next() {
		var t string
		if err := rows.Scan(&t); err != nil {
			return err
		}
		actualTables = append(actualTables, t)
	}

	if err := rows.Err(); err != nil {
		return err
	}

	contains := func(l []string, s string) bool {
		for _, i := range l {
			if i == s {
				return true
			}
		}
		return false
	}

	for _, t := range tables {
		if !contains(actualTables, t) {
			return ErrUnavailable
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"time"

	"github.com/full360/health/cloudwatch"
	"github.com/full360/health/consul"
	"github.com/full360/health/log"
)

// serviceCheckConfig is used to represent the configuration of a service check
type serviceCheckConfig struct {
	name            string
	tag             string
	metricName      string
	metricNamespace string
	blockTime       time.Duration
	logger          *log.Logger
}

// serviceCheck is used to represent a single service check with consul,
// cloudwatch and a logger
type serviceCheck struct {
	consul *consul.Check
	metric *cloudwatch.Metric
	logger *log.Logger
}

// defaultServiceCheck returns a defaul service check config
func defaultServiceCheck() *serviceCheckConfig {
	return &serviceCheckConfig{
		name:            "service",
		tag:             "tag",
		MetricName:      "service_monitoring",
		metricNamespace: "microservices",
		blockTime:       10 * time.Minute,
		logger:          log.NewLogger(),
	}
}

// newServiceCheck returns a new service check
func newServiceCheck(svcConfig *serviceCheckConfig) (*serviceCheck, error) {
	consul, err := consul.NewCheck(&consul.CheckConfig{
		Service:     svcConfig.name,
		Tag:         svcConfig.tag,
		PassingOnly: true,
		BlockTime:   svcConfig.blockTime,
	})
	if err != nil {
		return nil, err
	}

	svcCheck := &serviceCheck{
		consul: consul,
		metric: cloudwatch.NewMetric(&cloudwatch.MetricConfig{
			Name:      svcConfig.metricName,
			Namespace: svcConfig.metricNamespace,
			Service: &cloudwatch.Service{
				Name: svcConfig.name,
				Env:  svcConfig.tag,
			},
			Value: 0,
		}),
		logger: svcConfig.logger,
	}
	return svcCheck, nil
}

// loopCheck does an infinite loop calling serviceCheck
func (sc *serviceCheck) loopCheck() {
	for {
		err := sc.check()
		if err != nil {
			time.Sleep(10 * time.Second)
		}
	}
}

// check checks if a service is healthy and posts that data to a Cloudwatch
// metric based on the service name and environment
func (sc *serviceCheck) check() error {
	count, qm, err := sc.consul.Healthy()
	if err != nil {
		sc.logger.Error("Could not retrieve service count from Consul: %v", err)
		return err
	}
	// debug logging for Consul request
	sc.logger.Debug("Consul Query metadata, Request Time: %s, Last Index: %d", qm.RequestTime, qm.LastIndex)
	// Set the last response index as the wait index for the next request to
	// successfully do a blocking query
	sc.consul.QueryOptions.WaitIndex = qm.LastIndex
	sc.logger.Info("Service count: %d, with name: %s and tag: %s", count, sc.consul.Config.Service, sc.consul.Config.Tag)

	_, err = sc.metric.Put(float64(count))
	if err != nil {
		sc.logger.Error("Could not post metric to CloudWatch: %v", err)
		return err
	}
	return nil
}
<commit_msg>Fix the attribute name<commit_after>package main

import (
	"time"

	"github.com/full360/health/cloudwatch"
	"github.com/full360/health/consul"
	"github.com/full360/health/log"
)

// serviceCheckConfig is used to represent the configuration of a service check
type serviceCheckConfig struct {
	name            string
	tag             string
	metricName      string
	metricNamespace string
	blockTime       time.Duration
	logger          *log.Logger
}

// serviceCheck is used to represent a single service check with consul,
// cloudwatch and a logger
type serviceCheck struct {
	consul *consul.Check
	metric *cloudwatch.Metric
	logger *log.Logger
}

// defaultServiceCheck returns a defaul service check config
func defaultServiceCheck() *serviceCheckConfig {
	return &serviceCheckConfig{
		name:            "service",
		tag:             "tag",
		metricName:      "service_monitoring",
		metricNamespace: "microservices",
		blockTime:       10 * time.Minute,
		logger:          log.NewLogger(),
	}
}

// newServiceCheck returns a new service check
func newServiceCheck(svcConfig *serviceCheckConfig) (*serviceCheck, error) {
	consul, err := consul.NewCheck(&consul.CheckConfig{
		Service:     svcConfig.name,
		Tag:         svcConfig.tag,
		PassingOnly: true,
		BlockTime:   svcConfig.blockTime,
	})
	if err != nil {
		return nil, err
	}

	svcCheck := &serviceCheck{
		consul: consul,
		metric: cloudwatch.NewMetric(&cloudwatch.MetricConfig{
			Name:      svcConfig.metricName,
			Namespace: svcConfig.metricNamespace,
			Service: &cloudwatch.Service{
				Name: svcConfig.name,
				Env:  svcConfig.tag,
			},
			Value: 0,
		}),
		logger: svcConfig.logger,
	}
	return svcCheck, nil
}

// loopCheck does an infinite loop calling serviceCheck
func (sc *serviceCheck) loopCheck() {
	for {
		err := sc.check()
		if err != nil {
			time.Sleep(10 * time.Second)
		}
	}
}

// check checks if a service is healthy and posts that data to a Cloudwatch
// metric based on the service name and environment
func (sc *serviceCheck) check() error {
	count, qm, err := sc.consul.Healthy()
	if err != nil {
		sc.logger.Error("Could not retrieve service count from Consul: %v", err)
		return err
	}
	// debug logging for Consul request
	sc.logger.Debug("Consul Query metadata, Request Time: %s, Last Index: %d", qm.RequestTime, qm.LastIndex)
	// Set the last response index as the wait index for the next request to
	// successfully do a blocking query
	sc.consul.QueryOptions.WaitIndex = qm.LastIndex
	sc.logger.Info("Service count: %d, with name: %s and tag: %s", count, sc.consul.Config.Service, sc.consul.Config.Tag)

	_, err = sc.metric.Put(float64(count))
	if err != nil {
		sc.logger.Error("Could not post metric to CloudWatch: %v", err)
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package gocube

import (
	"testing"
)

func BenchmarkMakeEOPruner(b *testing.B) {
	moves, _ := ParseMoves("U D F B R L U2 D2 F2 B2 R2 L2 U' D' F' B' R' L'")
	for i := 0; i < b.N; i++ {
		MakeEOPruner(moves)
	}
}
<commit_msg>benchmark edge search<commit_after>package gocube

import (
	"testing"
)

func BenchmarkMakeEOPruner(b *testing.B) {
	moves, _ := ParseMoves("U D F B R L U2 D2 F2 B2 R2 L2 U' D' F' B' R' L'")
	for i := 0; i < b.N; i++ {
		MakeEOPruner(moves)
	}
}

func BenchmarkEdgeSearch(b *testing.B) {
	moves, _ := ParseMoves("U D F B R L U2 D2 F2 B2 R2 L2 U' D' F' B' R' L'")
	scramble, _ := ParseMoves("U D F B R")
	start := SolvedCubieEdges()
	for _, move := range scramble {
		start.Move(move)
	}
	for i := 0; i < b.N; i++ {
		s := start.Search(SolveEdgesGoal{}, nil, moves, 5, 0)
		for {
			if _, ok := <-s.Solutions(); !ok {
				break
			}
		}
	}
}

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/go-humble/rest"
	"github.com/rusco/qunit"
	"reflect"
	"strconv"
)

type Todo struct {
	Id          int
	Title       string
	IsCompleted bool
}

func (t Todo) ModelId() string {
	return strconv.Itoa(t.Id)
}

func (t Todo) RootURL() string {
	return "http://localhost:3000/todos"
}

func main() {
	// contentTypes is an array of all ContentTypes that we want to test for.
	// Note thate the test server must be capable of handling each type.
	contentTypes := []rest.ContentType{rest.ContentURLEncoded, rest.ContentJSON}

	qunit.Test("ReadAll", func(assert qunit.QUnitAssert) {
		// We want to run this test for each contentType in contentTypes.
		// We declare that we expect 2 assertions per type, then iterate through
		// each content type, set the type with rest.SetContentType, and run the
		// test. The rest of the tests use the same approach.
		qunit.Expect(2 * len(contentTypes))
		for _, contentType := range contentTypes {
			rest.SetContentType(contentType)
			done := assert.Call("async")
			go func() {
				expectedTodos := []*Todo{
					{
						Id:          0,
						Title:       "Todo 0",
						IsCompleted: false,
					},
					{
						Id:          1,
						Title:       "Todo 1",
						IsCompleted: false,
					},
					{
						Id:          2,
						Title:       "Todo 2",
						IsCompleted: true,
					},
				}
				gotTodos := []*Todo{}
				err := rest.ReadAll(&gotTodos)
				assert.Ok(err == nil, fmt.Sprintf("rest.ReadAll returned an error: %v", err))
				assert.Ok(reflect.DeepEqual(gotTodos, expectedTodos), fmt.Sprintf("Expected: %v, Got: %v", expectedTodos, gotTodos))
				done.Invoke()

			}()
		}
	})

	qunit.Test("Read", func(assert qunit.QUnitAssert) {
		qunit.Expect(2 * len(contentTypes))
		for _, contentType := range contentTypes {
			rest.SetContentType(contentType)
			done := assert.Call("async")
			go func() {
				expectedTodo := &Todo{
					Id:          2,
					Title:       "Todo 2",
					IsCompleted: true,
				}
				gotTodo := &Todo{}
				err := rest.Read("2", gotTodo)
				assert.Ok(err == nil, fmt.Sprintf("rest.Read returned an error: %v", err))
				assert.Ok(reflect.DeepEqual(gotTodo, expectedTodo), fmt.Sprintf("Expected: %v, Got: %v", expectedTodo, gotTodo))
				done.Invoke()
			}()
		}
	})

	qunit.Test("Create", func(assert qunit.QUnitAssert) {
		qunit.Expect(4 * len(contentTypes))
		for _, contentType := range contentTypes {
			rest.SetContentType(contentType)
			done := assert.Call("async")
			go func() {
				newTodo := &Todo{
					Title:       "Test",
					IsCompleted: true,
				}
				err := rest.Create(newTodo)
				assert.Ok(err == nil, fmt.Sprintf("rest.Create returned an error: %v", err))
				assert.Equal(newTodo.Id, 3, "newTodo.Id was not set correctly.")
				assert.Equal(newTodo.Title, "Test", "newTodo.Title was incorrect.")
				assert.Equal(newTodo.IsCompleted, true, "newTodo.IsCompleted was incorrect.")
				done.Invoke()
			}()
		}
	})

	qunit.Test("Update", func(assert qunit.QUnitAssert) {
		qunit.Expect(4 * len(contentTypes))
		for _, contentType := range contentTypes {
			rest.SetContentType(contentType)
			done := assert.Call("async")
			go func() {
				updatedTodo := &Todo{
					Id:          1,
					Title:       "Updated Title",
					IsCompleted: true,
				}
				err := rest.Update(updatedTodo)
				assert.Ok(err == nil, fmt.Sprintf("rest.Update returned an error: %v", err))
				assert.Equal(updatedTodo.Id, 1, "updatedTodo.Id was incorrect.")
				assert.Equal(updatedTodo.Title, "Updated Title", "updatedTodo.Title was incorrect.")
				assert.Equal(updatedTodo.IsCompleted, true, "updatedTodo.IsCompleted was incorrect.")
				done.Invoke()
			}()
		}
	})

	qunit.Test("Delete", func(assert qunit.QUnitAssert) {
		qunit.Expect(1 * len(contentTypes))
		for _, contentType := range contentTypes {
			rest.SetContentType(contentType)
			done := assert.Call("async")
			go func() {
				deletedTodo := &Todo{
					Id: 1,
				}
				err := rest.Delete(deletedTodo)
				assert.Ok(err == nil, fmt.Sprintf("rest.Update returned an error: %v", err))
				done.Invoke()
			}()
		}
	})
}
<commit_msg>Fix rest_test.go using a wait group to make sure all content types are covered.<commit_after>package main

import (
	"fmt"
	"github.com/go-humble/rest"
	"github.com/rusco/qunit"
	"reflect"
	"strconv"
	"sync"
)

type Todo struct {
	Id          int
	Title       string
	IsCompleted bool
}

func (t Todo) ModelId() string {
	return strconv.Itoa(t.Id)
}

func (t Todo) RootURL() string {
	return "http://localhost:3000/todos"
}

func main() {
	// contentTypes is an array of all ContentTypes that we want to test for.
	// Note thate the test server must be capable of handling each type.
	contentTypes := []rest.ContentType{rest.ContentURLEncoded, rest.ContentJSON}
	// For each content type, we want to run all the tests and wait for the
	// tests to finish before continuing to the next type.
	for _, contentType := range contentTypes {
		rest.SetContentType(contentType)
		wg := sync.WaitGroup{}
		// Currently there are 5 tests. Need to update this if we add more
		// tests.
		wg.Add(5)

		qunit.Test("ReadAll "+string(contentType), func(assert qunit.QUnitAssert) {
			qunit.Expect(2)
			done := assert.Call("async")
			go func() {
				expectedTodos := []*Todo{
					{
						Id:          0,
						Title:       "Todo 0",
						IsCompleted: false,
					},
					{
						Id:          1,
						Title:       "Todo 1",
						IsCompleted: false,
					},
					{
						Id:          2,
						Title:       "Todo 2",
						IsCompleted: true,
					},
				}
				gotTodos := []*Todo{}
				err := rest.ReadAll(&gotTodos)
				assert.Ok(err == nil, fmt.Sprintf("rest.ReadAll returned an error: %v", err))
				assert.Ok(reflect.DeepEqual(gotTodos, expectedTodos), fmt.Sprintf("Expected: %v, Got: %v", expectedTodos, gotTodos))
				done.Invoke()
				wg.Done()
			}()
		})

		qunit.Test("Read "+string(contentType), func(assert qunit.QUnitAssert) {
			qunit.Expect(2)
			done := assert.Call("async")
			go func() {
				expectedTodo := &Todo{
					Id:          2,
					Title:       "Todo 2",
					IsCompleted: true,
				}
				gotTodo := &Todo{}
				err := rest.Read("2", gotTodo)
				assert.Ok(err == nil, fmt.Sprintf("rest.Read returned an error: %v", err))
				assert.Ok(reflect.DeepEqual(gotTodo, expectedTodo), fmt.Sprintf("Expected: %v, Got: %v", expectedTodo, gotTodo))
				done.Invoke()
				wg.Done()
			}()
		})

		qunit.Test("Create "+string(contentType), func(assert qunit.QUnitAssert) {
			qunit.Expect(4)
			done := assert.Call("async")
			go func() {
				newTodo := &Todo{
					Title:       "Test",
					IsCompleted: true,
				}
				err := rest.Create(newTodo)
				assert.Ok(err == nil, fmt.Sprintf("rest.Create returned an error: %v", err))
				assert.Equal(newTodo.Id, 3, "newTodo.Id was not set correctly.")
				assert.Equal(newTodo.Title, "Test", "newTodo.Title was incorrect.")
				assert.Equal(newTodo.IsCompleted, true, "newTodo.IsCompleted was incorrect.")
				done.Invoke()
				wg.Done()
			}()
		})

		qunit.Test("Update "+string(contentType), func(assert qunit.QUnitAssert) {
			qunit.Expect(4)
			done := assert.Call("async")
			go func() {
				updatedTodo := &Todo{
					Id:          1,
					Title:       "Updated Title",
					IsCompleted: true,
				}
				err := rest.Update(updatedTodo)
				assert.Ok(err == nil, fmt.Sprintf("rest.Update returned an error: %v", err))
				assert.Equal(updatedTodo.Id, 1, "updatedTodo.Id was incorrect.")
				assert.Equal(updatedTodo.Title, "Updated Title", "updatedTodo.Title was incorrect.")
				assert.Equal(updatedTodo.IsCompleted, true, "updatedTodo.IsCompleted was incorrect.")
				done.Invoke()
				wg.Done()
			}()
		})

		qunit.Test("Delete "+string(contentType), func(assert qunit.QUnitAssert) {
			qunit.Expect(1)
			done := assert.Call("async")
			go func() {
				deletedTodo := &Todo{
					Id: 1,
				}
				err := rest.Delete(deletedTodo)
				assert.Ok(err == nil, fmt.Sprintf("rest.Update returned an error: %v", err))
				done.Invoke()
				wg.Done()
			}()
		})

		// Wait for all the tests to finish before continuing to the next content type.
		wg.Wait()
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libkbfs

import (
	"encoding/base64"
	"fmt"
	"strings"

	"github.com/keybase/client/go/logger"
	"github.com/keybase/kbfs/kbfscrypto"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

// Runs fn (which may block) in a separate goroutine and waits for it
// to finish, unless ctx is cancelled. Returns nil only when fn was
// run to completion and succeeded.  Any closed-over variables updated
// in fn should be considered visible only if nil is returned.
func runUnlessCanceled(ctx context.Context, fn func() error) error {
	c := make(chan error, 1) // buffered, in case the request is canceled
	go func() {
		c <- fn()
	}()

	select {
	case <-ctx.Done():
		return ctx.Err()
	case err := <-c:
		return err
	}
}

// MakeRandomRequestID generates a random ID suitable for tagging a
// request in KBFS, and very likely to be universally unique.
func MakeRandomRequestID() (string, error) {
	// Use a random ID to tag each request.  We want this to be really
	// universally unique, as these request IDs might need to be
	// propagated all the way to the server.  Use a base64-encoded
	// random 128-bit number.
	buf := make([]byte, 128/8)
	err := kbfscrypto.RandRead(buf)
	if err != nil {
		return "", err
	}
	// TODO: go1.5 has RawURLEncoding which leaves off the padding entirely
	return strings.TrimSuffix(base64.URLEncoding.EncodeToString(buf), "=="), nil
}

// LogTagsFromContextToMap parses log tags from the context into a map of strings.
func LogTagsFromContextToMap(ctx context.Context) (tags map[string]string) {
	if ctx == nil {
		return tags
	}
	logTags, ok := logger.LogTagsFromContext(ctx)
	if !ok || len(logTags) == 0 {
		return tags
	}
	tags = make(map[string]string)
	for key, tag := range logTags {
		if v := ctx.Value(key); v != nil {
			if value, ok := v.(fmt.Stringer); ok {
				tags[tag] = value.String()
			} else if value, ok := v.(string); ok {
				tags[tag] = value
			}
		}
	}
	return tags
}

// BoolForString returns false if trimmed string is "" (empty), "0", "false", or "no"
func BoolForString(s string) bool {
	s = strings.TrimSpace(s)
	if s == "" || s == "0" || s == "false" || s == "no" {
		return false
	}
	return true
}

// PrereleaseBuild is set at compile time for prerelease builds
var PrereleaseBuild string

// VersionString returns semantic version string
func VersionString() string {
	if PrereleaseBuild != "" {
		return fmt.Sprintf("%s-%s", Version, PrereleaseBuild)
	}
	return Version
}

// CtxBackgroundSyncKeyType is the type for a context background sync key.
type CtxBackgroundSyncKeyType int

const (
	// CtxBackgroundSyncKey is set in the context for any change
	// notifications that are triggered from a background sync.
	// Observers can ignore these if they want, since they will have
	// already gotten the relevant notifications via LocalChanges.
	CtxBackgroundSyncKey CtxBackgroundSyncKeyType = iota
)

func ctxWithRandomIDReplayable(ctx context.Context, tagKey interface{},
	tagName string, log logger.Logger) context.Context {
	id, err := MakeRandomRequestID()
	if err != nil && log != nil {
		log.Warning("Couldn't generate a random request ID: %v", err)
	}
	return NewContextReplayable(ctx, func(ctx context.Context) context.Context {
		logTags := make(logger.CtxLogTags)
		logTags[tagKey] = tagName
		newCtx := logger.NewContextWithLogTags(ctx, logTags)
		if err == nil {
			newCtx = context.WithValue(newCtx, tagKey, id)
		}
		return newCtx
	})
}

// LogTagsFromContext is a wrapper around logger.LogTagsFromContext
// that simply casts the result to the type expected by
// rpc.Connection.
func LogTagsFromContext(ctx context.Context) (map[interface{}]string, bool) {
	tags, ok := logger.LogTagsFromContext(ctx)
	return map[interface{}]string(tags), ok
}

// checkDataVersion validates that the data version for a
// block pointer is valid for the given version validator
func checkDataVersion(versioner dataVersioner, p path, ptr BlockPointer) error {
	if ptr.DataVer < FirstValidDataVer {
		return InvalidDataVersionError{ptr.DataVer}
	}
	if versioner != nil && ptr.DataVer > versioner.DataVersion() {
		return NewDataVersionError{p, ptr.DataVer}
	}
	return nil
}

func checkContext(ctx context.Context) error {
	select {
	case <-ctx.Done():
		return errors.WithStack(ctx.Err())
	default:
		return nil
	}
}
<commit_msg>libkbfs: Use base64.RawURLEncoding<commit_after>// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libkbfs

import (
	"encoding/base64"
	"fmt"
	"strings"

	"github.com/keybase/client/go/logger"
	"github.com/keybase/kbfs/kbfscrypto"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

// Runs fn (which may block) in a separate goroutine and waits for it
// to finish, unless ctx is cancelled. Returns nil only when fn was
// run to completion and succeeded.  Any closed-over variables updated
// in fn should be considered visible only if nil is returned.
func runUnlessCanceled(ctx context.Context, fn func() error) error {
	c := make(chan error, 1) // buffered, in case the request is canceled
	go func() {
		c <- fn()
	}()

	select {
	case <-ctx.Done():
		return ctx.Err()
	case err := <-c:
		return err
	}
}

// MakeRandomRequestID generates a random ID suitable for tagging a
// request in KBFS, and very likely to be universally unique.
func MakeRandomRequestID() (string, error) {
	// Use a random ID to tag each request.  We want this to be really
	// universally unique, as these request IDs might need to be
	// propagated all the way to the server.  Use a base64-encoded
	// random 128-bit number.
	buf := make([]byte, 128/8)
	err := kbfscrypto.RandRead(buf)
	if err != nil {
		return "", err
	}
	return base64.RawURLEncoding.EncodeToString(buf), nil
}

// LogTagsFromContextToMap parses log tags from the context into a map of strings.
func LogTagsFromContextToMap(ctx context.Context) (tags map[string]string) {
	if ctx == nil {
		return tags
	}
	logTags, ok := logger.LogTagsFromContext(ctx)
	if !ok || len(logTags) == 0 {
		return tags
	}
	tags = make(map[string]string)
	for key, tag := range logTags {
		if v := ctx.Value(key); v != nil {
			if value, ok := v.(fmt.Stringer); ok {
				tags[tag] = value.String()
			} else if value, ok := v.(string); ok {
				tags[tag] = value
			}
		}
	}
	return tags
}

// BoolForString returns false if trimmed string is "" (empty), "0", "false", or "no"
func BoolForString(s string) bool {
	s = strings.TrimSpace(s)
	if s == "" || s == "0" || s == "false" || s == "no" {
		return false
	}
	return true
}

// PrereleaseBuild is set at compile time for prerelease builds
var PrereleaseBuild string

// VersionString returns semantic version string
func VersionString() string {
	if PrereleaseBuild != "" {
		return fmt.Sprintf("%s-%s", Version, PrereleaseBuild)
	}
	return Version
}

// CtxBackgroundSyncKeyType is the type for a context background sync key.
type CtxBackgroundSyncKeyType int

const (
	// CtxBackgroundSyncKey is set in the context for any change
	// notifications that are triggered from a background sync.
	// Observers can ignore these if they want, since they will have
	// already gotten the relevant notifications via LocalChanges.
	CtxBackgroundSyncKey CtxBackgroundSyncKeyType = iota
)

func ctxWithRandomIDReplayable(ctx context.Context, tagKey interface{},
	tagName string, log logger.Logger) context.Context {
	id, err := MakeRandomRequestID()
	if err != nil && log != nil {
		log.Warning("Couldn't generate a random request ID: %v", err)
	}
	return NewContextReplayable(ctx, func(ctx context.Context) context.Context {
		logTags := make(logger.CtxLogTags)
		logTags[tagKey] = tagName
		newCtx := logger.NewContextWithLogTags(ctx, logTags)
		if err == nil {
			newCtx = context.WithValue(newCtx, tagKey, id)
		}
		return newCtx
	})
}

// LogTagsFromContext is a wrapper around logger.LogTagsFromContext
// that simply casts the result to the type expected by
// rpc.Connection.
func LogTagsFromContext(ctx context.Context) (map[interface{}]string, bool) {
	tags, ok := logger.LogTagsFromContext(ctx)
	return map[interface{}]string(tags), ok
}

// checkDataVersion validates that the data version for a
// block pointer is valid for the given version validator
func checkDataVersion(versioner dataVersioner, p path, ptr BlockPointer) error {
	if ptr.DataVer < FirstValidDataVer {
		return InvalidDataVersionError{ptr.DataVer}
	}
	if versioner != nil && ptr.DataVer > versioner.DataVersion() {
		return NewDataVersionError{p, ptr.DataVer}
	}
	return nil
}

func checkContext(ctx context.Context) error {
	select {
	case <-ctx.Done():
		return errors.WithStack(ctx.Err())
	default:
		return nil
	}
}
<|endoftext|>