<commit_before>package main

import (
	"fmt"
	"github.com/gorilla/mux"
	"github.com/minotar/minecraft"
	"net/http"
	"strconv"
	"strings"
)

type Router struct {
	Mux *mux.Router
}

type NotFoundHandler struct{}

// Handles 404 errors
func (h NotFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(404)
	fmt.Fprintf(w, "404 not found")
}

// Converts and sanitizes the string for the avatar size.
func (r *Router) GetSize(inp string) uint {
	out64, err := strconv.ParseUint(inp, 10, 0)
	out := uint(out64)
	if err != nil {
		return DefaultSize
	} else if out > MaxSize {
		return MaxSize
	} else if out < MinSize {
		return MinSize
	}
	return out

}

// Shows only the user's skin.
func (router *Router) SkinPage(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)

	username := vars["username"]

	skin := fetchSkin(username)

	w.Header().Add("Content-Type", "image/png")
	w.Header().Add("X-Requested", "skin")
	w.Header().Add("X-Result", "ok")

	skin.WriteSkin(w)
}

// Shows the skin and tells the browser to attempt to download it.
func (router *Router) DownloadPage(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Content-Disposition", "attachment; filename=\"skin.png\"")
	router.SkinPage(w, r)
}

// Pull the Get<resource> method from the skin. Originally this used
// reflection, but that was slow.
func (router *Router) ResolveMethod(skin *mcSkin, resource string) func(int) error {
	stats.Served(resource)

	switch resource {
	case "Avatar":
		return skin.GetHead
	case "Helm":
		return skin.GetHelm
	case "Cube":
		return skin.GetCube
	case "Bust":
		return skin.GetBust
	case "Body":
		return skin.GetBody
	case "ArmorBust":
		return skin.GetArmorBust
	default:
		return skin.GetHelm
	}
}

// Binds the route and makes a handler function for the requested resource.
func (router *Router) Serve(resource string) {
	fn := func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		size := router.GetSize(vars["size"])
		skin := fetchSkin(vars["username"])

		err := router.ResolveMethod(skin, resource)(int(size))
		if err != nil {
			w.WriteHeader(500)
			fmt.Fprintf(w, "500 internal server error")
			return
		}

		w.Header().Add("Content-Type", "image/png")
		w.Header().Add("X-Skin-Hash", skin.Hash)
		w.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d", TimeoutActualSkin))
		skin.WritePNG(w)
	}

	router.Mux.HandleFunc("/"+strings.ToLower(resource)+"/{username:"+minecraft.ValidUsernameRegex+"}{extension:(.png)?}", fn)
	router.Mux.HandleFunc("/"+strings.ToLower(resource)+"/{username:"+minecraft.ValidUsernameRegex+"}/{size:[0-9]+}{extension:(.png)?}", fn)
}

// Binds routes to the ServerMux.
func (router *Router) Bind() {

	router.Mux.NotFoundHandler = NotFoundHandler{}

	router.Serve("Avatar")
	router.Serve("Helm")
	router.Serve("Cube")
	router.Serve("Bust")
	router.Serve("Body")
	router.Serve("ArmorBust")

	router.Mux.HandleFunc("/download/{username:"+minecraft.ValidUsernameRegex+"}{extension:(.png)?}", router.DownloadPage)
	router.Mux.HandleFunc("/skin/{username:"+minecraft.ValidUsernameRegex+"}{extension:(.png)?}", router.SkinPage)

	router.Mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "%s", MinotarVersion)
	})

	router.Mux.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.Write(stats.ToJSON())
	})

	router.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "https://minotar.net/", 302)
	})
}

func fetchSkin(username string) *mcSkin {
	if cache.has(strings.ToLower(username)) {
		stats.HitCache()
		return &mcSkin{Processed: nil, Skin: cache.pull(strings.ToLower(username))}
	}

	skin, err := minecraft.FetchSkinFromMojang(username)
	if err != nil {
		log.Error("Failed Skin Mojang: " + username + " (" + err.Error() + ")")
		// Let's fallback to S3 and try and serve at least an old skin...
		skin, err = minecraft.FetchSkinFromS3(username)
		if err != nil {
			log.Error("Failed Skin S3: " + username + " (" + err.Error() + ")")
			// Well, looks like they don't exist after all.
			skin, _ = minecraft.FetchSkinForChar()
		}
	}

	stats.MissCache()
	cache.add(strings.ToLower(username), skin)

	return &mcSkin{Processed: nil, Skin: skin}
}
<commit_msg>Fix merge issue<commit_after>package main

import (
	"fmt"
	"github.com/gorilla/mux"
	"github.com/minotar/minecraft"
	"net/http"
	"strconv"
	"strings"
)

type Router struct {
	Mux *mux.Router
}

type NotFoundHandler struct{}

// Handles 404 errors
func (h NotFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(404)
	fmt.Fprintf(w, "404 not found")
}

// Converts and sanitizes the string for the avatar size.
func (r *Router) GetSize(inp string) uint {
	out64, err := strconv.ParseUint(inp, 10, 0)
	out := uint(out64)
	if err != nil {
		return DefaultSize
	} else if out > MaxSize {
		return MaxSize
	} else if out < MinSize {
		return MinSize
	}
	return out

}

// Shows only the user's skin.
func (router *Router) SkinPage(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)

	username := vars["username"]

	skin := fetchSkin(username)

	w.Header().Add("Content-Type", "image/png")
	w.Header().Add("X-Requested", "skin")
	w.Header().Add("X-Result", "ok")

	skin.WriteSkin(w)
}

// Shows the skin and tells the browser to attempt to download it.
func (router *Router) DownloadPage(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Content-Disposition", "attachment; filename=\"skin.png\"")
	router.SkinPage(w, r)
}

// Pull the Get<resource> method from the skin. Originally this used
// reflection, but that was slow.
func (router *Router) ResolveMethod(skin *mcSkin, resource string) func(int) error {
	stats.Served(resource)

	switch resource {
	case "Avatar":
		return skin.GetHead
	case "Helm":
		return skin.GetHelm
	case "Cube":
		return skin.GetCube
	case "Bust":
		return skin.GetBust
	case "Body":
		return skin.GetBody
	case "Armor/Bust":
		return skin.GetArmorBust
	default:
		return skin.GetHelm
	}
}

// Binds the route and makes a handler function for the requested resource.
func (router *Router) Serve(resource string) {
	fn := func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		size := router.GetSize(vars["size"])
		skin := fetchSkin(vars["username"])

		err := router.ResolveMethod(skin, resource)(int(size))
		if err != nil {
			w.WriteHeader(500)
			fmt.Fprintf(w, "500 internal server error")
			return
		}

		w.Header().Add("Content-Type", "image/png")
		w.Header().Add("X-Skin-Hash", skin.Hash)
		w.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d", TimeoutActualSkin))
		skin.WritePNG(w)
	}

	router.Mux.HandleFunc("/"+strings.ToLower(resource)+"/{username:"+minecraft.ValidUsernameRegex+"}{extension:(.png)?}", fn)
	router.Mux.HandleFunc("/"+strings.ToLower(resource)+"/{username:"+minecraft.ValidUsernameRegex+"}/{size:[0-9]+}{extension:(.png)?}", fn)
}

// Binds routes to the ServerMux.
func (router *Router) Bind() {

	router.Mux.NotFoundHandler = NotFoundHandler{}

	router.Serve("Avatar")
	router.Serve("Helm")
	router.Serve("Cube")
	router.Serve("Bust")
	router.Serve("Body")
	router.Serve("Armor/Bust")

	router.Mux.HandleFunc("/download/{username:"+minecraft.ValidUsernameRegex+"}{extension:(.png)?}", router.DownloadPage)
	router.Mux.HandleFunc("/skin/{username:"+minecraft.ValidUsernameRegex+"}{extension:(.png)?}", router.SkinPage)

	router.Mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "%s", MinotarVersion)
	})

	router.Mux.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.Write(stats.ToJSON())
	})

	router.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "https://minotar.net/", 302)
	})
}

func fetchSkin(username string) *mcSkin {
	if cache.has(strings.ToLower(username)) {
		stats.HitCache()
		return &mcSkin{Processed: nil, Skin: cache.pull(strings.ToLower(username))}
	}

	skin, err := minecraft.FetchSkinFromMojang(username)
	if err != nil {
		log.Error("Failed Skin Mojang: " + username + " (" + err.Error() + ")")
		// Let's fallback to S3 and try and serve at least an old skin...
		skin, err = minecraft.FetchSkinFromS3(username)
		if err != nil {
			log.Error("Failed Skin S3: " + username + " (" + err.Error() + ")")
			// Well, looks like they don't exist after all.
			skin, _ = minecraft.FetchSkinForChar()
		}
	}

	stats.MissCache()
	cache.add(strings.ToLower(username), skin)

	return &mcSkin{Processed: nil, Skin: skin}
}
<|endoftext|>


<commit_before>package sumoll

import (
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"time"
)

type httpClient interface {
	Do(req *http.Request) (*http.Response, error)
}

type (
	// HTTPSourceClient send to Resource HTTP
	HTTPSourceClient struct {
		url       *url.URL
		client    httpClient
		UserAgent string
		headers   *http.Header
	}

	// HTTPSourceClientOptFunc set some values to client
	HTTPSourceClientOptFunc func(*HTTPSourceClient) error
)

// SetXSumoCategoryHeader set X-Sumo-Category's value to header
func SetXSumoCategoryHeader(category string) HTTPSourceClientOptFunc {
	return func(h *HTTPSourceClient) error {
		if category != "" {
			h.headers.Add("X-Sumo-Category", category)
		}
		return nil
	}
}

// SetXSumoNameHeader set X-Sumo-Name's value to header
func SetXSumoNameHeader(name string) HTTPSourceClientOptFunc {
	return func(h *HTTPSourceClient) error {
		if name == "" {
			h.headers.Add("X-Sumo-Name", name)
		}
		return nil
	}
}

// SetXSumoHostHeader set X-Sumo-Host's value to header
func SetXSumoHostHeader(host string) HTTPSourceClientOptFunc {
	return func(h *HTTPSourceClient) error {
		if host == "" {
			h.headers.Add("X-Sumo-Host", host)
		}
		return nil
	}
}

// NewHTTPSourceClient create HTTPSourceClient object
func NewHTTPSourceClient(url *url.URL, opts ...HTTPSourceClientOptFunc) (*HTTPSourceClient, error) {
	c := &HTTPSourceClient{
		url:       url,
		client:    &http.Client{},
		UserAgent: UserAgent(),
		headers:   &http.Header{},
	}

	for _, opts := range opts {
		if err := opts(c); err != nil {
			return nil, err
		}
	}

	return c, nil
}

// Send object to sumologic
func (h *HTTPSourceClient) Send(body io.Reader) error {
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	req, err := h.newRequest(ctx, http.MethodPost, body)
	if err != nil {
		return err
	}

	if h.headers != nil {
		mergeHeaders(&req.Header, h.headers)
	}

	res, err := h.client.Do(req)
	if err != nil {
		return err
	}

	if !validResponseStatus(res.StatusCode) {
		return errors.New(fmt.Sprintf("Unexpected response code from Sumologic: %v", res.StatusCode))
	}

	return nil
}

func validResponseStatus(status int) bool {
	return status >= http.StatusOK && status < http.StatusMultipleChoices
}

func mergeHeaders(merged, input *http.Header) {
	if input == nil {
		return
	}
	for k, v := range *input {
		if len(v) > 0 {
			merged.Add(k, v[0])
		}
	}
}

func (h *HTTPSourceClient) newRequest(ctx context.Context, method string, body io.Reader) (*http.Request, error) {
	u := *h.url

	req, err := http.NewRequest(method, u.String(), body)
	if err != nil {
		return nil, err
	}

	req = req.WithContext(ctx)
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("User-Agent", h.UserAgent)

	return req, nil
}
<commit_msg>fixed implementation makes tests green<commit_after>package sumoll

import (
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"time"
)

type httpClient interface {
	Do(req *http.Request) (*http.Response, error)
}

type (
	// HTTPSourceClient send to Resource HTTP
	HTTPSourceClient struct {
		url       *url.URL
		client    httpClient
		UserAgent string
		headers   *http.Header
	}

	// HTTPSourceClientOptFunc set some values to client
	HTTPSourceClientOptFunc func(*HTTPSourceClient) error
)

// SetXSumoCategoryHeader set X-Sumo-Category's value to header
func SetXSumoCategoryHeader(category string) HTTPSourceClientOptFunc {
	return func(h *HTTPSourceClient) error {
		if category != "" {
			h.headers.Add("X-Sumo-Category", category)
		}
		return nil
	}
}

// SetXSumoNameHeader set X-Sumo-Name's value to header
func SetXSumoNameHeader(name string) HTTPSourceClientOptFunc {
	return func(h *HTTPSourceClient) error {
		if name != "" {
			h.headers.Add("X-Sumo-Name", name)
		}
		return nil
	}
}

// SetXSumoHostHeader set X-Sumo-Host's value to header
func SetXSumoHostHeader(host string) HTTPSourceClientOptFunc {
	return func(h *HTTPSourceClient) error {
		if host != "" {
			h.headers.Add("X-Sumo-Host", host)
		}
		return nil
	}
}

// NewHTTPSourceClient create HTTPSourceClient object
func NewHTTPSourceClient(url *url.URL, opts ...HTTPSourceClientOptFunc) (*HTTPSourceClient, error) {
	c := &HTTPSourceClient{
		url:       url,
		client:    &http.Client{},
		UserAgent: UserAgent(),
		headers:   &http.Header{},
	}

	for _, opts := range opts {
		if err := opts(c); err != nil {
			return nil, err
		}
	}

	return c, nil
}

// Send object to sumologic
func (h *HTTPSourceClient) Send(body io.Reader) error {
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	req, err := h.newRequest(ctx, http.MethodPost, body)
	if err != nil {
		return err
	}

	if h.headers != nil {
		mergeHeaders(&req.Header, h.headers)
	}

	res, err := h.client.Do(req)
	if err != nil {
		return err
	}

	if !validResponseStatus(res.StatusCode) {
		return errors.New(fmt.Sprintf("Unexpected response code from Sumologic: %v", res.StatusCode))
	}

	return nil
}

func validResponseStatus(status int) bool {
	return status >= http.StatusOK && status < http.StatusMultipleChoices
}

func mergeHeaders(merged, input *http.Header) {
	if input == nil {
		return
	}
	for k, v := range *input {
		if len(v) > 0 {
			merged.Add(k, v[0])
		}
	}
}

func (h *HTTPSourceClient) newRequest(ctx context.Context, method string, body io.Reader) (*http.Request, error) {
	u := *h.url

	req, err := http.NewRequest(method, u.String(), body)
	if err != nil {
		return nil, err
	}

	req = req.WithContext(ctx)
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("User-Agent", h.UserAgent)

	return req, nil
}
<|endoftext|>


<commit_before>package go_cron

import (
	_ "github.com/WindomZ/go-cron/cron"
)
<commit_msg>fix: init<commit_after>package gocron

import (
	_ "github.com/WindomZ/go-cron/cron"
)
<|endoftext|>


<commit_before>package okcoin

import (
	// "github.com/davecgh/go-spew/spew"
	"bitfx2/exchange"
	"os"
	"testing"
	"time"
)

var book exchange.Book
var ok = New(os.Getenv("OKCOIN_KEY"), os.Getenv("OKCOIN_SECRET"), "ltc", "usd", 1, 0.002)

func TestPriority(t *testing.T) {
	if ok.Priority() != 1 {
		t.Fatal("Priority should be 1")
	}
}

func TestFee(t *testing.T) {
	if ok.Fee()-0.002 > 0.000001 {
		t.Fatal("Fee should be 0.002")
	}
}

func TestUpdatePositon(t *testing.T) {
	if ok.Position() != 0 {
		t.Fatal("Should start with zero position")
	}
	ok.SetPosition(10)
	t.Logf("Set position to 10")
	if ok.Position() != 10 {
		t.Fatal("Position should have updated to 10")
	}
}

func TestCommunicateBook(t *testing.T) {
	bookChan := make(chan exchange.Book)
	doneChan := make(chan bool)
	err := ok.CommunicateBook(bookChan, doneChan)
	if err != nil {
		t.Fatal(err)
	}

	// Notify doneChan in 5 seconds
	go func() {
		time.Sleep(5 * time.Second)
		doneChan <- true
		t.Logf("Notified doneChan")
	}()

	for book = range bookChan {
		t.Logf("Received book data")
		// spew.Dump(book)
		if len(book.Bids) != 20 || len(book.Asks) != 20 {
			t.Fatal("Expected 20 book entries")
		}
		if book.Bids[0].Price < book.Bids[1].Price {
			t.Fatal("Bids not sorted correctly")
		}
		if book.Asks[0].Price > book.Asks[1].Price {
			t.Fatal("Asks not sorted correctly")
		}
	}
}

func TestNewOrder(t *testing.T) {
	action := "buy"
	otype := "limit"
	amount := 0.1
	price := book.Bids[0].Price - 0.20

	// Test submitting a new order
	id, err := ok.SendOrder(action, otype, amount, price)
	if err != nil || id == 0 {
		t.Fatal(err)
	}
	t.Logf("Placed a new buy order of 0.1 ltc_usd @ %v limit with ID: %d", price, id)

	// Check status
	order, err := ok.GetOrderStatus(id)
	if err != nil {
		t.Fatal(err)
	}
	if order.Status != "live" {
		t.Fatal("Order should be live")
	}
	t.Logf("Order confirmed live")
	if order.FilledAmount != 0 {
		t.Fatal("Order should not be filled")
	}
	t.Logf("Order confirmed unfilled")

	// Test cancelling the order
	success, err := ok.CancelOrder(id)
	if err != nil {
		t.Fatal(err)
	}
	if !success {
		t.Fatal("Order not cancelled")
	}
	t.Logf("Sent cancellation")

	// Check status
	tryAgain := true
	for tryAgain {
		t.Logf("checking status...")
		order, err = ok.GetOrderStatus(id)
		tryAgain = order.Status == ""
	}
	if err != nil {
		t.Fatal(err)
	}
	if order.Status != "dead" {
		t.Fatal("Order should be dead after cancel")
	}
	t.Logf("Order confirmed dead")
	if order.FilledAmount != 0 {
		t.Fatal("Order should not be filled")
	}
	t.Logf("Order confirmed unfilled")

	// Test bad order
	id, err = ok.SendOrder("kill", otype, amount, price)
	if id != 0 {
		t.Fatal("Expected id = 0")
	}
	if err == nil {
		t.Fatal("Expected error on bad order")
	}
}
<commit_msg>test cny book data and trading<commit_after>package okcoin

import (
	// "github.com/davecgh/go-spew/spew"
	"bitfx2/exchange"
	"os"
	"testing"
	"time"
)

var book exchange.Book
var ok = New(os.Getenv("OKUSD_KEY"), os.Getenv("OKUSD_SECRET"), "ltc", "usd", 1, 0.002)

func TestPriority(t *testing.T) {
	if ok.Priority() != 1 {
		t.Fatal("Priority should be 1")
	}
}

func TestFee(t *testing.T) {
	if ok.Fee()-0.002 > 0.000001 {
		t.Fatal("Fee should be 0.002")
	}
}

func TestUpdatePositon(t *testing.T) {
	if ok.Position() != 0 {
		t.Fatal("Should start with zero position")
	}
	ok.SetPosition(10)
	t.Logf("Set position to 10")
	if ok.Position() != 10 {
		t.Fatal("Position should have updated to 10")
	}
}

// USD tesing ******************************************************************

func TestCommunicateBookUSD(t *testing.T) {
	bookChan := make(chan exchange.Book)
	doneChan := make(chan bool)
	err := ok.CommunicateBook(bookChan, doneChan)
	if err != nil {
		t.Fatal(err)
	}

	// Notify doneChan in 5 seconds
	go func() {
		time.Sleep(5 * time.Second)
		doneChan <- true
		t.Logf("Notified doneChan")
	}()

	for book = range bookChan {
		t.Logf("Received book data")
		// spew.Dump(book)
		if len(book.Bids) != 20 || len(book.Asks) != 20 {
			t.Fatal("Expected 20 book entries")
		}
		if book.Bids[0].Price < book.Bids[1].Price {
			t.Fatal("Bids not sorted correctly")
		}
		if book.Asks[0].Price > book.Asks[1].Price {
			t.Fatal("Asks not sorted correctly")
		}
	}
}

func TestNewOrderUSD(t *testing.T) {
	action := "buy"
	otype := "limit"
	amount := 0.1
	price := book.Bids[0].Price - 0.20

	// Test submitting a new order
	id, err := ok.SendOrder(action, otype, amount, price)
	if err != nil || id == 0 {
		t.Fatal(err)
	}
	t.Logf("Placed a new buy order of 0.1 ltc_usd @ %v limit with ID: %d", price, id)

	// Check status
	order, err := ok.GetOrderStatus(id)
	if err != nil {
		t.Fatal(err)
	}
	if order.Status != "live" {
		t.Fatal("Order should be live")
	}
	t.Logf("Order confirmed live")
	if order.FilledAmount != 0 {
		t.Fatal("Order should not be filled")
	}
	t.Logf("Order confirmed unfilled")

	// Test cancelling the order
	success, err := ok.CancelOrder(id)
	if err != nil {
		t.Fatal(err)
	}
	if !success {
		t.Fatal("Order not cancelled")
	}
	t.Logf("Sent cancellation")

	// Check status
	tryAgain := true
	for tryAgain {
		t.Logf("checking status...")
		order, err = ok.GetOrderStatus(id)
		tryAgain = order.Status == ""
	}
	if err != nil {
		t.Fatal(err)
	}
	if order.Status != "dead" {
		t.Fatal("Order should be dead after cancel")
	}
	t.Logf("Order confirmed dead")
	if order.FilledAmount != 0 {
		t.Fatal("Order should not be filled")
	}
	t.Logf("Order confirmed unfilled")

	// Test bad order
	id, err = ok.SendOrder("kill", otype, amount, price)
	if id != 0 {
		t.Fatal("Expected id = 0")
	}
	if err == nil {
		t.Fatal("Expected error on bad order")
	}
}

// CNY tesing ******************************************************************

func TestCommunicateBookCNY(t *testing.T) {
	// Reset global variables
	book = exchange.Book{}
	ok = New(os.Getenv("OKCNY_KEY"), os.Getenv("OKCNY_SECRET"), "ltc", "cny", 1, 0.002)

	bookChan := make(chan exchange.Book)
	doneChan := make(chan bool)
	err := ok.CommunicateBook(bookChan, doneChan)
	if err != nil {
		t.Fatal(err)
	}

	// Notify doneChan in 5 seconds
	go func() {
		time.Sleep(5 * time.Second)
		doneChan <- true
		t.Logf("Notified doneChan")
	}()

	for book = range bookChan {
		t.Logf("Received book data")
		// spew.Dump(book)
		if len(book.Bids) != 20 || len(book.Asks) != 20 {
			t.Fatal("Expected 20 book entries")
		}
		if book.Bids[0].Price < book.Bids[1].Price {
			t.Fatal("Bids not sorted correctly")
		}
		if book.Asks[0].Price > book.Asks[1].Price {
			t.Fatal("Asks not sorted correctly")
		}
	}
}

func TestNewOrderCNY(t *testing.T) {
	action := "buy"
	otype := "limit"
	amount := 0.1
	price := book.Bids[0].Price - 1

	// Test submitting a new order
	id, err := ok.SendOrder(action, otype, amount, price)
	if err != nil || id == 0 {
		t.Fatal(err)
	}
	t.Logf("Placed a new buy order of 0.1 ltc_cny @ %v limit with ID: %d", price, id)

	// Check status
	order, err := ok.GetOrderStatus(id)
	if err != nil {
		t.Fatal(err)
	}
	if order.Status != "live" {
		t.Fatal("Order should be live")
	}
	t.Logf("Order confirmed live")
	if order.FilledAmount != 0 {
		t.Fatal("Order should not be filled")
	}
	t.Logf("Order confirmed unfilled")

	// Test cancelling the order
	success, err := ok.CancelOrder(id)
	if err != nil {
		t.Fatal(err)
	}
	if !success {
		t.Fatal("Order not cancelled")
	}
	t.Logf("Sent cancellation")

	// Check status
	tryAgain := true
	for tryAgain {
		t.Logf("checking status...")
		order, err = ok.GetOrderStatus(id)
		tryAgain = order.Status == ""
	}
	if err != nil {
		t.Fatal(err)
	}
	if order.Status != "dead" {
		t.Fatal("Order should be dead after cancel")
	}
	t.Logf("Order confirmed dead")
	if order.FilledAmount != 0 {
		t.Fatal("Order should not be filled")
	}
	t.Logf("Order confirmed unfilled")

	// Test bad order
	id, err = ok.SendOrder("kill", otype, amount, price)
	if id != 0 {
		t.Fatal("Expected id = 0")
	}
	if err == nil {
		t.Fatal("Expected error on bad order")
	}
}
<|endoftext|>


<commit_before>package opc

import (
	"fmt"
	"github.com/longears/pixelslinger/colorutils"
	"github.com/longears/pixelslinger/midi"
	"image"
	_ "image/color"
	_ "image/png"
	"math"
	"math/rand"
	"os"
	"time"
)

func handleErr(err error) {
	if err != nil {
		panic(fmt.Sprintf("%v", err))
	}
}

//================================================================================
// IMAGE

type MyColor struct {
	r float64
	g float64
	b float64
}

type MyImage struct {
	xres   int
	yres   int
	pixels [][]*MyColor // 2d array, [x][y]
}

// Init the MyImage pixel array, creating MyColor objects
// from the data in the given image (from the built-in image package).
// HSV is computed here also for each pixel.
func (mi *MyImage) populateFromImage(imgFn string) {
	// read and decode image
	file, err := os.Open(imgFn)
	handleErr(err)
	defer file.Close()
	img, _, err := image.Decode(file)
	handleErr(err)

	// copy and convert pixels
	mi.xres = img.Bounds().Max.X
	mi.yres = img.Bounds().Max.Y
	mi.pixels = make([][]*MyColor, mi.xres)
	for x := 0; x < mi.xres; x++ {
		mi.pixels[x] = make([]*MyColor, mi.yres)
		for y := 0; y < mi.yres; y++ {
			r, g, b, _ := img.At(x, y).RGBA()
			c := &MyColor{float64(r) / 256 / 256, float64(g) / 256 / 256, float64(b) / 256 / 256}
			mi.pixels[x][y] = c
		}
	}
}

func (mi *MyImage) String() string {
	return fmt.Sprintf("<image %v x %v>", mi.xres, mi.yres)
}

// given x and y as floats between 0 and 1,
// return r,g,b as floats between 0 and 1
func (mi *MyImage) getInterpolatedColor(x, y float64, wrapMethod string) (r, g, b float64) {

	switch wrapMethod {
	case "tile":
		// keep x and y between 0 and 1
		_, x = math.Modf(x)
		if x < 0 {
			x += 1
		}
		_, y = math.Modf(y)
		if y < 0 {
			y += 1
		}
	case "extend":
		x = colorutils.Clamp(x, 0, 1)
		y = colorutils.Clamp(y, 0, 1)
	case "mirror":
		x = colorutils.PosMod(x, 2)
		if x > 1 {
			x = 2 - x
		}
		y = colorutils.PosMod(y, 2)
		if y > 1 {
			y = 2 - y
		}
	}

	// float pixel coords
	xp := x * float64(mi.xres-1) * 0.999999
	yp := y * float64(mi.yres-1) * 0.999999

	// integer pixel coords
	x0 := int(xp)
	x1 := x0 + 1
	y0 := int(yp)
	y1 := y0 + 1

	// subpixel fractional coords for interpolation
	_, xPct := math.Modf(xp)
	_, yPct := math.Modf(yp)

	// retrieve colors from image array
	c00 := mi.pixels[x0][y0]
	c10 := mi.pixels[x1][y0]
	c01 := mi.pixels[x0][y1]
	c11 := mi.pixels[x1][y1]

	// interpolate
	r = (c00.r*(1-xPct)+c10.r*xPct)*(1-yPct) + (c01.r*(1-xPct)+c11.r*xPct)*yPct
	g = (c00.g*(1-xPct)+c10.g*xPct)*(1-yPct) + (c01.g*(1-xPct)+c11.g*xPct)*yPct
	b = (c00.b*(1-xPct)+c10.b*xPct)*(1-yPct) + (c01.b*(1-xPct)+c11.b*xPct)*yPct

	return r, g, b
}

//================================================================================
// PIXEL PATTERN

func MakePatternSunset(locations []float64) ByteThread {

	var (
		IMG_PATH = "images/sky4_square.png"
		DAY_LENGTH          = 20.0 // seconds
		SUN_SOFT_EDGE       = 0.2
		STAR_BRIGHTNESS_EXP = 2.7  // higher number means fewer bright stars
		STAR_THRESH         = 0.95
		STAR_CONTRAST       = 3.0
		STAR_FADE_EXP       = 4.0  // higher numbers keep stars from showing during sunrise/sunset
	)

	// make persistant random values
	rng := rand.New(rand.NewSource(9))
	randomValues := make([]float64, len(locations)/3)
	for ii := range randomValues {
		randomValues[ii] = math.Pow(rng.Float64(), STAR_BRIGHTNESS_EXP)
	}

	// get bounding box
	n_pixels := len(locations) / 3
	var max_coord_x, max_coord_y, max_coord_z float64
	var min_coord_x, min_coord_y, min_coord_z float64
	for ii := 0; ii < n_pixels; ii++ {
		x := locations[ii*3+0]
		y := locations[ii*3+1]
		z := locations[ii*3+2]
        if ii == 0 || x > max_coord_x { max_coord_x = x }
        if ii == 0 || y > max_coord_y { max_coord_y = y }
        if ii == 0 || z > max_coord_z { max_coord_z = z }
        if ii == 0 || x < min_coord_x { min_coord_x = x }
        if ii == 0 || y < min_coord_y { min_coord_y = y }
        if ii == 0 || z < min_coord_z { min_coord_z = z }
	}

	// load image
	myImage := &MyImage{}
	myImage.populateFromImage(IMG_PATH)

	return func(bytesIn chan []byte, bytesOut chan []byte, midiState *midi.MidiState) {
		for bytes := range bytesIn {
			n_pixels := len(bytes) / 3
			t := float64(time.Now().UnixNano())/1.0e9 - 9.4e8
			_ = t

			for ii := 0; ii < n_pixels; ii++ {
				//--------------------------------------------------------------------------------

				x := locations[ii*3+0] / 2
				y := locations[ii*3+1] / 2
				z := locations[ii*3+2] / 2
				_ = x
				_ = y
				_ = z

				zp := colorutils.Remap(z, min_coord_z, max_coord_z, 0, 1)

				// time of day, cycles through range 0 to 1.  0 is midnight, 0.5 is noon
				// sunrise at 0.25, sunset at 0.75
				timeOfDay := colorutils.PosMod2(t/DAY_LENGTH, 1)

				// compute sun height in range 0 to 1
				sunHeight := 0.0
				SUNRISE_TIME := 0.2 // range 0 to 0.25
				switch {
				case timeOfDay < 0.25-SUNRISE_TIME:
					sunHeight = 0
				case timeOfDay < 0.25+SUNRISE_TIME:
					sunHeight = colorutils.EaseRemapAndClamp(timeOfDay, 0.25-SUNRISE_TIME, 0.25+SUNRISE_TIME, 0, 1)
				case timeOfDay < 0.75-SUNRISE_TIME:
					sunHeight = 1
				case timeOfDay < 0.75+SUNRISE_TIME:
					sunHeight = colorutils.EaseRemapAndClamp(timeOfDay, 0.75-SUNRISE_TIME, 0.75+SUNRISE_TIME, 1, 0)
				default:
					sunHeight = 0
				}

				// sky color
				r, g, b := myImage.getInterpolatedColor(timeOfDay+0.5, 1-zp, "tile")

				// stars
				if ii >= 160 {
					// day/night
					starAmt := math.Pow(1-sunHeight, STAR_FADE_EXP)
					// fade at horizon
					starAmt *= math.Pow(colorutils.RemapAndClamp(zp, 0.35, 0.48, 0, 1), 2)
					// individual stars
					starAmt *= colorutils.Clamp(colorutils.Contrast(randomValues[ii], STAR_THRESH, STAR_CONTRAST), 0, 1)
					// twinkle
					starAmt *= colorutils.Cos(t, randomValues[ii], 0.3+2*colorutils.PosMod2(randomValues[ii]*7, 1), 0.6, 1)
					r += starAmt
					g += starAmt
					b += starAmt
				}

				// sun circle
				if ii < 160 {
					pct := float64(ii) / 160.0
					pct = pct * 2
					if pct > 1 {
						pct = 2 - pct
					}
					val := colorutils.Contrast(pct, colorutils.Remap(sunHeight, 0, 1, -SUN_SOFT_EDGE*2, 1+SUN_SOFT_EDGE*2), 1/SUN_SOFT_EDGE)
					val = colorutils.Clamp(1-val, 0, 1)
					r = val * 1.13
					g = val * 0.85
					b = val * 0.65
				}

				bytes[ii*3+0] = colorutils.FloatToByte(r)
				bytes[ii*3+1] = colorutils.FloatToByte(g)
				bytes[ii*3+2] = colorutils.FloatToByte(b)

				//--------------------------------------------------------------------------------
			}

			bytesOut <- bytes
		}
	}
}
<commit_msg>Tiny speedup for sunset pattern<commit_after>package opc

import (
	"fmt"
	"github.com/longears/pixelslinger/colorutils"
	"github.com/longears/pixelslinger/midi"
	"image"
	_ "image/color"
	_ "image/png"
	"math"
	"math/rand"
	"os"
	"time"
)

func handleErr(err error) {
	if err != nil {
		panic(fmt.Sprintf("%v", err))
	}
}

//================================================================================
// IMAGE

type MyColor struct {
	r float64
	g float64
	b float64
}

type MyImage struct {
	xres   int
	yres   int
	pixels [][]*MyColor // 2d array, [x][y]
}

// Init the MyImage pixel array, creating MyColor objects
// from the data in the given image (from the built-in image package).
// HSV is computed here also for each pixel.
func (mi *MyImage) populateFromImage(imgFn string) {
	// read and decode image
	file, err := os.Open(imgFn)
	handleErr(err)
	defer file.Close()
	img, _, err := image.Decode(file)
	handleErr(err)

	// copy and convert pixels
	mi.xres = img.Bounds().Max.X
	mi.yres = img.Bounds().Max.Y
	mi.pixels = make([][]*MyColor, mi.xres)
	for x := 0; x < mi.xres; x++ {
		mi.pixels[x] = make([]*MyColor, mi.yres)
		for y := 0; y < mi.yres; y++ {
			r, g, b, _ := img.At(x, y).RGBA()
			c := &MyColor{float64(r) / 256 / 256, float64(g) / 256 / 256, float64(b) / 256 / 256}
			mi.pixels[x][y] = c
		}
	}
}

func (mi *MyImage) String() string {
	return fmt.Sprintf("<image %v x %v>", mi.xres, mi.yres)
}

// given x and y as floats between 0 and 1,
// return r,g,b as floats between 0 and 1
func (mi *MyImage) getInterpolatedColor(x, y float64, wrapMethod string) (r, g, b float64) {

	switch wrapMethod {
	case "tile":
		// keep x and y between 0 and 1
		_, x = math.Modf(x)
		if x < 0 {
			x += 1
		}
		_, y = math.Modf(y)
		if y < 0 {
			y += 1
		}
	case "extend":
		x = colorutils.Clamp(x, 0, 1)
		y = colorutils.Clamp(y, 0, 1)
	case "mirror":
		x = colorutils.PosMod(x, 2)
		if x > 1 {
			x = 2 - x
		}
		y = colorutils.PosMod(y, 2)
		if y > 1 {
			y = 2 - y
		}
	}

	// float pixel coords
	xp := x * float64(mi.xres-1) * 0.999999
	yp := y * float64(mi.yres-1) * 0.999999

	// integer pixel coords
	x0 := int(xp)
	x1 := x0 + 1
	y0 := int(yp)
	y1 := y0 + 1

	// subpixel fractional coords for interpolation
	_, xPct := math.Modf(xp)
	_, yPct := math.Modf(yp)

	// retrieve colors from image array
	c00 := mi.pixels[x0][y0]
	c10 := mi.pixels[x1][y0]
	c01 := mi.pixels[x0][y1]
	c11 := mi.pixels[x1][y1]

	// interpolate
	r = (c00.r*(1-xPct)+c10.r*xPct)*(1-yPct) + (c01.r*(1-xPct)+c11.r*xPct)*yPct
	g = (c00.g*(1-xPct)+c10.g*xPct)*(1-yPct) + (c01.g*(1-xPct)+c11.g*xPct)*yPct
	b = (c00.b*(1-xPct)+c10.b*xPct)*(1-yPct) + (c01.b*(1-xPct)+c11.b*xPct)*yPct

	return r, g, b
}

//================================================================================
// PIXEL PATTERN

func MakePatternSunset(locations []float64) ByteThread {

	var (
		IMG_PATH = "images/sky4_square.png"
		DAY_LENGTH          = 20.0 // seconds
		SUN_SOFT_EDGE       = 0.2
		STAR_BRIGHTNESS_EXP = 2.7  // higher number means fewer bright stars
		STAR_THRESH         = 0.95
		STAR_CONTRAST       = 3.0
		STAR_FADE_EXP       = 4.0  // higher numbers keep stars from showing during sunrise/sunset
	)

	// make persistant random values
	rng := rand.New(rand.NewSource(9))
	randomValues := make([]float64, len(locations)/3)
	for ii := range randomValues {
		randomValues[ii] = math.Pow(rng.Float64(), STAR_BRIGHTNESS_EXP)
	}

	// get bounding box
	n_pixels := len(locations) / 3
	var max_coord_x, max_coord_y, max_coord_z float64
	var min_coord_x, min_coord_y, min_coord_z float64
	for ii := 0; ii < n_pixels; ii++ {
		x := locations[ii*3+0]
		y := locations[ii*3+1]
		z := locations[ii*3+2]
        if ii == 0 || x > max_coord_x { max_coord_x = x }
        if ii == 0 || y > max_coord_y { max_coord_y = y }
        if ii == 0 || z > max_coord_z { max_coord_z = z }
        if ii == 0 || x < min_coord_x { min_coord_x = x }
        if ii == 0 || y < min_coord_y { min_coord_y = y }
        if ii == 0 || z < min_coord_z { min_coord_z = z }
	}

	// load image
	myImage := &MyImage{}
	myImage.populateFromImage(IMG_PATH)

	return func(bytesIn chan []byte, bytesOut chan []byte, midiState *midi.MidiState) {
		for bytes := range bytesIn {
			n_pixels := len(bytes) / 3
			t := float64(time.Now().UnixNano())/1.0e9 - 9.4e8
			_ = t

			for ii := 0; ii < n_pixels; ii++ {
				//--------------------------------------------------------------------------------

				x := locations[ii*3+0] / 2
				y := locations[ii*3+1] / 2
				z := locations[ii*3+2] / 2
				_ = x
				_ = y
				_ = z

				zp := colorutils.Remap(z, min_coord_z, max_coord_z, 0, 1)

				// time of day, cycles through range 0 to 1.  0 is midnight, 0.5 is noon
				// sunrise at 0.25, sunset at 0.75
				timeOfDay := colorutils.PosMod2(t/DAY_LENGTH, 1)

				// compute sun height in range 0 to 1
				sunHeight := 0.0
				SUNRISE_TIME := 0.2 // range 0 to 0.25
				switch {
				case timeOfDay < 0.25-SUNRISE_TIME:
					sunHeight = 0
				case timeOfDay < 0.25+SUNRISE_TIME:
					sunHeight = colorutils.EaseRemapAndClamp(timeOfDay, 0.25-SUNRISE_TIME, 0.25+SUNRISE_TIME, 0, 1)
				case timeOfDay < 0.75-SUNRISE_TIME:
					sunHeight = 1
				case timeOfDay < 0.75+SUNRISE_TIME:
					sunHeight = colorutils.EaseRemapAndClamp(timeOfDay, 0.75-SUNRISE_TIME, 0.75+SUNRISE_TIME, 1, 0)
				default:
					sunHeight = 0
				}

				// sky color
				r, g, b := myImage.getInterpolatedColor(timeOfDay+0.5, 1-zp, "tile")

				// stars
				if ii >= 160 {
					// day/night
					starAmt := math.Pow(1-sunHeight, STAR_FADE_EXP)
					// fade at horizon
					starAmt *= math.Pow(colorutils.RemapAndClamp(zp, 0.35, 0.48, 0, 1), 2)
					// individual stars
					starAmt *= colorutils.ContrastAndClamp(randomValues[ii], STAR_THRESH, STAR_CONTRAST, 0, 1)
					// twinkle
					starAmt *= colorutils.Cos(t, randomValues[ii], 0.3+2*colorutils.PosMod2(randomValues[ii]*7, 1), 0.6, 1)
					r += starAmt
					g += starAmt
					b += starAmt
				}

				// sun circle
				if ii < 160 {
					pct := float64(ii) / 160.0
					pct = pct * 2
					if pct > 1 {
						pct = 2 - pct
					}
					val := colorutils.Contrast(pct, colorutils.Remap(sunHeight, 0, 1, -SUN_SOFT_EDGE*2, 1+SUN_SOFT_EDGE*2), 1/SUN_SOFT_EDGE)
					val = colorutils.Clamp(1-val, 0, 1)
					r = val * 1.13
					g = val * 0.85
					b = val * 0.65
				}

				bytes[ii*3+0] = colorutils.FloatToByte(r)
				bytes[ii*3+1] = colorutils.FloatToByte(g)
				bytes[ii*3+2] = colorutils.FloatToByte(b)

				//--------------------------------------------------------------------------------
			}

			bytesOut <- bytes
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Code generated by client-gen. DO NOT EDIT.

package fake

import (
	"context"

	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	labels "k8s.io/apimachinery/pkg/labels"
	schema "k8s.io/apimachinery/pkg/runtime/schema"
	types "k8s.io/apimachinery/pkg/types"
	watch "k8s.io/apimachinery/pkg/watch"
	testing "k8s.io/client-go/testing"
	v1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1"
)

// FakeFoos implements FooInterface
type FakeFoos struct {
	Fake *FakeSamplecontrollerV1alpha1
	ns   string
}

var foosResource = schema.GroupVersionResource{Group: "samplecontroller.k8s.io", Version: "v1alpha1", Resource: "foos"}

var foosKind = schema.GroupVersionKind{Group: "samplecontroller.k8s.io", Version: "v1alpha1", Kind: "Foo"}

// Get takes name of the foo, and returns the corresponding foo object, and an error if there is any.
func (c *FakeFoos) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Foo, err error) {
	obj, err := c.Fake.
		Invokes(testing.NewGetAction(foosResource, c.ns, name), &v1alpha1.Foo{})

	if obj == nil {
		return nil, err
	}
	return obj.(*v1alpha1.Foo), err
}

// List takes label and field selectors, and returns the list of Foos that match those selectors.
func (c *FakeFoos) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.FooList, err error) {
	obj, err := c.Fake.
		Invokes(testing.NewListAction(foosResource, foosKind, c.ns, opts), &v1alpha1.FooList{})

	if obj == nil {
		return nil, err
	}

	label, _, _ := testing.ExtractFromListOptions(opts)
	if label == nil {
		label = labels.Everything()
	}
	list := &v1alpha1.FooList{ListMeta: obj.(*v1alpha1.FooList).ListMeta}
	for _, item := range obj.(*v1alpha1.FooList).Items {
		if label.Matches(labels.Set(item.Labels)) {
			list.Items = append(list.Items, item)
		}
	}
	return list, err
}

// Watch returns a watch.Interface that watches the requested foos.
func (c *FakeFoos) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
	return c.Fake.
		InvokesWatch(testing.NewWatchAction(foosResource, c.ns, opts))

}

// Create takes the representation of a foo and creates it.  Returns the server's representation of the foo, and an error, if there is any.
func (c *FakeFoos) Create(ctx context.Context, foo *v1alpha1.Foo, opts v1.CreateOptions) (result *v1alpha1.Foo, err error) {
	obj, err := c.Fake.
		Invokes(testing.NewCreateAction(foosResource, c.ns, foo), &v1alpha1.Foo{})

	if obj == nil {
		return nil, err
	}
	return obj.(*v1alpha1.Foo), err
}

// Update takes the representation of a foo and updates it. Returns the server's representation of the foo, and an error, if there is any.
func (c *FakeFoos) Update(ctx context.Context, foo *v1alpha1.Foo, opts v1.UpdateOptions) (result *v1alpha1.Foo, err error) {
	obj, err := c.Fake.
		Invokes(testing.NewUpdateAction(foosResource, c.ns, foo), &v1alpha1.Foo{})

	if obj == nil {
		return nil, err
	}
	return obj.(*v1alpha1.Foo), err
}

// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakeFoos) UpdateStatus(ctx context.Context, foo *v1alpha1.Foo, opts v1.UpdateOptions) (*v1alpha1.Foo, error) {
	obj, err := c.Fake.
		Invokes(testing.NewUpdateSubresourceAction(foosResource, "status", c.ns, foo), &v1alpha1.Foo{})

	if obj == nil {
		return nil, err
	}
	return obj.(*v1alpha1.Foo), err
}

// Delete takes name of the foo and deletes it. Returns an error if one occurs.
func (c *FakeFoos) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
	_, err := c.Fake.
		Invokes(testing.NewDeleteAction(foosResource, c.ns, name), &v1alpha1.Foo{})

	return err
}

// DeleteCollection deletes a collection of objects.
func (c *FakeFoos) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
	action := testing.NewDeleteCollectionAction(foosResource, c.ns, listOpts)

	_, err := c.Fake.Invokes(action, &v1alpha1.FooList{})
	return err
}

// Patch applies the patch and returns the patched foo.
func (c *FakeFoos) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Foo, err error) {
	obj, err := c.Fake.
		Invokes(testing.NewPatchSubresourceAction(foosResource, c.ns, name, pt, data, subresources...), &v1alpha1.Foo{})

	if obj == nil {
		return nil, err
	}
	return obj.(*v1alpha1.Foo), err
}
<commit_msg>Auto generated<commit_after>/*
Copyright The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Code generated by client-gen. DO NOT EDIT.

package fake

import (
	"context"

	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	labels "k8s.io/apimachinery/pkg/labels"
	schema "k8s.io/apimachinery/pkg/runtime/schema"
	types "k8s.io/apimachinery/pkg/types"
	watch "k8s.io/apimachinery/pkg/watch"
	testing "k8s.io/client-go/testing"
	v1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1"
)

// FakeFoos implements FooInterface
type FakeFoos struct {
	Fake *FakeSamplecontrollerV1alpha1
	ns   string
}

var foosResource = schema.GroupVersionResource{Group: "samplecontroller.k8s.io", Version: "v1alpha1", Resource: "foos"}

var foosKind = schema.GroupVersionKind{Group: "samplecontroller.k8s.io", Version: "v1alpha1", Kind: "Foo"}

// Get takes name of the foo, and returns the corresponding foo object, and an error if there is any.
func (c *FakeFoos) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Foo, err error) {
	obj, err := c.Fake.
		Invokes(testing.NewGetAction(foosResource, c.ns, name), &v1alpha1.Foo{})

	if obj == nil {
		return nil, err
	}
	return obj.(*v1alpha1.Foo), err
}

// List takes label and field selectors, and returns the list of Foos that match those selectors.
func (c *FakeFoos) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.FooList, err error) {
	obj, err := c.Fake.
		Invokes(testing.NewListAction(foosResource, foosKind, c.ns, opts), &v1alpha1.FooList{})

	if obj == nil {
		return nil, err
	}

	label, _, _ := testing.ExtractFromListOptions(opts)
	if label == nil {
		label = labels.Everything()
	}
	list := &v1alpha1.FooList{ListMeta: obj.(*v1alpha1.FooList).ListMeta}
	for _, item := range obj.(*v1alpha1.FooList).Items {
		if label.Matches(labels.Set(item.Labels)) {
			list.Items = append(list.Items, item)
		}
	}
	return list, err
}

// Watch returns a watch.Interface that watches the requested foos.
func (c *FakeFoos) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
	return c.Fake.
		InvokesWatch(testing.NewWatchAction(foosResource, c.ns, opts))

}

// Create takes the representation of a foo and creates it.  Returns the server's representation of the foo, and an error, if there is any.
func (c *FakeFoos) Create(ctx context.Context, foo *v1alpha1.Foo, opts v1.CreateOptions) (result *v1alpha1.Foo, err error) {
	obj, err := c.Fake.
		Invokes(testing.NewCreateAction(foosResource, c.ns, foo), &v1alpha1.Foo{})

	if obj == nil {
		return nil, err
	}
	return obj.(*v1alpha1.Foo), err
}

// Update takes the representation of a foo and updates it. Returns the server's representation of the foo, and an error, if there is any.
func (c *FakeFoos) Update(ctx context.Context, foo *v1alpha1.Foo, opts v1.UpdateOptions) (result *v1alpha1.Foo, err error) {
	obj, err := c.Fake.
		Invokes(testing.NewUpdateAction(foosResource, c.ns, foo), &v1alpha1.Foo{})

	if obj == nil {
		return nil, err
	}
	return obj.(*v1alpha1.Foo), err
}

// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakeFoos) UpdateStatus(ctx context.Context, foo *v1alpha1.Foo, opts v1.UpdateOptions) (*v1alpha1.Foo, error) {
	obj, err := c.Fake.
		Invokes(testing.NewUpdateSubresourceAction(foosResource, "status", c.ns, foo), &v1alpha1.Foo{})

	if obj == nil {
		return nil, err
	}
	return obj.(*v1alpha1.Foo), err
}

// Delete takes name of the foo and deletes it. Returns an error if one occurs.
func (c *FakeFoos) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
	_, err := c.Fake.
		Invokes(testing.NewDeleteActionWithOptions(foosResource, c.ns, name, opts), &v1alpha1.Foo{})

	return err
}

// DeleteCollection deletes a collection of objects.
func (c *FakeFoos) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
	action := testing.NewDeleteCollectionAction(foosResource, c.ns, listOpts)

	_, err := c.Fake.Invokes(action, &v1alpha1.FooList{})
	return err
}

// Patch applies the patch and returns the patched foo.
func (c *FakeFoos) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Foo, err error) {
	obj, err := c.Fake.
		Invokes(testing.NewPatchSubresourceAction(foosResource, c.ns, name, pt, data, subresources...), &v1alpha1.Foo{})

	if obj == nil {
		return nil, err
	}
	return obj.(*v1alpha1.Foo), err
}
<|endoftext|>


<commit_before>package quic

import (
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"hash"
	"net"
	"sync"
	"time"

	"github.com/lucas-clemente/quic-go/internal/protocol"
	"github.com/lucas-clemente/quic-go/internal/utils"
	"github.com/lucas-clemente/quic-go/internal/wire"
)

type statelessResetErr struct {
	token *[16]byte
}

func (e statelessResetErr) StatelessResetToken() *[16]byte { return e.token }

func (e statelessResetErr) Error() string {
	return fmt.Sprintf("received a stateless reset with token %x", *e.token)
}

// The packetHandlerMap stores packetHandlers, identified by connection ID.
// It is used:
// * by the server to store sessions
// * when multiplexing outgoing connections to store clients
type packetHandlerMap struct {
	mutex sync.RWMutex

	conn      net.PacketConn
	connIDLen int

	handlers    map[string] /* string(ConnectionID)*/ packetHandler
	resetTokens map[[16]byte] /* stateless reset token */ packetHandler
	server      unknownPacketHandler

	listening chan struct{} // is closed when listen returns
	closed    bool

	deleteRetiredSessionsAfter time.Duration

	statelessResetEnabled bool
	statelessResetMutex   sync.Mutex
	statelessResetHasher  hash.Hash

	logger utils.Logger
}

var _ packetHandlerManager = &packetHandlerMap{}

func newPacketHandlerMap(
	conn net.PacketConn,
	connIDLen int,
	statelessResetKey []byte,
	logger utils.Logger,
) packetHandlerManager {
	m := &packetHandlerMap{
		conn:                       conn,
		connIDLen:                  connIDLen,
		listening:                  make(chan struct{}),
		handlers:                   make(map[string]packetHandler),
		resetTokens:                make(map[[16]byte]packetHandler),
		deleteRetiredSessionsAfter: protocol.RetiredConnectionIDDeleteTimeout,
		statelessResetEnabled:      len(statelessResetKey) > 0,
		statelessResetHasher:       hmac.New(sha256.New, statelessResetKey),
		logger:                     logger,
	}
	go m.listen()

	if logger.Debug() {
		go m.logUsage()
	}

	return m
}

func (h *packetHandlerMap) logUsage() {
	ticker := time.NewTicker(2 * time.Second)
	var printedZero bool
	for {
		select {
		case <-h.listening:
			return
		case <-ticker.C:
		}

		h.mutex.Lock()
		numHandlers := len(h.handlers)
		numTokens := len(h.resetTokens)
		h.mutex.Unlock()
		// If the number tracked handlers and tokens is zero, only print it a single time.
		hasZero := numHandlers == 0 && numTokens == 0
		if !hasZero || (hasZero && !printedZero) {
			h.logger.Debugf("Tracking %d connection IDs and %d reset tokens.\n", numHandlers, numTokens)
			printedZero = false
			if hasZero {
				printedZero = true
			}
		}
	}
}

func (h *packetHandlerMap) Add(id protocol.ConnectionID, handler packetHandler) bool /* was added */ {
	sid := string(id)

	h.mutex.Lock()
	defer h.mutex.Unlock()

	if _, ok := h.handlers[sid]; ok {
		return false
	}
	h.handlers[sid] = handler
	return true
}

func (h *packetHandlerMap) AddWithConnID(clientDestConnID, newConnID protocol.ConnectionID, fn func() packetHandler) bool {
	sid := string(clientDestConnID)
	h.mutex.Lock()
	defer h.mutex.Unlock()

	if _, ok := h.handlers[sid]; ok {
		return false
	}

	sess := fn()
	h.handlers[sid] = sess
	h.handlers[string(newConnID)] = sess
	return true
}

func (h *packetHandlerMap) Remove(id protocol.ConnectionID) {
	h.mutex.Lock()
	delete(h.handlers, string(id))
	h.mutex.Unlock()
}

func (h *packetHandlerMap) Retire(id protocol.ConnectionID) {
	time.AfterFunc(h.deleteRetiredSessionsAfter, func() {
		h.mutex.Lock()
		delete(h.handlers, string(id))
		h.mutex.Unlock()
	})
}

func (h *packetHandlerMap) ReplaceWithClosed(id protocol.ConnectionID, handler packetHandler) {
	h.mutex.Lock()
	h.handlers[string(id)] = handler
	h.mutex.Unlock()

	time.AfterFunc(h.deleteRetiredSessionsAfter, func() {
		h.mutex.Lock()
		handler.shutdown()
		delete(h.handlers, string(id))
		h.mutex.Unlock()
	})
}

func (h *packetHandlerMap) AddResetToken(token [16]byte, handler packetHandler) {
	h.mutex.Lock()
	h.resetTokens[token] = handler
	h.mutex.Unlock()
}

func (h *packetHandlerMap) RemoveResetToken(token [16]byte) {
	h.mutex.Lock()
	delete(h.resetTokens, token)
	h.mutex.Unlock()
}

func (h *packetHandlerMap) RetireResetToken(token [16]byte) {
	time.AfterFunc(h.deleteRetiredSessionsAfter, func() {
		h.mutex.Lock()
		delete(h.resetTokens, token)
		h.mutex.Unlock()
	})
}

func (h *packetHandlerMap) SetServer(s unknownPacketHandler) {
	h.mutex.Lock()
	h.server = s
	h.mutex.Unlock()
}

func (h *packetHandlerMap) CloseServer() {
	h.mutex.Lock()
	h.server = nil
	var wg sync.WaitGroup
	for _, handler := range h.handlers {
		if handler.getPerspective() == protocol.PerspectiveServer {
			wg.Add(1)
			go func(handler packetHandler) {
				// blocks until the CONNECTION_CLOSE has been sent and the run-loop has stopped
				handler.shutdown()
				wg.Done()
			}(handler)
		}
	}
	h.mutex.Unlock()
	wg.Wait()
}

// Destroy the underlying connection and wait until listen() has returned.
// It does not close active sessions.
func (h *packetHandlerMap) Destroy() error {
	if err := h.conn.Close(); err != nil {
		return err
	}
	<-h.listening // wait until listening returns
	return nil
}

func (h *packetHandlerMap) close(e error) error {
	h.mutex.Lock()
	if h.closed {
		h.mutex.Unlock()
		return nil
	}

	var wg sync.WaitGroup
	for _, handler := range h.handlers {
		wg.Add(1)
		go func(handler packetHandler) {
			handler.destroy(e)
			wg.Done()
		}(handler)
	}

	if h.server != nil {
		h.server.setCloseError(e)
	}
	h.closed = true
	h.mutex.Unlock()
	wg.Wait()
	return getMultiplexer().RemoveConn(h.conn)
}

func (h *packetHandlerMap) listen() {
	defer close(h.listening)
	for {
		buffer := getPacketBuffer()
		data := buffer.Data[:protocol.MaxReceivePacketSize]
		// The packet size should not exceed protocol.MaxReceivePacketSize bytes
		// If it does, we only read a truncated packet, which will then end up undecryptable
		n, addr, err := h.conn.ReadFrom(data)
		if err != nil {
			h.close(err)
			return
		}
		h.handlePacket(addr, buffer, data[:n])
	}
}

func (h *packetHandlerMap) handlePacket(
	addr net.Addr,
	buffer *packetBuffer,
	data []byte,
) {
	connID, err := wire.ParseConnectionID(data, h.connIDLen)
	if err != nil {
		h.logger.Debugf("error parsing connection ID on packet from %s: %s", addr, err)
		return
	}
	rcvTime := time.Now()

	h.mutex.RLock()
	defer h.mutex.RUnlock()

	if isStatelessReset := h.maybeHandleStatelessReset(data); isStatelessReset {
		return
	}

	handler, handlerFound := h.handlers[string(connID)]

	p := &receivedPacket{
		remoteAddr: addr,
		rcvTime:    rcvTime,
		buffer:     buffer,
		data:       data,
	}
	if handlerFound { // existing session
		handler.handlePacket(p)
		return
	}
	if data[0]&0x80 == 0 {
		go h.maybeSendStatelessReset(p, connID)
		return
	}
	if h.server == nil { // no server set
		h.logger.Debugf("received a packet with an unexpected connection ID %s", connID)
		return
	}
	h.server.handlePacket(p)
}

func (h *packetHandlerMap) maybeHandleStatelessReset(data []byte) bool {
	// stateless resets are always short header packets
	if data[0]&0x80 != 0 {
		return false
	}
	if len(data) < 17 /* type byte + 16 bytes for the reset token */ {
		return false
	}

	var token [16]byte
	copy(token[:], data[len(data)-16:])
	if sess, ok := h.resetTokens[token]; ok {
		h.logger.Debugf("Received a stateless reset with token %#x. Closing session.", token)
		go sess.destroy(&statelessResetErr{token: &token})
		return true
	}
	return false
}

func (h *packetHandlerMap) GetStatelessResetToken(connID protocol.ConnectionID) [16]byte {
	var token [16]byte
	if !h.statelessResetEnabled {
		// Return a random stateless reset token.
		// This token will be sent in the server's transport parameters.
		// By using a random token, an off-path attacker won't be able to disrupt the connection.
		rand.Read(token[:])
		return token
	}
	h.statelessResetMutex.Lock()
	h.statelessResetHasher.Write(connID.Bytes())
	copy(token[:], h.statelessResetHasher.Sum(nil))
	h.statelessResetHasher.Reset()
	h.statelessResetMutex.Unlock()
	return token
}

func (h *packetHandlerMap) maybeSendStatelessReset(p *receivedPacket, connID protocol.ConnectionID) {
	defer p.buffer.Release()
	if !h.statelessResetEnabled {
		return
	}
	// Don't send a stateless reset in response to very small packets.
	// This includes packets that could be stateless resets.
	if len(p.data) <= protocol.MinStatelessResetSize {
		return
	}
	token := h.GetStatelessResetToken(connID)
	h.logger.Debugf("Sending stateless reset to %s (connection ID: %s). Token: %#x", p.remoteAddr, connID, token)
	data := make([]byte, protocol.MinStatelessResetSize-16, protocol.MinStatelessResetSize)
	rand.Read(data)
	data[0] = (data[0] & 0x7f) | 0x40
	data = append(data, token[:]...)
	if _, err := h.conn.WriteTo(data, p.remoteAddr); err != nil {
		h.logger.Debugf("Error sending Stateless Reset: %s", err)
	}
}
<commit_msg>add debug logging to the packet handler map<commit_after>package quic

import (
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"hash"
	"net"
	"sync"
	"time"

	"github.com/lucas-clemente/quic-go/internal/protocol"
	"github.com/lucas-clemente/quic-go/internal/utils"
	"github.com/lucas-clemente/quic-go/internal/wire"
)

type statelessResetErr struct {
	token *[16]byte
}

func (e statelessResetErr) StatelessResetToken() *[16]byte { return e.token }

func (e statelessResetErr) Error() string {
	return fmt.Sprintf("received a stateless reset with token %x", *e.token)
}

// The packetHandlerMap stores packetHandlers, identified by connection ID.
// It is used:
// * by the server to store sessions
// * when multiplexing outgoing connections to store clients
type packetHandlerMap struct {
	mutex sync.RWMutex

	conn      net.PacketConn
	connIDLen int

	handlers    map[string] /* string(ConnectionID)*/ packetHandler
	resetTokens map[[16]byte] /* stateless reset token */ packetHandler
	server      unknownPacketHandler

	listening chan struct{} // is closed when listen returns
	closed    bool

	deleteRetiredSessionsAfter time.Duration

	statelessResetEnabled bool
	statelessResetMutex   sync.Mutex
	statelessResetHasher  hash.Hash

	logger utils.Logger
}

var _ packetHandlerManager = &packetHandlerMap{}

func newPacketHandlerMap(
	conn net.PacketConn,
	connIDLen int,
	statelessResetKey []byte,
	logger utils.Logger,
) packetHandlerManager {
	m := &packetHandlerMap{
		conn:                       conn,
		connIDLen:                  connIDLen,
		listening:                  make(chan struct{}),
		handlers:                   make(map[string]packetHandler),
		resetTokens:                make(map[[16]byte]packetHandler),
		deleteRetiredSessionsAfter: protocol.RetiredConnectionIDDeleteTimeout,
		statelessResetEnabled:      len(statelessResetKey) > 0,
		statelessResetHasher:       hmac.New(sha256.New, statelessResetKey),
		logger:                     logger,
	}
	go m.listen()

	if logger.Debug() {
		go m.logUsage()
	}

	return m
}

func (h *packetHandlerMap) logUsage() {
	ticker := time.NewTicker(2 * time.Second)
	var printedZero bool
	for {
		select {
		case <-h.listening:
			return
		case <-ticker.C:
		}

		h.mutex.Lock()
		numHandlers := len(h.handlers)
		numTokens := len(h.resetTokens)
		h.mutex.Unlock()
		// If the number tracked handlers and tokens is zero, only print it a single time.
		hasZero := numHandlers == 0 && numTokens == 0
		if !hasZero || (hasZero && !printedZero) {
			h.logger.Debugf("Tracking %d connection IDs and %d reset tokens.\n", numHandlers, numTokens)
			printedZero = false
			if hasZero {
				printedZero = true
			}
		}
	}
}

func (h *packetHandlerMap) Add(id protocol.ConnectionID, handler packetHandler) bool /* was added */ {
	sid := string(id)

	h.mutex.Lock()
	defer h.mutex.Unlock()

	if _, ok := h.handlers[sid]; ok {
		h.logger.Debugf("Not adding connection ID %s, as it already exists.", id)
		return false
	}
	h.handlers[sid] = handler
	h.logger.Debugf("Adding connection ID %s.", id)
	return true
}

func (h *packetHandlerMap) AddWithConnID(clientDestConnID, newConnID protocol.ConnectionID, fn func() packetHandler) bool {
	sid := string(clientDestConnID)
	h.mutex.Lock()
	defer h.mutex.Unlock()

	if _, ok := h.handlers[sid]; ok {
		h.logger.Debugf("Not adding connection ID %s for a new session, as it already exists.", clientDestConnID)
		return false
	}

	sess := fn()
	h.handlers[sid] = sess
	h.handlers[string(newConnID)] = sess
	h.logger.Debugf("Adding connection IDs %s and %s for a new session.", clientDestConnID, newConnID)
	return true
}

func (h *packetHandlerMap) Remove(id protocol.ConnectionID) {
	h.mutex.Lock()
	delete(h.handlers, string(id))
	h.mutex.Unlock()
	h.logger.Debugf("Removing connection ID %s.", id)
}

func (h *packetHandlerMap) Retire(id protocol.ConnectionID) {
	h.logger.Debugf("Retiring connection ID %s in %s.", id, h.deleteRetiredSessionsAfter)
	time.AfterFunc(h.deleteRetiredSessionsAfter, func() {
		h.mutex.Lock()
		delete(h.handlers, string(id))
		h.mutex.Unlock()
		h.logger.Debugf("Removing connection ID %s after it has been retired.", id)
	})
}

func (h *packetHandlerMap) ReplaceWithClosed(id protocol.ConnectionID, handler packetHandler) {
	h.mutex.Lock()
	h.handlers[string(id)] = handler
	h.mutex.Unlock()
	h.logger.Debugf("Replacing session for connection ID %s with a closed session.", id)

	time.AfterFunc(h.deleteRetiredSessionsAfter, func() {
		h.mutex.Lock()
		handler.shutdown()
		delete(h.handlers, string(id))
		h.mutex.Unlock()
		h.logger.Debugf("Removing connection ID %s for a closed session after it has been retired.", id)
	})
}

func (h *packetHandlerMap) AddResetToken(token [16]byte, handler packetHandler) {
	h.mutex.Lock()
	h.resetTokens[token] = handler
	h.mutex.Unlock()
}

func (h *packetHandlerMap) RemoveResetToken(token [16]byte) {
	h.mutex.Lock()
	delete(h.resetTokens, token)
	h.mutex.Unlock()
}

func (h *packetHandlerMap) RetireResetToken(token [16]byte) {
	time.AfterFunc(h.deleteRetiredSessionsAfter, func() {
		h.mutex.Lock()
		delete(h.resetTokens, token)
		h.mutex.Unlock()
	})
}

func (h *packetHandlerMap) SetServer(s unknownPacketHandler) {
	h.mutex.Lock()
	h.server = s
	h.mutex.Unlock()
}

func (h *packetHandlerMap) CloseServer() {
	h.mutex.Lock()
	h.server = nil
	var wg sync.WaitGroup
	for _, handler := range h.handlers {
		if handler.getPerspective() == protocol.PerspectiveServer {
			wg.Add(1)
			go func(handler packetHandler) {
				// blocks until the CONNECTION_CLOSE has been sent and the run-loop has stopped
				handler.shutdown()
				wg.Done()
			}(handler)
		}
	}
	h.mutex.Unlock()
	wg.Wait()
}

// Destroy the underlying connection and wait until listen() has returned.
// It does not close active sessions.
func (h *packetHandlerMap) Destroy() error {
	if err := h.conn.Close(); err != nil {
		return err
	}
	<-h.listening // wait until listening returns
	return nil
}

func (h *packetHandlerMap) close(e error) error {
	h.mutex.Lock()
	if h.closed {
		h.mutex.Unlock()
		return nil
	}

	var wg sync.WaitGroup
	for _, handler := range h.handlers {
		wg.Add(1)
		go func(handler packetHandler) {
			handler.destroy(e)
			wg.Done()
		}(handler)
	}

	if h.server != nil {
		h.server.setCloseError(e)
	}
	h.closed = true
	h.mutex.Unlock()
	wg.Wait()
	return getMultiplexer().RemoveConn(h.conn)
}

func (h *packetHandlerMap) listen() {
	defer close(h.listening)
	for {
		buffer := getPacketBuffer()
		data := buffer.Data[:protocol.MaxReceivePacketSize]
		// The packet size should not exceed protocol.MaxReceivePacketSize bytes
		// If it does, we only read a truncated packet, which will then end up undecryptable
		n, addr, err := h.conn.ReadFrom(data)
		if err != nil {
			h.close(err)
			return
		}
		h.handlePacket(addr, buffer, data[:n])
	}
}

func (h *packetHandlerMap) handlePacket(
	addr net.Addr,
	buffer *packetBuffer,
	data []byte,
) {
	connID, err := wire.ParseConnectionID(data, h.connIDLen)
	if err != nil {
		h.logger.Debugf("error parsing connection ID on packet from %s: %s", addr, err)
		return
	}
	rcvTime := time.Now()

	h.mutex.RLock()
	defer h.mutex.RUnlock()

	if isStatelessReset := h.maybeHandleStatelessReset(data); isStatelessReset {
		return
	}

	handler, handlerFound := h.handlers[string(connID)]

	p := &receivedPacket{
		remoteAddr: addr,
		rcvTime:    rcvTime,
		buffer:     buffer,
		data:       data,
	}
	if handlerFound { // existing session
		handler.handlePacket(p)
		return
	}
	if data[0]&0x80 == 0 {
		go h.maybeSendStatelessReset(p, connID)
		return
	}
	if h.server == nil { // no server set
		h.logger.Debugf("received a packet with an unexpected connection ID %s", connID)
		return
	}
	h.server.handlePacket(p)
}

func (h *packetHandlerMap) maybeHandleStatelessReset(data []byte) bool {
	// stateless resets are always short header packets
	if data[0]&0x80 != 0 {
		return false
	}
	if len(data) < 17 /* type byte + 16 bytes for the reset token */ {
		return false
	}

	var token [16]byte
	copy(token[:], data[len(data)-16:])
	if sess, ok := h.resetTokens[token]; ok {
		h.logger.Debugf("Received a stateless reset with token %#x. Closing session.", token)
		go sess.destroy(&statelessResetErr{token: &token})
		return true
	}
	return false
}

func (h *packetHandlerMap) GetStatelessResetToken(connID protocol.ConnectionID) [16]byte {
	var token [16]byte
	if !h.statelessResetEnabled {
		// Return a random stateless reset token.
		// This token will be sent in the server's transport parameters.
		// By using a random token, an off-path attacker won't be able to disrupt the connection.
		rand.Read(token[:])
		return token
	}
	h.statelessResetMutex.Lock()
	h.statelessResetHasher.Write(connID.Bytes())
	copy(token[:], h.statelessResetHasher.Sum(nil))
	h.statelessResetHasher.Reset()
	h.statelessResetMutex.Unlock()
	return token
}

func (h *packetHandlerMap) maybeSendStatelessReset(p *receivedPacket, connID protocol.ConnectionID) {
	defer p.buffer.Release()
	if !h.statelessResetEnabled {
		return
	}
	// Don't send a stateless reset in response to very small packets.
	// This includes packets that could be stateless resets.
	if len(p.data) <= protocol.MinStatelessResetSize {
		return
	}
	token := h.GetStatelessResetToken(connID)
	h.logger.Debugf("Sending stateless reset to %s (connection ID: %s). Token: %#x", p.remoteAddr, connID, token)
	data := make([]byte, protocol.MinStatelessResetSize-16, protocol.MinStatelessResetSize)
	rand.Read(data)
	data[0] = (data[0] & 0x7f) | 0x40
	data = append(data, token[:]...)
	if _, err := h.conn.WriteTo(data, p.remoteAddr); err != nil {
		h.logger.Debugf("Error sending Stateless Reset: %s", err)
	}
}
<|endoftext|>


<commit_before>package parser

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"testing"
)

import (
	"fmt"
	"os"
	"os/exec"

	"github.com/Sirupsen/logrus"
	"github.com/modcloth/docker-builder/builderfile"
	"github.com/modcloth/go-fileutils"
)

func TestBuilder(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Parser Specs")
}

var nullLogger = &logrus.Logger{
	Out:       os.Stderr,
	Formatter: new(logrus.TextFormatter),
	Level:     logrus.Panic,
}

var _ = Describe("Parse", func() {

	var (
		subject                 *Parser
		validFile               string
		invalidFile             string
		branch                  string
		rev                     string
		short                   string
		top                     string
		expectedCommandSequence *CommandSequence
		expectedInstructionSet  = &InstructionSet{
			DockerBuildOpts: []string{"--rm", "--no-cache"},
			DockerTagOpts:   []string{"--force"},
			Containers: []builderfile.ContainerSection{
				*&builderfile.ContainerSection{
					Name:       "base",
					Dockerfile: "Dockerfile.base",
					Included:   []string{"Gemfile", "Gemfile.lock"},
					Excluded:   []string{"spec", "tmp"},
					Registry:   "quay.io/modcloth",
					Project:    "style-gallery",
					Tags:       []string{"base"},
					SkipPush:   true,
				},
				*&builderfile.ContainerSection{
					Name:       "app",
					Dockerfile: "Dockerfile",
					Included:   []string{},
					Excluded:   []string{"spec", "tmp"},
					Registry:   "quay.io/modcloth",
					Project:    "style-gallery",
					Tags:       []string{"git:branch", "git:rev", "git:short"},
					SkipPush:   false,
				},
			},
		}
		expectedBuilderfile = &builderfile.Builderfile{
			Version: 1,
			Docker: *&builderfile.Docker{
				BuildOpts: []string{"--rm", "--no-cache"},
				TagOpts:   []string{"--force"},
			},
			ContainerGlobals: &builderfile.ContainerSection{
				Excluded: []string{"spec", "tmp"},
				Registry: "quay.io/modcloth",
				Project:  "style-gallery",
				Tags:     []string{"git:branch", "git:rev", "git:short"},
			},
			ContainerArr: []*builderfile.ContainerSection{
				&builderfile.ContainerSection{
					Name:       "base",
					Dockerfile: "Dockerfile.base",
					Included:   []string{"Gemfile", "Gemfile.lock"},
					Excluded:   nil,
					Registry:   "",
					Project:    "",
					Tags:       []string{"base"},
					SkipPush:   true,
				},
				&builderfile.ContainerSection{
					Name:       "app",
					Dockerfile: "Dockerfile",
					Included:   nil,
					Excluded:   nil,
					Registry:   "",
					Project:    "",
					Tags:       nil,
					SkipPush:   false,
				},
			},
		}
	)

	BeforeEach(func() {
		top = os.Getenv("PWD")
		git, _ := fileutils.Which("git")
		validFile = fmt.Sprintf("%s/spec/fixtures/bob.toml", top)
		invalidFile = fmt.Sprintf("%s/specs/fixtures/foodoesnotexist", top)
		subject = nil
		// branch
		branchCmd := &exec.Cmd{
			Path: git,
			Dir:  top,
			Args: []string{git, "rev-parse", "-q", "--abbrev-ref", "HEAD"},
		}

		branchBytes, _ := branchCmd.Output()
		branch = string(branchBytes)[:len(branchBytes)-1]

		// rev
		revCmd := &exec.Cmd{
			Path: git,
			Dir:  top,
			Args: []string{git, "rev-parse", "-q", "HEAD"},
		}
		revBytes, _ := revCmd.Output()
		rev = string(revBytes)[:len(revBytes)-1]

		// short
		shortCmd := &exec.Cmd{
			Path: git,
			Dir:  top,
			Args: []string{git, "describe", "--always", "--dirty", "--tags"},
		}
		shortBytes, _ := shortCmd.Output()
		short = string(shortBytes)[:len(shortBytes)-1]
		expectedCommandSequence = &CommandSequence{
			Commands: []*SubSequence{
				&SubSequence{
					Metadata: &SubSequenceMetadata{
						Name:       "base",
						Dockerfile: "Dockerfile.base",
						Excluded:   []string{"spec", "tmp"},
						Included:   []string{"Gemfile", "Gemfile.lock"},
						UUID:       "035c4ea0-d73b-5bde-7d6f-c806b04f2ec3",
					},
					SubCommand: []interface{}{
						*&exec.Cmd{
							Path: "docker",
							Args: []string{
								"docker",
								"build",
								"-t",
								"quay.io/modcloth/style-gallery:035c4ea0-d73b-5bde-7d6f-c806b04f2ec3",
								"--rm",
								"--no-cache",
								".",
							},
						},
						&TagCmd{Tag: "quay.io/modcloth/style-gallery:base"},
					},
				},
				&SubSequence{
					Metadata: &SubSequenceMetadata{
						Name:       "app",
						Dockerfile: "Dockerfile",
						Excluded:   []string{"spec", "tmp"},
						Included:   []string{},
						UUID:       "035c4ea0-d73b-5bde-7d6f-c806b04f2ec3",
					},
					SubCommand: []interface{}{
						*&exec.Cmd{
							Path: "docker",
							Args: []string{
								"docker",
								"build",
								"-t",
								"quay.io/modcloth/style-gallery:035c4ea0-d73b-5bde-7d6f-c806b04f2ec3",
								"--rm",
								"--no-cache",
								".",
							},
						},
						&TagCmd{Tag: fmt.Sprintf("quay.io/modcloth/style-gallery:%s", branch)},
						&TagCmd{Tag: fmt.Sprintf("quay.io/modcloth/style-gallery:%s", rev)},
						&TagCmd{Tag: fmt.Sprintf("quay.io/modcloth/style-gallery:%s", short)},
						*&exec.Cmd{
							Path: "docker",
							Args: []string{
								"docker",
								"push",
								fmt.Sprintf("quay.io/modcloth/style-gallery:%s", branch),
							},
						},
						*&exec.Cmd{
							Path: "docker",
							Args: []string{
								"docker",
								"push",
								fmt.Sprintf("quay.io/modcloth/style-gallery:%s", rev),
							},
						},
						*&exec.Cmd{
							Path: "docker",
							Args: []string{
								"docker",
								"push",
								fmt.Sprintf("quay.io/modcloth/style-gallery:%s", short),
							},
						},
					},
				},
			},
		}
	})

	Context("with a valid Builderfile", func() {

		It("produces an openable file", func() {
			subject, _ := NewParser(validFile, nullLogger)
			Expect(subject.IsOpenable()).To(Equal(true))
		})

		It("returns a non empty string and a nil error as raw data", func() {
			subject, _ := NewParser(validFile, nullLogger)
			raw, err := subject.getRaw()
			Expect(len(raw)).ToNot(Equal(0))
			Expect(err).To(BeNil())
		})

		It("returns a fully parsed Builderfile", func() {
			subject, _ := NewParser(validFile, nullLogger)
			actual, err := subject.rawToStruct()
			Expect(expectedBuilderfile).To(Equal(actual))
			Expect(err).To(BeNil())
		})

		It("further processes the Builderfile into an InstructionSet", func() {
			subject, _ := NewParser(validFile, nullLogger)
			actual, err := subject.structToInstructionSet()
			Expect(expectedInstructionSet).To(Equal(actual))
			Expect(err).To(BeNil())
		})

		It("further processes the InstructionSet into an CommandSequence", func() {
			subject, _ := NewParser(validFile, nullLogger)
			subject.SeedUUIDGenerator()
			actual, err := subject.instructionSetToCommandSequence()
			Expect(expectedCommandSequence).To(Equal(actual))
			Expect(err).To(BeNil())
		})
	})

	Context("with an invalid Builderfile", func() {
		It("returns an empty string and error as raw data", func() {
			subject, _ := NewParser(invalidFile, nullLogger)
			raw, err := subject.getRaw()
			Expect(raw).To(Equal(""))
			Expect(err).ToNot(BeNil())
		})
	})
})
<commit_msg>Fixing the parser specs for the new tag/push commands<commit_after>package parser

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"testing"
)

import (
	"fmt"
	"os"
	"os/exec"

	"github.com/Sirupsen/logrus"
	"github.com/modcloth/docker-builder/builderfile"
	"github.com/modcloth/go-fileutils"
)

func TestBuilder(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Parser Specs")
}

var nullLogger = &logrus.Logger{
	Out:       os.Stderr,
	Formatter: new(logrus.TextFormatter),
	Level:     logrus.Panic,
}

var _ = Describe("Parse", func() {

	var (
		subject                 *Parser
		validFile               string
		invalidFile             string
		branch                  string
		rev                     string
		short                   string
		top                     string
		expectedCommandSequence *CommandSequence
		expectedInstructionSet  = &InstructionSet{
			DockerBuildOpts: []string{"--rm", "--no-cache"},
			DockerTagOpts:   []string{"--force"},
			Containers: []builderfile.ContainerSection{
				*&builderfile.ContainerSection{
					Name:       "base",
					Dockerfile: "Dockerfile.base",
					Included:   []string{"Gemfile", "Gemfile.lock"},
					Excluded:   []string{"spec", "tmp"},
					Registry:   "quay.io/modcloth",
					Project:    "style-gallery",
					Tags:       []string{"base"},
					SkipPush:   true,
				},
				*&builderfile.ContainerSection{
					Name:       "app",
					Dockerfile: "Dockerfile",
					Included:   []string{},
					Excluded:   []string{"spec", "tmp"},
					Registry:   "quay.io/modcloth",
					Project:    "style-gallery",
					Tags:       []string{"git:branch", "git:rev", "git:short"},
					SkipPush:   false,
				},
			},
		}
		expectedBuilderfile = &builderfile.Builderfile{
			Version: 1,
			Docker: *&builderfile.Docker{
				BuildOpts: []string{"--rm", "--no-cache"},
				TagOpts:   []string{"--force"},
			},
			ContainerGlobals: &builderfile.ContainerSection{
				Excluded: []string{"spec", "tmp"},
				Registry: "quay.io/modcloth",
				Project:  "style-gallery",
				Tags:     []string{"git:branch", "git:rev", "git:short"},
			},
			ContainerArr: []*builderfile.ContainerSection{
				&builderfile.ContainerSection{
					Name:       "base",
					Dockerfile: "Dockerfile.base",
					Included:   []string{"Gemfile", "Gemfile.lock"},
					Excluded:   nil,
					Registry:   "",
					Project:    "",
					Tags:       []string{"base"},
					SkipPush:   true,
				},
				&builderfile.ContainerSection{
					Name:       "app",
					Dockerfile: "Dockerfile",
					Included:   nil,
					Excluded:   nil,
					Registry:   "",
					Project:    "",
					Tags:       nil,
					SkipPush:   false,
				},
			},
		}
	)

	BeforeEach(func() {
		top = os.Getenv("PWD")
		git, _ := fileutils.Which("git")
		validFile = fmt.Sprintf("%s/spec/fixtures/bob.toml", top)
		invalidFile = fmt.Sprintf("%s/specs/fixtures/foodoesnotexist", top)
		subject = nil
		// branch
		branchCmd := &exec.Cmd{
			Path: git,
			Dir:  top,
			Args: []string{git, "rev-parse", "-q", "--abbrev-ref", "HEAD"},
		}

		branchBytes, _ := branchCmd.Output()
		branch = string(branchBytes)[:len(branchBytes)-1]

		// rev
		revCmd := &exec.Cmd{
			Path: git,
			Dir:  top,
			Args: []string{git, "rev-parse", "-q", "HEAD"},
		}
		revBytes, _ := revCmd.Output()
		rev = string(revBytes)[:len(revBytes)-1]

		// short
		shortCmd := &exec.Cmd{
			Path: git,
			Dir:  top,
			Args: []string{git, "describe", "--always", "--dirty", "--tags"},
		}
		shortBytes, _ := shortCmd.Output()
		short = string(shortBytes)[:len(shortBytes)-1]
		expectedCommandSequence = &CommandSequence{
			Commands: []*SubSequence{
				&SubSequence{
					Metadata: &SubSequenceMetadata{
						Name:       "base",
						Dockerfile: "Dockerfile.base",
						Excluded:   []string{"spec", "tmp"},
						Included:   []string{"Gemfile", "Gemfile.lock"},
						UUID:       "035c4ea0-d73b-5bde-7d6f-c806b04f2ec3",
					},
					SubCommand: []interface{}{
						*&exec.Cmd{
							Path: "docker",
							Args: []string{
								"docker",
								"build",
								"-t",
								"quay.io/modcloth/style-gallery:035c4ea0-d73b-5bde-7d6f-c806b04f2ec3",
								"--rm",
								"--no-cache",
								".",
							},
						},
						&TagCmd{
							Repo: "quay.io/modcloth/style-gallery",
							Tag:  "base",
						},
					},
				},
				&SubSequence{
					Metadata: &SubSequenceMetadata{
						Name:       "app",
						Dockerfile: "Dockerfile",
						Excluded:   []string{"spec", "tmp"},
						Included:   []string{},
						UUID:       "035c4ea0-d73b-5bde-7d6f-c806b04f2ec3",
					},
					SubCommand: []interface{}{
						*&exec.Cmd{
							Path: "docker",
							Args: []string{
								"docker",
								"build",
								"-t",
								"quay.io/modcloth/style-gallery:035c4ea0-d73b-5bde-7d6f-c806b04f2ec3",
								"--rm",
								"--no-cache",
								".",
							},
						},
						&TagCmd{
							Repo: "quay.io/modcloth/style-gallery",
							Tag:  branch,
						},
						&TagCmd{
							Repo: "quay.io/modcloth/style-gallery",
							Tag:  rev,
						},
						&TagCmd{
							Repo: "quay.io/modcloth/style-gallery",
							Tag:  short,
						},
						&PushCmd{
							Image:    "quay.io/modcloth/style-gallery",
							Tag:      branch,
							Registry: "quay.io/modcloth",
						},
						&PushCmd{
							Image:    "quay.io/modcloth/style-gallery",
							Tag:      rev,
							Registry: "quay.io/modcloth",
						},
						&PushCmd{
							Image:    "quay.io/modcloth/style-gallery",
							Tag:      short,
							Registry: "quay.io/modcloth",
						},
					},
				},
			},
		}
	})

	Context("with a valid Builderfile", func() {

		It("produces an openable file", func() {
			subject, _ := NewParser(validFile, nullLogger)
			Expect(subject.IsOpenable()).To(Equal(true))
		})

		It("returns a non empty string and a nil error as raw data", func() {
			subject, _ := NewParser(validFile, nullLogger)
			raw, err := subject.getRaw()
			Expect(len(raw)).ToNot(Equal(0))
			Expect(err).To(BeNil())
		})

		It("returns a fully parsed Builderfile", func() {
			subject, _ := NewParser(validFile, nullLogger)
			actual, err := subject.rawToStruct()
			Expect(expectedBuilderfile).To(Equal(actual))
			Expect(err).To(BeNil())
		})

		It("further processes the Builderfile into an InstructionSet", func() {
			subject, _ := NewParser(validFile, nullLogger)
			actual, err := subject.structToInstructionSet()
			Expect(expectedInstructionSet).To(Equal(actual))
			Expect(err).To(BeNil())
		})

		It("further processes the InstructionSet into an CommandSequence", func() {
			subject, _ := NewParser(validFile, nullLogger)
			subject.SeedUUIDGenerator()
			actual, err := subject.instructionSetToCommandSequence()
			Expect(expectedCommandSequence).To(Equal(actual))
			Expect(err).To(BeNil())
		})
	})

	Context("with an invalid Builderfile", func() {
		It("returns an empty string and error as raw data", func() {
			subject, _ := NewParser(invalidFile, nullLogger)
			raw, err := subject.getRaw()
			Expect(raw).To(Equal(""))
			Expect(err).ToNot(BeNil())
		})
	})
})
<|endoftext|>


<commit_before>package parser

import (
	"math/big"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"testing"

	"github.com/alecthomas/participle/v2/lexer"
	"github.com/alecthomas/repr"
	"github.com/stretchr/testify/require"
)

func TestParserFromFixtures(t *testing.T) {
	files, err := filepath.Glob("../testdata/*.proto")
	require.NoError(t, err)
	for _, file := range files {
		t.Run(file, func(t *testing.T) {
			r, err := os.Open(file)
			require.NoError(t, err)
			_, err = Parse(file, r)
			require.NoError(t, err)
		})
	}
}

func TestParser(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected *Proto
	}{{
		name: "MessageOptions",
		input: `
			message VariousComplexOptions {
			  option (complex_opt2).bar.(protobuf_unittest.corge).qux = 2008;
			  option (complex_opt2).(protobuf_unittest.garply).(corge).qux = 2121;
			  option .(.ComplexOptionType2.ComplexOptionType4.complex_opt4).waldo = 1971;
			  option (strings) = "1" "2";
			}
			`,
		expected: &Proto{
			Entries: []*Entry{
				{Message: &Message{
					Name: "VariousComplexOptions",
					Entries: []*MessageEntry{
						{Option: &Option{
							Name:  []*OptionName{{Name: "(complex_opt2)"}, {Name: "bar"}, {Name: "(protobuf_unittest.corge)"}, {Name: "qux"}},
							Value: &Value{Number: toBig(2008)},
						}},
						{Option: &Option{
							Name:  []*OptionName{{Name: "(complex_opt2)"}, {Name: "(protobuf_unittest.garply)"}, {Name: "(corge)"}, {Name: "qux"}},
							Value: &Value{Number: toBig(2121)},
						}},
						{Option: &Option{
							Name:  []*OptionName{{Name: ".(.ComplexOptionType2.ComplexOptionType4.complex_opt4)"}, {Name: "waldo"}},
							Value: &Value{Number: toBig(1971)},
						}},
						{Option: &Option{
							Name:  []*OptionName{{Name: "(strings)"}},
							Value: &Value{String: strP("12")},
						}},
					},
				}},
			},
		}},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			actual, err := ParseString(test.name, test.input)
			require.NoError(t, err)
			_ = Visit(actual, clearPos)
			expectedStr := repr.String(test.expected, repr.Indent("  "))
			actualStr := repr.String(actual, repr.Indent("  "))
			require.Equal(t, expectedStr, actualStr, actualStr)
		})
	}
}

func TestImports(t *testing.T) {
	tests := []struct {
		name   string
		source string
		want   []*Import
	}{{
		name:   "parses a single import correctly",
		source: `import 'foo/bar/test.proto'`,
		want:   []*Import{{Name: "foo/bar/test.proto", Public: false}},
	}, {
		name:   "parses public imports correctly",
		source: `import public "foo/bar/test.proto"`,
		want:   []*Import{{Name: "foo/bar/test.proto", Public: true}},
	}}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := ParseString("test.proto", tt.source)
			require.NoError(t, err)

			result := imports(got)
			require.Equal(t, tt.want, result)
		})
	}
}

func imports(from *Proto) []*Import {
	var result []*Import
	for _, entity := range from.Entries {
		if entity.Import != nil {
			result = append(result, entity.Import)
		}
	}
	return result
}

var zeroPos = reflect.ValueOf(lexer.Position{})

func clearPos(node Node, next func() error) error {
	reflect.Indirect(reflect.ValueOf(node)).FieldByName("Pos").Set(zeroPos)
	return next()
}

func toBig(n int) *big.Float {
	f, _, _ := big.ParseFloat(strconv.Itoa(n), 10, 64, 0)
	return f
}

func strP(s string) *string {
	return &s
}
<commit_msg>Update parser_test.go for valid option input<commit_after>package parser

import (
	"math/big"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"testing"

	"github.com/alecthomas/participle/v2/lexer"
	"github.com/alecthomas/repr"
	"github.com/stretchr/testify/require"
)

func TestParserFromFixtures(t *testing.T) {
	files, err := filepath.Glob("../testdata/*.proto")
	require.NoError(t, err)
	for _, file := range files {
		t.Run(file, func(t *testing.T) {
			r, err := os.Open(file)
			require.NoError(t, err)
			_, err = Parse(file, r)
			require.NoError(t, err)
		})
	}
}

func TestParser(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected *Proto
	}{{
		name: "MessageOptions",
		input: `
			message VariousComplexOptions {
			  option (complex_opt2).bar.(protobuf_unittest.corge).qux = 2008;
			  option (complex_opt2).(protobuf_unittest.garply).(corge).qux = 2121;
			  option (.ComplexOptionType2.ComplexOptionType4.complex_opt4).waldo = 1971;
			  option (strings) = "1" "2";
			}
			`,
		expected: &Proto{
			Entries: []*Entry{
				{Message: &Message{
					Name: "VariousComplexOptions",
					Entries: []*MessageEntry{
						{Option: &Option{
							Name:  []*OptionName{{Name: "(complex_opt2)"}, {Name: "bar"}, {Name: "(protobuf_unittest.corge)"}, {Name: "qux"}},
							Value: &Value{Number: toBig(2008)},
						}},
						{Option: &Option{
							Name:  []*OptionName{{Name: "(complex_opt2)"}, {Name: "(protobuf_unittest.garply)"}, {Name: "(corge)"}, {Name: "qux"}},
							Value: &Value{Number: toBig(2121)},
						}},
						{Option: &Option{
							Name:  []*OptionName{{Name: "(.ComplexOptionType2.ComplexOptionType4.complex_opt4)"}, {Name: "waldo"}},
							Value: &Value{Number: toBig(1971)},
						}},
						{Option: &Option{
							Name:  []*OptionName{{Name: "(strings)"}},
							Value: &Value{String: strP("12")},
						}},
					},
				}},
			},
		}},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			actual, err := ParseString(test.name, test.input)
			require.NoError(t, err)
			_ = Visit(actual, clearPos)
			expectedStr := repr.String(test.expected, repr.Indent("  "))
			actualStr := repr.String(actual, repr.Indent("  "))
			require.Equal(t, expectedStr, actualStr, actualStr)
		})
	}
}

func TestImports(t *testing.T) {
	tests := []struct {
		name   string
		source string
		want   []*Import
	}{{
		name:   "parses a single import correctly",
		source: `import 'foo/bar/test.proto'`,
		want:   []*Import{{Name: "foo/bar/test.proto", Public: false}},
	}, {
		name:   "parses public imports correctly",
		source: `import public "foo/bar/test.proto"`,
		want:   []*Import{{Name: "foo/bar/test.proto", Public: true}},
	}}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := ParseString("test.proto", tt.source)
			require.NoError(t, err)

			result := imports(got)
			require.Equal(t, tt.want, result)
		})
	}
}

func imports(from *Proto) []*Import {
	var result []*Import
	for _, entity := range from.Entries {
		if entity.Import != nil {
			result = append(result, entity.Import)
		}
	}
	return result
}

var zeroPos = reflect.ValueOf(lexer.Position{})

func clearPos(node Node, next func() error) error {
	reflect.Indirect(reflect.ValueOf(node)).FieldByName("Pos").Set(zeroPos)
	return next()
}

func toBig(n int) *big.Float {
	f, _, _ := big.ParseFloat(strconv.Itoa(n), 10, 64, 0)
	return f
}

func strP(s string) *string {
	return &s
}
<|endoftext|>


<commit_before>package encoders

import (
	"github.com/stretchr/testify/assert"
	"github.com/zacg/htm/utils"
	"testing"
)

func TestSimpleEncoding(t *testing.T) {

	p := NewScalerEncoderParams(3, 1, 8)
	//p.Resolution = 1
	p.N = 14
	//p.Width = 3
	//p.MaxVal = 8
	//p.MinVal = 1
	p.Periodic = true
	//p.Verbosity = 5

	e := NewScalerEncoder(p)

	encoded := e.Encode(1, false)
	t.Log(encoded)
	expected := utils.Make1DBool([]int{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
	assert.True(t, len(encoded) == 14)
	assert.Equal(t, expected, encoded)

	encoded = e.Encode(2, false)
	expected = utils.Make1DBool([]int{0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
	assert.True(t, len(encoded) == 14)
	assert.Equal(t, expected, encoded)

	encoded = e.Encode(3, false)
	expected = utils.Make1DBool([]int{0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0})
	assert.True(t, len(encoded) == 14)
	assert.Equal(t, expected, encoded)

}
<commit_msg>decode() unit test<commit_after>package encoders

import (
	"github.com/stretchr/testify/assert"
	"github.com/zacg/htm/utils"
	"testing"
)

func TestSimpleEncoding(t *testing.T) {

	p := NewScalerEncoderParams(3, 1, 8)
	//p.Resolution = 1
	p.N = 14
	//p.Width = 3
	//p.MaxVal = 8
	//p.MinVal = 1
	p.Periodic = true
	//p.Verbosity = 5

	e := NewScalerEncoder(p)

	encoded := e.Encode(1, false)
	t.Log(encoded)
	expected := utils.Make1DBool([]int{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
	assert.True(t, len(encoded) == 14)
	assert.Equal(t, expected, encoded)

	encoded = e.Encode(2, false)
	expected = utils.Make1DBool([]int{0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
	assert.True(t, len(encoded) == 14)
	assert.Equal(t, expected, encoded)

	encoded = e.Encode(3, false)
	expected = utils.Make1DBool([]int{0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0})
	assert.True(t, len(encoded) == 14)
	assert.Equal(t, expected, encoded)

}

func TestSimpleDecoding(t *testing.T) {

	p := NewScalerEncoderParams(3, 1, 8)
	//p.Resolution = 1
	//p.N = 14
	p.Radius = 1.5
	//p.Width = 3
	//p.MaxVal = 8
	//p.MinVal = 1
	p.Periodic = true
	p.Verbosity = 5

	e := NewScalerEncoder(p)

	// Test with a "hole"
	encoded := utils.Make1DBool([]int{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0})
	expected := []utils.TupleFloat{utils.TupleFloat{7.5, 7.5}}
	actual := e.Decode(encoded)
	assert.Equal(t, expected, actual)

	// Test with something wider than w, and with a hole, and wrapped
	encoded = utils.Make1DBool([]int{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0})
	expected = []utils.TupleFloat{utils.TupleFloat{7.5, 8}}
	actual = e.Decode(encoded)
	assert.Equal(t, expected, actual)

	// Test with something wider than w, no hole
	encoded = utils.Make1DBool([]int{1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0})
	expected = []utils.TupleFloat{utils.TupleFloat{1.5, 2.5}}
	actual = e.Decode(encoded)
	assert.Equal(t, expected, actual)

	// 1
	encoded = utils.Make1DBool([]int{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
	expected = []utils.TupleFloat{utils.TupleFloat{1, 1}}
	actual = e.Decode(encoded)
	assert.Equal(t, expected, actual)

	// 2
	encoded = utils.Make1DBool([]int{0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
	expected = []utils.TupleFloat{utils.TupleFloat{2, 2}}
	actual = e.Decode(encoded)
	assert.Equal(t, expected, actual)

}
<|endoftext|>


<commit_before>package backend

import (
	"image"
	"image/draw"
	"strconv"
	"strings"

	"github.com/disintegration/imaging"
	colorful "github.com/lucasb-eyer/go-colorful"

	imagefile "github.com/thoas/picfit/image"
)

func (e *GoImage) Flat(backgroundFile *imagefile.ImageFile, options *Options) ([]byte, error) {
	if options.Format == imaging.GIF {
		return e.TransformGIF(backgroundFile, options, imaging.Resize)
	}

	background, err := e.Source(backgroundFile)
	if err != nil {
		return nil, err
	}

	images := make([]image.Image, len(options.Images))
	for i := range options.Images {
		images[i], err = e.Source(&options.Images[i])
		if err != nil {
			return nil, err
		}
	}

	bg := image.NewRGBA(image.Rectangle{image.Point{}, background.Bounds().Size()})
	draw.Draw(bg, background.Bounds(), background, image.Point{}, draw.Src)

	dst := positionForeground(bg, options.Position)
	fg := foregroundImage(dst, options.Color)
	fg = drawForeground(fg, images, options)

	draw.Draw(bg, dst, fg, fg.Bounds().Min, draw.Over)

	return e.ToBytes(bg, options.Format, options.Quality)
}

func positionForeground(bg image.Image, pos string) image.Rectangle {
	ratios := []int{100, 100, 100, 100}
	val := strings.Split(pos, ".")
	for i := range val {
		if i+1 > len(ratios) {
			break
		}
		ratios[i], _ = strconv.Atoi(val[i])
	}
	b := bg.Bounds()
	return image.Rectangle{
		image.Point{b.Dx() * ratios[0], b.Dy() * ratios[1]}.Div(100),
		image.Point{b.Dx() * ratios[2], b.Dy() * ratios[3]}.Div(100),
	}
}

func foregroundImage(rec image.Rectangle, c string) *image.RGBA {
	fg := image.NewRGBA(image.Rectangle{image.ZP, rec.Size()})
	if c == "" {
		return fg
	}

	col, err := colorful.Hex(c)
	if err != nil {
		return fg
	}

	draw.Draw(fg, fg.Bounds(), &image.Uniform{col}, fg.Bounds().Min, draw.Src)
	return fg
}

func drawForeground(fg *image.RGBA, images []image.Image, options *Options) *image.RGBA {
	n := len(images)
	if n == 0 {
		return fg
	}

	// resize images for foreground
	b := fg.Bounds()
	opts := &Options{Upscale: true}

	if b.Dx() > b.Dy() {
		opts.Width = b.Dx() / n
		opts.Height = b.Dy()
	} else {
		opts.Width = b.Dx()
		opts.Height = b.Dy() / n
	}

	for i := range images {
		images[i] = scale(images[i], opts, imaging.Fit)
	}

	if b.Dx() > b.Dy() {
		return foregroundHorizontal(fg, images, options)
	} else {
		return foregroundVertical(fg, images, options)
	}
}

func foregroundHorizontal(fg *image.RGBA, images []image.Image, options *Options) *image.RGBA {
	position := fg.Bounds().Min
	totalHeight := fg.Bounds().Dy()
	cellWidth := fg.Bounds().Dx() / len(images)
	for i := range images {
		bounds := images[i].Bounds()
		position.Y = (totalHeight - bounds.Dy()) / 2
		position.X = fg.Bounds().Min.X + i*cellWidth + (cellWidth-bounds.Dx())/2
		r := image.Rectangle{
			position,
			position.Add(fg.Bounds().Size()),
		}
		draw.Draw(fg, r, images[i], bounds.Min, draw.Over)
	}
	return fg
}

func foregroundVertical(fg *image.RGBA, images []image.Image, options *Options) *image.RGBA {
	position := fg.Bounds().Min
	cellHeight := fg.Bounds().Dy() / len(images)
	totalWidth := fg.Bounds().Dx()
	for i := range images {
		bounds := images[i].Bounds()
		position.Y = fg.Bounds().Min.Y + i*cellHeight + (cellHeight-bounds.Dy())/2
		position.X = fg.Bounds().Min.X + (totalWidth-bounds.Dx())/2
		r := image.Rectangle{
			position,
			position.Add(image.Point{bounds.Dx(), bounds.Dy()}),
		}
		draw.Draw(fg, r, images[i], bounds.Min, draw.Over)
	}
	return fg
}
<commit_msg>fix color hex<commit_after>package backend

import (
	"fmt"
	"image"
	"image/draw"
	"strconv"
	"strings"

	"github.com/disintegration/imaging"
	colorful "github.com/lucasb-eyer/go-colorful"

	imagefile "github.com/thoas/picfit/image"
)

func (e *GoImage) Flat(backgroundFile *imagefile.ImageFile, options *Options) ([]byte, error) {
	if options.Format == imaging.GIF {
		return e.TransformGIF(backgroundFile, options, imaging.Resize)
	}

	background, err := e.Source(backgroundFile)
	if err != nil {
		return nil, err
	}

	images := make([]image.Image, len(options.Images))
	for i := range options.Images {
		images[i], err = e.Source(&options.Images[i])
		if err != nil {
			return nil, err
		}
	}

	bg := image.NewRGBA(image.Rectangle{image.Point{}, background.Bounds().Size()})
	draw.Draw(bg, background.Bounds(), background, image.Point{}, draw.Src)

	dst := positionForeground(bg, options.Position)
	fg := foregroundImage(dst, options.Color)
	fg = drawForeground(fg, images, options)

	draw.Draw(bg, dst, fg, fg.Bounds().Min, draw.Over)

	return e.ToBytes(bg, options.Format, options.Quality)
}

func positionForeground(bg image.Image, pos string) image.Rectangle {
	ratios := []int{100, 100, 100, 100}
	val := strings.Split(pos, ".")
	for i := range val {
		if i+1 > len(ratios) {
			break
		}
		ratios[i], _ = strconv.Atoi(val[i])
	}
	b := bg.Bounds()
	return image.Rectangle{
		image.Point{b.Dx() * ratios[0], b.Dy() * ratios[1]}.Div(100),
		image.Point{b.Dx() * ratios[2], b.Dy() * ratios[3]}.Div(100),
	}
}

func foregroundImage(rec image.Rectangle, c string) *image.RGBA {
	fg := image.NewRGBA(image.Rectangle{image.ZP, rec.Size()})
	if c == "" {
		return fg
	}

	col, err := colorful.Hex(fmt.Sprintf("#%s", c))
	if err != nil {
		return fg
	}

	draw.Draw(fg, fg.Bounds(), &image.Uniform{col}, fg.Bounds().Min, draw.Src)
	return fg
}

func drawForeground(fg *image.RGBA, images []image.Image, options *Options) *image.RGBA {
	n := len(images)
	if n == 0 {
		return fg
	}

	// resize images for foreground
	b := fg.Bounds()
	opts := &Options{Upscale: true}

	if b.Dx() > b.Dy() {
		opts.Width = b.Dx() / n
		opts.Height = b.Dy()
	} else {
		opts.Width = b.Dx()
		opts.Height = b.Dy() / n
	}

	for i := range images {
		images[i] = scale(images[i], opts, imaging.Fit)
	}

	if b.Dx() > b.Dy() {
		return foregroundHorizontal(fg, images, options)
	} else {
		return foregroundVertical(fg, images, options)
	}
}

func foregroundHorizontal(fg *image.RGBA, images []image.Image, options *Options) *image.RGBA {
	position := fg.Bounds().Min
	totalHeight := fg.Bounds().Dy()
	cellWidth := fg.Bounds().Dx() / len(images)
	for i := range images {
		bounds := images[i].Bounds()
		position.Y = (totalHeight - bounds.Dy()) / 2
		position.X = fg.Bounds().Min.X + i*cellWidth + (cellWidth-bounds.Dx())/2
		r := image.Rectangle{
			position,
			position.Add(fg.Bounds().Size()),
		}
		draw.Draw(fg, r, images[i], bounds.Min, draw.Over)
	}
	return fg
}

func foregroundVertical(fg *image.RGBA, images []image.Image, options *Options) *image.RGBA {
	position := fg.Bounds().Min
	cellHeight := fg.Bounds().Dy() / len(images)
	totalWidth := fg.Bounds().Dx()
	for i := range images {
		bounds := images[i].Bounds()
		position.Y = fg.Bounds().Min.Y + i*cellHeight + (cellHeight-bounds.Dy())/2
		position.X = fg.Bounds().Min.X + (totalWidth-bounds.Dx())/2
		r := image.Rectangle{
			position,
			position.Add(image.Point{bounds.Dx(), bounds.Dy()}),
		}
		draw.Draw(fg, r, images[i], bounds.Min, draw.Over)
	}
	return fg
}
<|endoftext|>