<commit_before>package debug_test

import (
	"net/http"

	"github.com/cloudfoundry-incubator/garden-linux/debug"
	"github.com/pivotal-golang/lager"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Debug", func() {
	It("reports an expvar debug metric on /debug path", func() {
		sink := lager.NewReconfigurableSink(lager.NewWriterSink(GinkgoWriter, lager.DEBUG), lager.DEBUG)
		_, err := debug.Run("127.0.0.1:5123", sink)
		Expect(err).ToNot(HaveOccurred())

		resp, err := http.Get("http://127.0.0.1:5123/debug/vars")
		Expect(err).ToNot(HaveOccurred())
		defer resp.Body.Close()
		Expect(resp.StatusCode).To(Equal(http.StatusOK))
	})
})
<commit_msg>Fix debug tests<commit_after>package debug_test

import (
	"io/ioutil"
	"net/http"
	"os"

	"github.com/cloudfoundry-incubator/garden-linux/debug"
	"github.com/pivotal-golang/lager"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Debug", func() {
	var (
		backingStorePath string
		depotPath        string
	)

	BeforeEach(func() {
		var err error

		backingStorePath, err = ioutil.TempDir("", "backing_stores")
		Expect(err).NotTo(HaveOccurred())

		depotPath, err = ioutil.TempDir("", "depotDirs")
		Expect(err).NotTo(HaveOccurred())
	})

	AfterEach(func() {
		Expect(os.RemoveAll(backingStorePath)).To(Succeed())
		Expect(os.RemoveAll(depotPath)).To(Succeed())
	})

	It("reports an expvar debug metric on /debug path", func() {
		sink := lager.NewReconfigurableSink(lager.NewWriterSink(GinkgoWriter, lager.DEBUG), lager.DEBUG)
		_, err := debug.Run("127.0.0.1:5123", sink, backingStorePath, depotPath)
		Expect(err).ToNot(HaveOccurred())

		resp, err := http.Get("http://127.0.0.1:5123/debug/vars")
		Expect(err).ToNot(HaveOccurred())
		defer resp.Body.Close()
		Expect(resp.StatusCode).To(Equal(http.StatusOK))
	})
})
<|endoftext|>


<commit_before>// 通用的websocket服务器
package network

import (
	"crypto/tls"
	"fmt"
	"net"
	"net/http"
	"sync"
	"time"

	"github.com/gfandada/gserver/logger"

	"github.com/gorilla/websocket"
)

type Config struct {
	ServerAddress string         // 服务地址
	MaxHeader     int            // header大小限制，byte
	MaxConnNum    int            // 最大连接数
	MaxMsgLen     int            // 单消息的最大长度
	MinMsgLen     int            // 单消息的最小长度
	ReadDeadline  int            // 读超时s
	WriteDeadline int            // 写超时s
	HttpTimeout   int            // http超时s
	PendingNum    int            // 异步队列上限：gateway->client
	CertFile      string         // for ssl
	KeyFile       string         // for ssl
	MsgParser     Imessage       // for message
	Parser        *MessageParser // for 报文
	Gate          Iagent         // 网关
	Rpm           int            // rpm流量上限：每分钟消息数client->gateway
	AsyncMQ       int            // 异步队列上限：gateway->client
	GateWayIds    uint16         // gateway内部路由的消息段[0,GateWayIds]
}

type WsServer struct {
	serverAddress  string
	maxHeader      int
	maxConnNum     int
	maxMsgLen      int
	minMsgLen      int
	pendingNum     int
	readTimeout    int
	writeTimeout   int
	httpTimeout    int
	certFile       string
	keyFile        string
	msgParser      Imessage
	handler        *wsHandler
	serverListener net.Listener
	gate           Iagent
}

type wsHandler struct {
	maxConnNum   int
	maxMsgLen    int
	minMsgLen    int
	pendingNum   int
	readTimeout  int
	writeTimeout int
	upgrader     websocket.Upgrader
	gate         Iagent
	conns        map[*websocket.Conn]struct{}
	mutexConns   sync.Mutex
	wgConns      sync.WaitGroup
	mutexWG      sync.WaitGroup
}

func StartWs(config *Config) *WsServer {
	server := new(WsServer)
	server.serverAddress = config.ServerAddress
	server.maxHeader = config.MaxHeader
	server.maxConnNum = config.MaxConnNum
	server.maxMsgLen = config.MaxMsgLen
	server.minMsgLen = config.MinMsgLen
	server.pendingNum = config.PendingNum
	server.readTimeout = config.ReadDeadline
	server.writeTimeout = config.WriteDeadline
	server.httpTimeout = config.HttpTimeout
	server.certFile = config.CertFile
	server.keyFile = config.KeyFile
	server.msgParser = config.MsgParser
	server.gate = config.Gate
	server.start()
	return server
}

func (server *WsServer) start() {
	listener := server.init()
	if listener == nil {
		logger.Error(fmt.Sprintf("http server start failed, %v"))
		return
	}
	go server.run(listener)
}

func (handler *wsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		logger.Error("Method not allowed, %s", r.Method)
		return
	}
	conn, err := handler.upgrader.Upgrade(w, r, nil)
	if err != nil {
		logger.Error("upgrade error, %v", err)
		return
	}
	conn.SetReadLimit(int64(handler.maxMsgLen + 8))
	defer func() {
		if r := recover(); r != nil {
			// TODO
			fmt.Println("ws agent error:", r)
		}
	}()
	handler.mutexConns.Lock()
	if len(handler.conns) >= handler.maxConnNum {
		handler.mutexConns.Unlock()
		conn.Close()
		return
	}
	handler.conns[conn] = struct{}{}
	handler.mutexConns.Unlock()
	handler.mutexWG.Add(1)
	defer handler.mutexWG.Done()
	handler.gate.NewIagent().Start(&WsConn{conn: conn})
}

func (server *WsServer) init() net.Listener {
	listener, err := net.Listen("tcp", server.serverAddress)
	if err != nil {
		logger.Error(fmt.Sprintf("net.Listen error: %v", err))
		return nil
	}
	if server.maxHeader <= 0 {
		server.maxHeader = 1024
		logger.Warning(fmt.Sprintf("server.maxHeader <= 0, defalut 1024"))
	}
	if server.maxConnNum <= 0 {
		server.maxConnNum = 1000
		logger.Warning(fmt.Sprintf("server.maxConnNum <= 0, defalut 1000"))
	}
	if server.pendingNum <= 0 {
		server.pendingNum = 100
		logger.Warning(fmt.Sprintf("server.pendingNum <= 0, defalut 100"))
	}
	if server.maxMsgLen <= 0 {
		server.maxMsgLen = 512
		logger.Warning(fmt.Sprintf("server.maxMsgLen <= 0, defalut 512"))
	}
	if server.minMsgLen < 0 {
		server.minMsgLen = 0
		logger.Warning(fmt.Sprintf("server.minMsgLen < 0, defalut 0"))
	}
	if server.httpTimeout <= 0 {
		server.httpTimeout = 10
		logger.Warning(fmt.Sprintf("server.httpTimeout <= 0, defalut 10s"))
	}
	if server.readTimeout <= 0 {
		server.readTimeout = 10
		logger.Warning(fmt.Sprintf("server.readTimeout <= 0, defalut 10s"))
	}
	if server.writeTimeout <= 0 {
		server.writeTimeout = 10
		logger.Warning(fmt.Sprintf("server.writeTimeout <= 0, defalut 10s"))
	}
	// for ssl
	if server.certFile != "" || server.keyFile != "" {
		config := &tls.Config{}
		config.NextProtos = []string{"http/1.1"}
		var err error
		config.Certificates = make([]tls.Certificate, 1)
		config.Certificates[0], err = tls.LoadX509KeyPair(server.certFile, server.keyFile)
		if err != nil {
			logger.Warning(fmt.Sprintf("wss error: %v", err))
		}
		listener = tls.NewListener(listener, config)
	}
	server.serverListener = listener
	server.handler = &wsHandler{
		maxConnNum:   server.maxConnNum,
		maxMsgLen:    server.maxMsgLen,
		minMsgLen:    server.minMsgLen,
		pendingNum:   server.pendingNum,
		readTimeout:  server.readTimeout,
		writeTimeout: server.writeTimeout,
		conns:        make(map[*websocket.Conn]struct{}, server.maxConnNum),
		upgrader: websocket.Upgrader{
			HandshakeTimeout: time.Duration(server.httpTimeout) * time.Second,
			CheckOrigin:      func(_ *http.Request) bool { return true },
		},
	}
	if server.msgParser == nil {
		logger.Error("server.msgParser is nil %v", server)
		return nil
	}
	server.handler.gate = server.gate
	return listener
}

func (server *WsServer) run(listener net.Listener) {
	httpServer := &http.Server{
		Addr:           server.serverAddress,
		Handler:        server.handler,
		ReadTimeout:    time.Duration(server.readTimeout) * time.Second,
		WriteTimeout:   time.Duration(server.writeTimeout) * time.Second,
		MaxHeaderBytes: server.maxHeader,
	}
	httpServer.Serve(listener)
}

func (server *WsServer) Close() {
	server.serverListener.Close()
	server.handler.mutexWG.Wait()
	server.handler.mutexConns.Lock()
	for conn := range server.handler.conns {
		conn.Close()
	}
	server.handler.conns = nil
	server.handler.mutexConns.Unlock()
	server.handler.wgConns.Wait()
}
<commit_msg>update Config<commit_after>// 通用的websocket服务器
package network

import (
	"crypto/tls"
	"fmt"
	"net"
	"net/http"
	"sync"
	"time"

	"github.com/gfandada/gserver/logger"

	"github.com/gorilla/websocket"
)

type Config struct {
	ServerAddress string         // 服务地址
	MaxConnNum    int            // 最大连接数
	MaxMsgLen     int            // client->gateway message上限
	MinMsgLen     int            // client->gateway message下限
	ReadDeadline  int            // gateway->client读超时
	WriteDeadline int            // gateway->client写超时
	MaxHeader     int            // header上限(for websocket)
	HttpTimeout   int            // http-get超时(for websocket)
	CertFile      string         // for ssl
	KeyFile       string         // for ssl
	MsgParser     Imessage       // for message
	Parser        *MessageParser // for 报文
	Gate          Iagent         // 网关
	PendingNum    int            // gateway->client异步ipc队列上限
	Rpm           int            // client->gateway流量上限/min
	AsyncMQ       int            // service->gateway异步ipc队列上限
	GateWayIds    uint16         // gateway本地路由id段(当前路由规则是简单的id分段规则)
}

type WsServer struct {
	serverAddress  string
	maxHeader      int
	maxConnNum     int
	maxMsgLen      int
	minMsgLen      int
	pendingNum     int
	readTimeout    int
	writeTimeout   int
	httpTimeout    int
	certFile       string
	keyFile        string
	msgParser      Imessage
	handler        *wsHandler
	serverListener net.Listener
	gate           Iagent
}

type wsHandler struct {
	maxConnNum   int
	maxMsgLen    int
	minMsgLen    int
	pendingNum   int
	readTimeout  int
	writeTimeout int
	upgrader     websocket.Upgrader
	gate         Iagent
	conns        map[*websocket.Conn]struct{}
	mutexConns   sync.Mutex
	wgConns      sync.WaitGroup
	mutexWG      sync.WaitGroup
}

func StartWs(config *Config) *WsServer {
	server := new(WsServer)
	server.serverAddress = config.ServerAddress
	server.maxHeader = config.MaxHeader
	server.maxConnNum = config.MaxConnNum
	server.maxMsgLen = config.MaxMsgLen
	server.minMsgLen = config.MinMsgLen
	server.pendingNum = config.PendingNum
	server.readTimeout = config.ReadDeadline
	server.writeTimeout = config.WriteDeadline
	server.httpTimeout = config.HttpTimeout
	server.certFile = config.CertFile
	server.keyFile = config.KeyFile
	server.msgParser = config.MsgParser
	server.gate = config.Gate
	server.start()
	return server
}

func (server *WsServer) start() {
	listener := server.init()
	if listener == nil {
		logger.Error(fmt.Sprintf("http server start failed, %v"))
		return
	}
	go server.run(listener)
}

func (handler *wsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		logger.Error("Method not allowed, %s", r.Method)
		return
	}
	conn, err := handler.upgrader.Upgrade(w, r, nil)
	if err != nil {
		logger.Error("upgrade error, %v", err)
		return
	}
	conn.SetReadLimit(int64(handler.maxMsgLen + 8))
	defer func() {
		if r := recover(); r != nil {
			// TODO
			fmt.Println("ws agent error:", r)
		}
	}()
	handler.mutexConns.Lock()
	if len(handler.conns) >= handler.maxConnNum {
		handler.mutexConns.Unlock()
		conn.Close()
		return
	}
	handler.conns[conn] = struct{}{}
	handler.mutexConns.Unlock()
	handler.mutexWG.Add(1)
	defer handler.mutexWG.Done()
	handler.gate.NewIagent().Start(&WsConn{conn: conn})
}

func (server *WsServer) init() net.Listener {
	listener, err := net.Listen("tcp", server.serverAddress)
	if err != nil {
		logger.Error(fmt.Sprintf("net.Listen error: %v", err))
		return nil
	}
	if server.maxHeader <= 0 {
		server.maxHeader = 1024
		logger.Warning(fmt.Sprintf("server.maxHeader <= 0, defalut 1024"))
	}
	if server.maxConnNum <= 0 {
		server.maxConnNum = 1000
		logger.Warning(fmt.Sprintf("server.maxConnNum <= 0, defalut 1000"))
	}
	if server.pendingNum <= 0 {
		server.pendingNum = 100
		logger.Warning(fmt.Sprintf("server.pendingNum <= 0, defalut 100"))
	}
	if server.maxMsgLen <= 0 {
		server.maxMsgLen = 512
		logger.Warning(fmt.Sprintf("server.maxMsgLen <= 0, defalut 512"))
	}
	if server.minMsgLen < 0 {
		server.minMsgLen = 0
		logger.Warning(fmt.Sprintf("server.minMsgLen < 0, defalut 0"))
	}
	if server.httpTimeout <= 0 {
		server.httpTimeout = 10
		logger.Warning(fmt.Sprintf("server.httpTimeout <= 0, defalut 10s"))
	}
	if server.readTimeout <= 0 {
		server.readTimeout = 10
		logger.Warning(fmt.Sprintf("server.readTimeout <= 0, defalut 10s"))
	}
	if server.writeTimeout <= 0 {
		server.writeTimeout = 10
		logger.Warning(fmt.Sprintf("server.writeTimeout <= 0, defalut 10s"))
	}
	// for ssl
	if server.certFile != "" || server.keyFile != "" {
		config := &tls.Config{}
		config.NextProtos = []string{"http/1.1"}
		var err error
		config.Certificates = make([]tls.Certificate, 1)
		config.Certificates[0], err = tls.LoadX509KeyPair(server.certFile, server.keyFile)
		if err != nil {
			logger.Warning(fmt.Sprintf("wss error: %v", err))
		}
		listener = tls.NewListener(listener, config)
	}
	server.serverListener = listener
	server.handler = &wsHandler{
		maxConnNum:   server.maxConnNum,
		maxMsgLen:    server.maxMsgLen,
		minMsgLen:    server.minMsgLen,
		pendingNum:   server.pendingNum,
		readTimeout:  server.readTimeout,
		writeTimeout: server.writeTimeout,
		conns:        make(map[*websocket.Conn]struct{}, server.maxConnNum),
		upgrader: websocket.Upgrader{
			HandshakeTimeout: time.Duration(server.httpTimeout) * time.Second,
			CheckOrigin:      func(_ *http.Request) bool { return true },
		},
	}
	if server.msgParser == nil {
		logger.Error("server.msgParser is nil %v", server)
		return nil
	}
	server.handler.gate = server.gate
	return listener
}

func (server *WsServer) run(listener net.Listener) {
	httpServer := &http.Server{
		Addr:           server.serverAddress,
		Handler:        server.handler,
		ReadTimeout:    time.Duration(server.readTimeout) * time.Second,
		WriteTimeout:   time.Duration(server.writeTimeout) * time.Second,
		MaxHeaderBytes: server.maxHeader,
	}
	httpServer.Serve(listener)
}

func (server *WsServer) Close() {
	server.serverListener.Close()
	server.handler.mutexWG.Wait()
	server.handler.mutexConns.Lock()
	for conn := range server.handler.conns {
		conn.Close()
	}
	server.handler.conns = nil
	server.handler.mutexConns.Unlock()
	server.handler.wgConns.Wait()
}
<|endoftext|>


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

package ogletest

import (
	"fmt"
	"reflect"
	"testing"
)

// RunTests runs the test suites registered with ogletest, communicating
// failures to the supplied testing.T object. This is the bridge between
// ogletest and the testing package (and gotest); you should ensure that it's
// called at least once by creating a gotest-compatible test function and
// calling it there.
//
// For example:
//
//     import (
//       "github.com/jacobsa/ogletest"
//       "testing"
//     )
//
//     func TestOgletest(t *testing.T) {
//       ogletest.RunTests(t)
//     }
//
func RunTests(t *testing.T) {
	for _, suite := range testSuites {
		val := reflect.ValueOf(suite)
		typ := val.Type()
		suiteName := typ.Elem().Name()

		fmt.Println("=========", suiteName)

		// Run the SetUpTestSuite method, if any.
		runMethodIfExists(val, "SetUpTestSuite")

		// Run each method.
		//
		// TODO(jacobsa): Recover from panics.
		// TODO(jacobsa): Pay attention to failures.
		// TODO(jacobsa): Confirm that unexported methods don't show up here.
		for i := 0; i < typ.NumMethod(); i++ {
			method := typ.Method(i)
			if isSpecialMethod(method.Name) {
				continue
			}

			fmt.Printf("==== %s.%s\n", suiteName, method.Name)

			// Create a receiver, and call it.
			rcvr := reflect.New(typ.Elem())
			runMethodIfExists(rcvr, "SetUp")
			runMethodIfExists(rcvr, method.Name)
			runMethodIfExists(rcvr, "TearDown")
		}

		// Run the TearDownTestSuite method, if any.
		runMethodIfExists(val, "TearDownTestSuite")
	}
}

func runMethodIfExists(v reflect.Value, name string) {
	method := v.MethodByName(name)
	if method.Kind() == reflect.Invalid {
		return
	}

	// TODO(jacobsa): Panic (or print error?) if method doesn't have the right
	// signature.
	method.Call([]reflect.Value{})
}

func isSpecialMethod(name string) bool {
	return (name == "SetUpTestSuite") ||
		(name == "TearDownTestSuite") ||
		(name == "SetUp") ||
		(name == "TearDown")
}
<commit_msg>Added checking of error states.<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ogletest

import (
	"fmt"
	"github.com/jacobsa/ogletest/internal"
	"reflect"
	"testing"
)

// RunTests runs the test suites registered with ogletest, communicating
// failures to the supplied testing.T object. This is the bridge between
// ogletest and the testing package (and gotest); you should ensure that it's
// called at least once by creating a gotest-compatible test function and
// calling it there.
//
// For example:
//
//     import (
//       "github.com/jacobsa/ogletest"
//       "testing"
//     )
//
//     func TestOgletest(t *testing.T) {
//       ogletest.RunTests(t)
//     }
//
func RunTests(t *testing.T) {
	for _, suite := range testSuites {
		val := reflect.ValueOf(suite)
		typ := val.Type()
		suiteName := typ.Elem().Name()

		fmt.Println("=========", suiteName)

		// Run the SetUpTestSuite method, if any.
		runMethodIfExists(val, "SetUpTestSuite")

		// Run each method.
		//
		// TODO(jacobsa): Recover from panics.
		// TODO(jacobsa): Pay attention to failures.
		// TODO(jacobsa): Confirm that unexported methods don't show up here.
		for i := 0; i < typ.NumMethod(); i++ {
			method := typ.Method(i)
			if isSpecialMethod(method.Name) {
				continue
			}

			fmt.Printf("==== %s.%s\n", suiteName, method.Name)

			// Set up a clean slate for this test.
			internal.CurrentTest = internal.NewTestState()

			// Create a receiver, and call it.
			rcvr := reflect.New(typ.Elem())
			runMethodIfExists(rcvr, "SetUp")
			runMethodIfExists(rcvr, method.Name)
			runMethodIfExists(rcvr, "TearDown")

			// Print any failures, and mark the test as having failed if there are any.
			for _, record := range internal.CurrentTest.FailureRecords {
				t.Fail()
				fmt.Printf(
					"%s:%d:\n%s\n%s",
					record.FileName,
					record.LineNumber,
					record.GeneratedError,
					record.UserError)
			}
		}

		// Run the TearDownTestSuite method, if any.
		runMethodIfExists(val, "TearDownTestSuite")
	}
}

func runMethodIfExists(v reflect.Value, name string) {
	method := v.MethodByName(name)
	if method.Kind() == reflect.Invalid {
		return
	}

	// TODO(jacobsa): Panic (or print error?) if method doesn't have the right
	// signature.
	method.Call([]reflect.Value{})
}

func isSpecialMethod(name string) bool {
	return (name == "SetUpTestSuite") ||
		(name == "TearDownTestSuite") ||
		(name == "SetUp") ||
		(name == "TearDown")
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package cli

import (
	"os"

	"github.com/spf13/cobra"
	"mynewt.apache.org/newt/newt/builder"
	"mynewt.apache.org/newt/newt/image"
	"mynewt.apache.org/newt/newt/project"
	"mynewt.apache.org/newt/util"
)

func runRunCmd(cmd *cobra.Command, args []string) {
	if err := project.Initialize(); err != nil {
		NewtUsage(cmd, err)
	}
	if len(args) < 1 {
		NewtUsage(cmd, util.NewNewtError("Must specify target"))
	}

	t := ResolveTarget(args[0])
	if t == nil {
		NewtUsage(cmd, util.NewNewtError("Invalid target name: "+args[0]))
	}

	b, err := builder.NewTargetBuilder(t)
	if err != nil {
		NewtUsage(nil, err)
	}

	err = b.Build()
	if err != nil {
		NewtUsage(nil, err)
	}

	/*
	 * Run create-image if version number is specified. If no version number,
	 * remove .img which would'be been created. This so that download script
	 * will barf if it needs an image for this type of target, instead of
	 * downloading an older version.
	 */
	var app_img *image.Image
	var loader_img *image.Image
	if len(args) > 1 {
		if b.Loader == nil {
			err, app_img = CreateImage(b.App, args[1], "", 0, nil)
			if err != nil {
				NewtUsage(cmd, err)
			}
		} else {
			err, loader_img = CreateImage(b.Loader, args[1], "", 0, nil)
			if err != nil {
				NewtUsage(cmd, err)
			}
			err, app_img = CreateImage(b.App, args[1], "", 0, loader_img)
			if err != nil {
				NewtUsage(cmd, err)
			}

		}
	} else {
		os.Remove(b.App.AppImgPath())
		os.Remove(b.Loader.AppImgPath())
	}

	build_id := image.CreateBuildId(app_img, loader_img)

	err = image.CreateManifest(b, app_img, loader_img, build_id)
	if err != nil {
		NewtUsage(cmd, err)
	}

	err = b.Load()
	if err != nil {
		NewtUsage(cmd, err)
	}
	err = b.Debug()
	if err != nil {
		NewtUsage(cmd, err)
	}
}

func AddRunCommands(cmd *cobra.Command) {
	runHelpText := "Same as running\n" +
		" - build <target>\n" +
		" - create-image <target> <version>\n" +
		" - load <target>\n" +
		" - debug <target>\n\n" +
		"Note if version number is omitted, create-image step is skipped\n"
	runHelpEx := "  newt run <target-name> [<version>]\n"

	runCmd := &cobra.Command{
		Use:     "run",
		Short:   "build/create-image/download/debug <target>",
		Long:    runHelpText,
		Example: runHelpEx,
		Run:     runRunCmd,
	}
	cmd.AddCommand(runCmd)
}
<commit_msg>MYNEWT-317<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package cli

import (
	"os"

	"github.com/spf13/cobra"
	"mynewt.apache.org/newt/newt/builder"
	"mynewt.apache.org/newt/newt/image"
	"mynewt.apache.org/newt/newt/project"
	"mynewt.apache.org/newt/util"
)

func runRunCmd(cmd *cobra.Command, args []string) {
	if err := project.Initialize(); err != nil {
		NewtUsage(cmd, err)
	}
	if len(args) < 1 {
		NewtUsage(cmd, util.NewNewtError("Must specify target"))
	}

	t := ResolveTarget(args[0])
	if t == nil {
		NewtUsage(cmd, util.NewNewtError("Invalid target name: "+args[0]))
	}

	b, err := builder.NewTargetBuilder(t)
	if err != nil {
		NewtUsage(nil, err)
	}

	err = b.Build()
	if err != nil {
		NewtUsage(nil, err)
	}

	/*
	 * Run create-image if version number is specified. If no version number,
	 * remove .img which would'be been created. This so that download script
	 * will barf if it needs an image for this type of target, instead of
	 * downloading an older version.
	 */
	var app_img *image.Image
	var loader_img *image.Image
	if len(args) > 1 {
		if b.Loader == nil {
			err, app_img = CreateImage(b.App, args[1], "", 0, nil)
			if err != nil {
				NewtUsage(cmd, err)
			}
		} else {
			err, loader_img = CreateImage(b.Loader, args[1], "", 0, nil)
			if err != nil {
				NewtUsage(cmd, err)
			}
			err, app_img = CreateImage(b.App, args[1], "", 0, loader_img)
			if err != nil {
				NewtUsage(cmd, err)
			}

		}
	} else {
		os.Remove(b.App.AppImgPath())

		if b.Loader != nil {
			os.Remove(b.Loader.AppImgPath())
		}
	}
	if app_img != nil {
		build_id := image.CreateBuildId(app_img, loader_img)

		err = image.CreateManifest(b, app_img, loader_img, build_id)
		if err != nil {
			NewtUsage(cmd, err)
		}
	}

	err = b.Load()
	if err != nil {
		NewtUsage(cmd, err)
	}
	err = b.Debug()
	if err != nil {
		NewtUsage(cmd, err)
	}
}

func AddRunCommands(cmd *cobra.Command) {
	runHelpText := "Same as running\n" +
		" - build <target>\n" +
		" - create-image <target> <version>\n" +
		" - load <target>\n" +
		" - debug <target>\n\n" +
		"Note if version number is omitted, create-image step is skipped\n"
	runHelpEx := "  newt run <target-name> [<version>]\n"

	runCmd := &cobra.Command{
		Use:     "run",
		Short:   "build/create-image/download/debug <target>",
		Long:    runHelpText,
		Example: runHelpEx,
		Run:     runRunCmd,
	}
	cmd.AddCommand(runCmd)
}
<|endoftext|>


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

package s3

import (
	"bytes"
	"crypto/md5"
	"encoding/base64"
	"fmt"
	"github.com/jacobsa/aws"
	"github.com/jacobsa/aws/s3/auth"
	"github.com/jacobsa/aws/s3/http"
	"github.com/jacobsa/aws/s3/time"
	"net/url"
	sys_time "time"
	"unicode/utf8"
)

// Bucket represents an S3 bucket, which is a collection of objects keyed on
// Unicode strings. The UTF-8 encoding of a key must be no more than 1024 bytes
// long.
//
// See here for more info:
//
//     http://goo.gl/Nd63t
//
type Bucket interface {
	// Retrieve data for the object with the given key.
	GetObject(key string) (data []byte, err error)

	// Store the supplied data with the given key, overwriting any previous
	// version. The object is created with the default ACL of "private".
	StoreObject(key string, data []byte) error
}

// OpenBucket returns a Bucket tied to a given name in whe given region. You
// must have previously created the bucket in the region, and the supplied
// access key must have access to it.
//
// To easily create a bucket, use the AWS Console:
//
//     http://aws.amazon.com/console/
//
func OpenBucket(name string, region Region, key aws.AccessKey) (Bucket, error) {
	// Create a connection to the given region's endpoint.
	endpoint := &url.URL{Scheme: "https", Host: string(region)}
	httpConn, err := http.NewConn(endpoint)
	if err != nil {
		return nil, fmt.Errorf("http.NewConn: %v", err)
	}

	// Create an appropriate request signer.
	signer, err := auth.NewSigner(&key)
	if err != nil {
		return nil, fmt.Errorf("auth.NewSigner: %v", err)
	}

	return openBucket(name, httpConn, signer, time.RealClock())
}

// A version of OpenBucket with the ability to inject dependencies, for
// testability.
func openBucket(
	name string,
	httpConn http.Conn,
	signer auth.Signer,
	clock time.Clock) (Bucket, error) {
	return &bucket{name, httpConn, signer, clock}, nil
}

type bucket struct {
	name     string
	httpConn http.Conn
	signer   auth.Signer
	clock    time.Clock
}

func (b *bucket) GetObject(key string) (data []byte, err error) {
	return nil, fmt.Errorf("TODO: Implement bucket.GetObject.")
}

func (b *bucket) StoreObject(key string, data []byte) error {
	// Validate the key.
	if len(key) > 1024 {
		return fmt.Errorf("Keys may be no longer than 1024 bytes.")
	}

	if !utf8.ValidString(key) {
		return fmt.Errorf("Keys must be valid UTF-8.")
	}

	// Build an appropriate HTTP request.
	//
	// Reference:
	//     http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPUT.html
	httpReq := &http.Request{
		Verb: "PUT",
		Path: fmt.Sprintf("/%s/%s", b.name, key),
		Body: data,
		Headers: map[string]string{
			"Date": b.clock.Now().UTC().Format(sys_time.RFC1123),
		},
	}

	// Add a Content-MD5 header, as advised in the Amazon docs.
	md5Hash := md5.New()
	if _, err := md5Hash.Write(data); err != nil {
		return fmt.Errorf("md5Hash.Write: %v", err)
	}

	base64Md5Buf := new(bytes.Buffer)
	base64Encoder := base64.NewEncoder(base64.StdEncoding, base64Md5Buf)
	if _, err := base64Encoder.Write(md5Hash.Sum(nil)); err != nil {
		return fmt.Errorf("base64Encoder.Write: %v", err)
	}

	base64Encoder.Close()
	httpReq.Headers["Content-MD5"] = base64Md5Buf.String()

	// Sign the request.
	if err := b.signer.Sign(httpReq); err != nil {
		return fmt.Errorf("Sign: %v", err)
	}

	// Send the request.
	httpResp, err := b.httpConn.SendRequest(httpReq)
	if err != nil {
		return fmt.Errorf("SendRequest: %v", err)
	}

	// Check the response.
	if httpResp.StatusCode != 200 {
		return fmt.Errorf("Error from server: %d %s", httpResp.StatusCode, httpResp.Body)
	}

	return nil
}
<commit_msg>Moved to helper function.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package s3

import (
	"bytes"
	"crypto/md5"
	"encoding/base64"
	"fmt"
	"github.com/jacobsa/aws"
	"github.com/jacobsa/aws/s3/auth"
	"github.com/jacobsa/aws/s3/http"
	"github.com/jacobsa/aws/s3/time"
	"net/url"
	sys_time "time"
	"unicode/utf8"
)

// Bucket represents an S3 bucket, which is a collection of objects keyed on
// Unicode strings. The UTF-8 encoding of a key must be no more than 1024 bytes
// long.
//
// See here for more info:
//
//     http://goo.gl/Nd63t
//
type Bucket interface {
	// Retrieve data for the object with the given key.
	GetObject(key string) (data []byte, err error)

	// Store the supplied data with the given key, overwriting any previous
	// version. The object is created with the default ACL of "private".
	StoreObject(key string, data []byte) error
}

// OpenBucket returns a Bucket tied to a given name in whe given region. You
// must have previously created the bucket in the region, and the supplied
// access key must have access to it.
//
// To easily create a bucket, use the AWS Console:
//
//     http://aws.amazon.com/console/
//
func OpenBucket(name string, region Region, key aws.AccessKey) (Bucket, error) {
	// Create a connection to the given region's endpoint.
	endpoint := &url.URL{Scheme: "https", Host: string(region)}
	httpConn, err := http.NewConn(endpoint)
	if err != nil {
		return nil, fmt.Errorf("http.NewConn: %v", err)
	}

	// Create an appropriate request signer.
	signer, err := auth.NewSigner(&key)
	if err != nil {
		return nil, fmt.Errorf("auth.NewSigner: %v", err)
	}

	return openBucket(name, httpConn, signer, time.RealClock())
}

// A version of OpenBucket with the ability to inject dependencies, for
// testability.
func openBucket(
	name string,
	httpConn http.Conn,
	signer auth.Signer,
	clock time.Clock) (Bucket, error) {
	return &bucket{name, httpConn, signer, clock}, nil
}

type bucket struct {
	name     string
	httpConn http.Conn
	signer   auth.Signer
	clock    time.Clock
}

func (b *bucket) GetObject(key string) (data []byte, err error) {
	return nil, fmt.Errorf("TODO: Implement bucket.GetObject.")
}

func (b *bucket) StoreObject(key string, data []byte) error {
	// Validate the key.
	if len(key) > 1024 {
		return fmt.Errorf("Keys may be no longer than 1024 bytes.")
	}

	if !utf8.ValidString(key) {
		return fmt.Errorf("Keys must be valid UTF-8.")
	}

	// Build an appropriate HTTP request.
	//
	// Reference:
	//     http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPUT.html
	httpReq := &http.Request{
		Verb: "PUT",
		Path: fmt.Sprintf("/%s/%s", b.name, key),
		Body: data,
		Headers: map[string]string{
			"Date": b.clock.Now().UTC().Format(sys_time.RFC1123),
		},
	}

	// Add a Content-MD5 header, as advised in the Amazon docs.
	if err := addMd5Header(httpReq, data); err != nil {
		return err
	}

	// Sign the request.
	if err := b.signer.Sign(httpReq); err != nil {
		return fmt.Errorf("Sign: %v", err)
	}

	// Send the request.
	httpResp, err := b.httpConn.SendRequest(httpReq)
	if err != nil {
		return fmt.Errorf("SendRequest: %v", err)
	}

	// Check the response.
	if httpResp.StatusCode != 200 {
		return fmt.Errorf("Error from server: %d %s", httpResp.StatusCode, httpResp.Body)
	}

	return nil
}

func addMd5Header(r *http.Request, body []byte) error {
	md5Hash := md5.New()
	if _, err := md5Hash.Write(body); err != nil {
		return fmt.Errorf("md5Hash.Write: %v", err)
	}

	base64Md5Buf := new(bytes.Buffer)
	base64Encoder := base64.NewEncoder(base64.StdEncoding, base64Md5Buf)
	if _, err := base64Encoder.Write(md5Hash.Sum(nil)); err != nil {
		return fmt.Errorf("base64Encoder.Write: %v", err)
	}

	base64Encoder.Close()
	r.Headers["Content-MD5"] = base64Md5Buf.String()

	return nil
}
<|endoftext|>


<commit_before>package lexer

import (
	"testing"

	"github.com/135yshr/t_zungo/token"
)

func TestNextToken(t *testing.T) {
	type args struct {
		input string
	}
	tests := []struct {
		name string
		args args
		want []token.Token
	}{
		{
			name: "=+(){},;を渡して解析できること",
			args: args{
				input: `=`,
			},
			want: []token.Token{
				{token.ASSIGN, "="},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			sut := New(tt.args.input)
			for i, tt := range tt.want {
				tok := sut.NextToken()
				if tok.Type != tt.Type {
					t.Fatalf("tests[%d] - token type wrong. expected=%q, got=%q",
						i, tt.Type, tok.Type)
				}
				if tok.Literal != tt.Literal {
					t.Fatalf("tests[%d] - token literal wrong. expected=%q, got=%q",
						i, tt.Literal, tok.Literal)
				}
			}
		})
	}
}
<commit_msg>:pencil2: test title<commit_after>package lexer

import (
	"testing"

	"github.com/135yshr/t_zungo/token"
)

func TestNextToken(t *testing.T) {
	type args struct {
		input string
	}
	tests := []struct {
		name string
		args args
		want []token.Token
	}{
		{
			name: "=を渡して解析できること",
			args: args{
				input: `=`,
			},
			want: []token.Token{
				{token.ASSIGN, "="},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			sut := New(tt.args.input)
			for i, tt := range tt.want {
				tok := sut.NextToken()
				if tok.Type != tt.Type {
					t.Fatalf("tests[%d] - token type wrong. expected=%q, got=%q",
						i, tt.Type, tok.Type)
				}
				if tok.Literal != tt.Literal {
					t.Fatalf("tests[%d] - token literal wrong. expected=%q, got=%q",
						i, tt.Literal, tok.Literal)
				}
			}
		})
	}
}
<|endoftext|>


<commit_before>package lexer_test

import (
	"fmt"
	"io/ioutil"
	"strings"
	"testing"

	"github.com/drewwells/sprite-sass/lexer"
)

func TestSassLexer(t *testing.T) {

	fvar, _ := ioutil.ReadFile("../test/var.scss")

	items, err := parse(string(fvar))
	if err != nil {
		t.Errorf("Error parsing string")
	}
	for _, item := range items {
		switch fmt.Sprintf("%s", item.Type) {
		case "variable":
			vname := fmt.Sprintf("%s", item)
			if !strings.HasPrefix(vname, "$") {
				t.Errorf("Invalid variable prefix")
			}
			if strings.Index(vname, ":") > -1 {
				t.Errorf("Invalid symbol in variable")
			}
		}

	}

}

// create a parser for the language.
func parse(input string) ([]lexer.Item, error) {
	lex := lexer.New(func(lex *lexer.Lexer) lexer.StateFn {
		return lex.Action()
	}, input)

	var status []lexer.Item
	for {
		item := lex.Next()
		err := item.Error()
		if err != nil {
			return nil, fmt.Errorf("Error: %v (pos %d)", err, item.Pos)
		}
		switch item.Type {
		case lexer.ItemEOF:
			return status, nil
		case lexer.CMD, lexer.SPRITE, lexer.TEXT, lexer.VAR, lexer.FILE:
			fallthrough
		case lexer.LPAREN, lexer.RPAREN,
			lexer.LBRACKET, lexer.RBRACKET:
			fallthrough
		case lexer.EXTRA:
			fallthrough
		case item.Type:
			status = append(status, *item)
		default:
			fmt.Printf("Default: %d %s\n", item.Pos, item)
		}
	}
}
<commit_msg>command and lol png file tests<commit_after>package lexer_test

import (
	"fmt"
	"io/ioutil"
	"strings"
	"testing"

	"github.com/drewwells/sprite-sass/lexer"
)

func TestSassLexer(t *testing.T) {

	fvar, _ := ioutil.ReadFile("../test/var.scss")

	items, err := parse(string(fvar))
	if err != nil {
		t.Errorf("Error parsing string")
	}
	for _, item := range items {
		v := fmt.Sprintf("%s", item)
		switch fmt.Sprintf("%s", item.Type) {
		case "variable":
			if !strings.HasPrefix(v, "$") {
				t.Errorf("Invalid variable prefix")
			}
			if strings.Index(v, ":") > -1 {
				t.Errorf("Invalid symbol in variable")
			}
		case "command":
			if !strings.HasPrefix(v, "sprite") {
				t.Errorf("Invalid command name: %s", v)
			}
		case "file":
			//File globbing is a vast and varied field
			// TODO: crib tests from http://golang.org/src/pkg/path/filepath/match_test.go
			if !strings.HasSuffix(v, "png") {
				t.Errorf("File safety test failed expected png$, was: %s", v)
			}
		default:
			fmt.Println(item.Type)
		}

	}

}

// create a parser for the language.
func parse(input string) ([]lexer.Item, error) {
	lex := lexer.New(func(lex *lexer.Lexer) lexer.StateFn {
		return lex.Action()
	}, input)

	var status []lexer.Item
	for {
		item := lex.Next()
		err := item.Error()
		if err != nil {
			return nil, fmt.Errorf("Error: %v (pos %d)", err, item.Pos)
		}
		switch item.Type {
		case lexer.ItemEOF:
			return status, nil
		case lexer.CMD, lexer.SPRITE, lexer.TEXT, lexer.VAR, lexer.FILE:
			fallthrough
		case lexer.LPAREN, lexer.RPAREN,
			lexer.LBRACKET, lexer.RBRACKET:
			fallthrough
		case lexer.EXTRA:
			fallthrough
		case item.Type:
			status = append(status, *item)
		default:
			fmt.Printf("Default: %d %s\n", item.Pos, item)
		}
	}
}
<|endoftext|>


<commit_before>package engine

import (
	"math"
)

type (
	CollisionType int

	// This will be renamed to Collision
	Collision interface {
		Type() CollisionType
		Start() WorldTime
		End() WorldTime
		OverlapAt(WorldTime) float64
	}

	PathCollision struct {
		CollisionType
		TimeSpan
		A, B PathAction
	}

	CellCollision struct {
		CollisionType
		TimeSpan
		Cell Cell
		Path PathAction
	}
)

// TODO Implement this as bitflags
const (
	CT_NONE CollisionType = iota
	CT_HEAD_TO_HEAD
	CT_FROM_SIDE
	CT_A_INTO_B
	CT_A_INTO_B_FROM_SIDE
	CT_SWAP
	CT_SAME_ORIG
	CT_SAME_ORIG_PERP
	CT_SAME_ORIG_DEST
	CT_CELL_DEST
	CT_CELL_ORIG
)

func (c CollisionType) String() string {
	switch c {
	case CT_NONE:
		return "none"
	case CT_HEAD_TO_HEAD:
		return "head to head"
	case CT_FROM_SIDE:
		return "from the side"
	case CT_A_INTO_B:
		return "A into B"
	case CT_A_INTO_B_FROM_SIDE:
		return "A into B from the side"
	case CT_SWAP:
		return "swap"
	case CT_SAME_ORIG:
		return "same origin inverse facing"
	case CT_SAME_ORIG_PERP:
		return "same origin perpendicular facing"
	case CT_SAME_ORIG_DEST:
		return "same origin and destination"
	case CT_CELL_DEST:
		return "cell destination"
	case CT_CELL_ORIG:
		return "cell origin"
	}
	return "unknown collision type"
}

func (A PathAction) CollidesWith(B interface{}) (c Collision) {
	switch b := B.(type) {
	case PathAction:
		return pathCollision(A, b)
	case Cell:
		return cellCollision(A, b)
	default:
	}
	panic("unknown collision attempt")
}

func pathCollision(a, b PathAction) (c PathCollision) {
	var start, end WorldTime
	c.A, c.B = a, b

	switch {
	case a.Orig == b.Orig && a.Dest == b.Dest:
		// A & B are moving out of the same Cell in the same direction
		c.CollisionType = CT_SAME_ORIG_DEST
		goto CT_SAME_ORIG_DEST_TIMESPAN

	case a.Orig == b.Orig:
		// A & B are moving out of the same Cell in different directions
		if a.Direction() == b.Direction().Reverse() {
			c.CollisionType = CT_SAME_ORIG
			goto CT_SAME_ORIG_TIMESPAN
		}
		// A & B are moving perpendicular to each other
		c.CollisionType = CT_SAME_ORIG_PERP
		goto CT_SAME_ORIG_PERP_TIMESPAN

	case a.Dest == b.Dest:
		// A & B are moving into the same Cell
		if a.Direction() == b.Direction().Reverse() {
			// Head to Head
			c.CollisionType = CT_HEAD_TO_HEAD
			goto CT_HEAD_TO_HEAD_TIMESPAN
		}
		// From the Side
		c.CollisionType = CT_FROM_SIDE
		goto CT_FROM_SIDE_TIMESPAN

	case a.Dest == b.Orig && b.Dest == a.Orig:
		// A and B are swapping positions
		c.CollisionType = CT_SWAP
		goto CT_SWAP_TIMESPAN

	case b.Dest == a.Orig:
		// Need to flip A and B
		a, b = b, a
		c.A, c.B = a, b
		fallthrough

	case a.Dest == b.Orig:
		// A is moving into the Cell B is leaving
		if a.Direction() == b.Direction() {
			if a.start >= b.start && a.end >= b.end {
				goto EXIT
			}
			c.CollisionType = CT_A_INTO_B
			goto CT_A_INTO_B_TIMESPAN

		} else {
			c.CollisionType = CT_A_INTO_B_FROM_SIDE
			goto CT_A_INTO_B_FROM_SIDE_TIMESPAN
		}
	default:
		goto EXIT
	}

CT_SAME_ORIG_DEST_TIMESPAN:
	if a.start < b.start {
		start = a.start
	} else {
		start = b.start
	}

	if a.end > b.end {
		end = a.end
	} else {
		end = b.end
	}

	c.TimeSpan = NewTimeSpan(start, end)
	goto EXIT

CT_SAME_ORIG_TIMESPAN:
	if a.start < b.start {
		start = a.start
	} else {
		start = b.start
	}

	if a.end == b.start {
		end = a.end
	} else if b.end == a.start {
		end = b.end
	} else {
		var at, as, bt, bs float64
		// Starts
		at, bt = float64(a.start), float64(b.start)
		// Speeds
		as, bs = float64(a.end-a.start), float64(b.end-b.start)

		end = WorldTime(math.Ceil((at*bs + bt*as + as*bs) / (bs + as)))

		// TODO Check if this floating point work around hack can be avoided or done differently
		if c.OverlapAt(end-1) == 0.0 {
			end -= 1
		}
	}

	c.TimeSpan = NewTimeSpan(start, end)
	goto EXIT

CT_SAME_ORIG_PERP_TIMESPAN:
	if a.start < b.start {
		start = a.start
	} else {
		start = b.start
	}

	if a.end < b.end {
		end = a.end
	} else {
		end = b.end
	}
	c.TimeSpan = NewTimeSpan(start, end)
	goto EXIT

CT_HEAD_TO_HEAD_TIMESPAN:
	// Start of collision
	if a.start == b.end {
		start = a.start
	} else if b.start == a.end {
		start = b.start
	} else {
		var at, as, bt, bs float64
		// Starts
		at, bt = float64(a.start), float64(b.start)
		// Speeds
		as, bs = float64(a.end-a.start), float64(b.end-b.start)

		start = WorldTime(math.Floor((at*bs + bt*as + as*bs) / (bs + as)))

		// TODO Check if this floating point work around hack can be avoided or done differently
		if c.OverlapAt(start+1) == 0.0 {
			start += 1
		}
	}

	// End of Collision
	if a.end >= b.end {
		end = a.end
	} else {
		end = b.end
	}

	c.TimeSpan = NewTimeSpan(start, end)
	goto EXIT

CT_FROM_SIDE_TIMESPAN:
	if a.start > b.start {
		start = a.start
	} else {
		start = b.start
	}

	if a.end > b.end {
		end = a.end
	} else {
		end = b.end
	}

	c.TimeSpan = NewTimeSpan(start, end)
	goto EXIT

CT_SWAP_TIMESPAN:
	// TODO this is a.TimeSpan.Add(b.TimeSpan)
	if a.start <= b.start {
		start = a.start
	} else {
		start = b.start
	}

	if a.end >= b.end {
		end = a.end
	} else {
		end = b.end
	}

	c.TimeSpan = NewTimeSpan(start, end)
	goto EXIT

CT_A_INTO_B_TIMESPAN:
	if a.start <= b.start {
		start = a.start
	} else {
		var as, ae, bs, be float64
		as, ae = float64(a.start), float64(a.end)
		bs, be = float64(b.start), float64(b.end)

		start = WorldTime(math.Floor(((as / (ae - as)) - (bs / (be - bs))) / ((1 / (ae - as)) - (1 / (be - bs)))))

		// TODO Check if this floating point work around hack can be avoided or done differently
		if c.OverlapAt(start+1) == 0.0 {
			start += 1
		}
	}
	c.TimeSpan = NewTimeSpan(start, b.end)
	goto EXIT

CT_A_INTO_B_FROM_SIDE_TIMESPAN:
	start = a.start
	end = b.end
	c.TimeSpan = NewTimeSpan(start, end)

EXIT:
	return
}

func cellCollision(p PathAction, c Cell) (cc CellCollision) {
	cc.Path, cc.Cell = p, c
	switch c {
	case p.Dest:
		cc.CollisionType = CT_CELL_DEST
		cc.TimeSpan = p.TimeSpan
	case p.Orig:
		cc.CollisionType = CT_CELL_ORIG
		cc.TimeSpan = p.TimeSpan
	}
	return
}

func (c PathCollision) Type() CollisionType { return c.CollisionType }
func (c PathCollision) Start() WorldTime    { return c.TimeSpan.start }
func (c PathCollision) End() WorldTime      { return c.TimeSpan.end }
func (c PathCollision) OverlapAt(t WorldTime) (overlap float64) {

	switch c.CollisionType {
	case CT_SAME_ORIG:
		p := [...]PartialCell{
			c.A.OrigPartial(t),
			c.B.OrigPartial(t),
		}

		overlap = p[0].Percentage + p[1].Percentage - 1.0
		if overlap < 0.0 {
			overlap = 0.0
		}

	case CT_SAME_ORIG_PERP:
		p := [...]PartialCell{
			c.A.OrigPartial(t),
			c.B.OrigPartial(t),
		}
		overlap = p[0].Percentage * p[1].Percentage

	case CT_HEAD_TO_HEAD:
		p := [...]PartialCell{
			c.A.DestPartial(t),
			c.B.DestPartial(t),
		}
		sum := p[0].Percentage + p[1].Percentage
		if sum > 1.0 {
			overlap = sum - 1.0
		}

	case CT_FROM_SIDE:
		p := [...]PartialCell{
			c.A.DestPartial(t),
			c.B.DestPartial(t),
		}
		overlap = p[0].Percentage * p[1].Percentage

	case CT_SWAP:
		p := [...]PartialCell{
			c.A.DestPartial(t),
			c.B.DestPartial(t),
		}
		overlap = p[0].Percentage + p[1].Percentage
		if overlap > 1.0 {
			p = [...]PartialCell{
				c.A.OrigPartial(t),
				c.B.OrigPartial(t),
			}
			overlap = p[0].Percentage + p[1].Percentage
		}

	case CT_A_INTO_B:
		p := [...]PartialCell{
			c.A.DestPartial(t),
			c.B.OrigPartial(t),
		}
		sum := p[0].Percentage + p[1].Percentage
		if sum > 1.0 {
			overlap = sum - 1.0
		}

	case CT_A_INTO_B_FROM_SIDE:
		p := [...]PartialCell{
			c.A.DestPartial(t),
			c.B.OrigPartial(t),
		}
		overlap = p[0].Percentage * p[1].Percentage
	}
	return
}

func (c CellCollision) Type() CollisionType { return c.CollisionType }
func (c CellCollision) Start() WorldTime    { return c.TimeSpan.start }
func (c CellCollision) End() WorldTime      { return c.TimeSpan.end }
func (c CellCollision) OverlapAt(t WorldTime) (overlap float64) {
	switch c.CollisionType {
	case CT_CELL_DEST:
		overlap = c.Path.DestPartial(t).Percentage
	case CT_CELL_ORIG:
		overlap = c.Path.OrigPartial(t).Percentage
	}
	return
}
<commit_msg>Removed irrelevant comment<commit_after>package engine

import (
	"math"
)

type (
	CollisionType int

	Collision interface {
		Type() CollisionType
		Start() WorldTime
		End() WorldTime
		OverlapAt(WorldTime) float64
	}

	PathCollision struct {
		CollisionType
		TimeSpan
		A, B PathAction
	}

	CellCollision struct {
		CollisionType
		TimeSpan
		Cell Cell
		Path PathAction
	}
)

// TODO Implement this as bitflags
const (
	CT_NONE CollisionType = iota
	CT_HEAD_TO_HEAD
	CT_FROM_SIDE
	CT_A_INTO_B
	CT_A_INTO_B_FROM_SIDE
	CT_SWAP
	CT_SAME_ORIG
	CT_SAME_ORIG_PERP
	CT_SAME_ORIG_DEST
	CT_CELL_DEST
	CT_CELL_ORIG
)

func (c CollisionType) String() string {
	switch c {
	case CT_NONE:
		return "none"
	case CT_HEAD_TO_HEAD:
		return "head to head"
	case CT_FROM_SIDE:
		return "from the side"
	case CT_A_INTO_B:
		return "A into B"
	case CT_A_INTO_B_FROM_SIDE:
		return "A into B from the side"
	case CT_SWAP:
		return "swap"
	case CT_SAME_ORIG:
		return "same origin inverse facing"
	case CT_SAME_ORIG_PERP:
		return "same origin perpendicular facing"
	case CT_SAME_ORIG_DEST:
		return "same origin and destination"
	case CT_CELL_DEST:
		return "cell destination"
	case CT_CELL_ORIG:
		return "cell origin"
	}
	return "unknown collision type"
}

func (A PathAction) CollidesWith(B interface{}) (c Collision) {
	switch b := B.(type) {
	case PathAction:
		return pathCollision(A, b)
	case Cell:
		return cellCollision(A, b)
	default:
	}
	panic("unknown collision attempt")
}

func pathCollision(a, b PathAction) (c PathCollision) {
	var start, end WorldTime
	c.A, c.B = a, b

	switch {
	case a.Orig == b.Orig && a.Dest == b.Dest:
		// A & B are moving out of the same Cell in the same direction
		c.CollisionType = CT_SAME_ORIG_DEST
		goto CT_SAME_ORIG_DEST_TIMESPAN

	case a.Orig == b.Orig:
		// A & B are moving out of the same Cell in different directions
		if a.Direction() == b.Direction().Reverse() {
			c.CollisionType = CT_SAME_ORIG
			goto CT_SAME_ORIG_TIMESPAN
		}
		// A & B are moving perpendicular to each other
		c.CollisionType = CT_SAME_ORIG_PERP
		goto CT_SAME_ORIG_PERP_TIMESPAN

	case a.Dest == b.Dest:
		// A & B are moving into the same Cell
		if a.Direction() == b.Direction().Reverse() {
			// Head to Head
			c.CollisionType = CT_HEAD_TO_HEAD
			goto CT_HEAD_TO_HEAD_TIMESPAN
		}
		// From the Side
		c.CollisionType = CT_FROM_SIDE
		goto CT_FROM_SIDE_TIMESPAN

	case a.Dest == b.Orig && b.Dest == a.Orig:
		// A and B are swapping positions
		c.CollisionType = CT_SWAP
		goto CT_SWAP_TIMESPAN

	case b.Dest == a.Orig:
		// Need to flip A and B
		a, b = b, a
		c.A, c.B = a, b
		fallthrough

	case a.Dest == b.Orig:
		// A is moving into the Cell B is leaving
		if a.Direction() == b.Direction() {
			if a.start >= b.start && a.end >= b.end {
				goto EXIT
			}
			c.CollisionType = CT_A_INTO_B
			goto CT_A_INTO_B_TIMESPAN

		} else {
			c.CollisionType = CT_A_INTO_B_FROM_SIDE
			goto CT_A_INTO_B_FROM_SIDE_TIMESPAN
		}
	default:
		goto EXIT
	}

CT_SAME_ORIG_DEST_TIMESPAN:
	if a.start < b.start {
		start = a.start
	} else {
		start = b.start
	}

	if a.end > b.end {
		end = a.end
	} else {
		end = b.end
	}

	c.TimeSpan = NewTimeSpan(start, end)
	goto EXIT

CT_SAME_ORIG_TIMESPAN:
	if a.start < b.start {
		start = a.start
	} else {
		start = b.start
	}

	if a.end == b.start {
		end = a.end
	} else if b.end == a.start {
		end = b.end
	} else {
		var at, as, bt, bs float64
		// Starts
		at, bt = float64(a.start), float64(b.start)
		// Speeds
		as, bs = float64(a.end-a.start), float64(b.end-b.start)

		end = WorldTime(math.Ceil((at*bs + bt*as + as*bs) / (bs + as)))

		// TODO Check if this floating point work around hack can be avoided or done differently
		if c.OverlapAt(end-1) == 0.0 {
			end -= 1
		}
	}

	c.TimeSpan = NewTimeSpan(start, end)
	goto EXIT

CT_SAME_ORIG_PERP_TIMESPAN:
	if a.start < b.start {
		start = a.start
	} else {
		start = b.start
	}

	if a.end < b.end {
		end = a.end
	} else {
		end = b.end
	}
	c.TimeSpan = NewTimeSpan(start, end)
	goto EXIT

CT_HEAD_TO_HEAD_TIMESPAN:
	// Start of collision
	if a.start == b.end {
		start = a.start
	} else if b.start == a.end {
		start = b.start
	} else {
		var at, as, bt, bs float64
		// Starts
		at, bt = float64(a.start), float64(b.start)
		// Speeds
		as, bs = float64(a.end-a.start), float64(b.end-b.start)

		start = WorldTime(math.Floor((at*bs + bt*as + as*bs) / (bs + as)))

		// TODO Check if this floating point work around hack can be avoided or done differently
		if c.OverlapAt(start+1) == 0.0 {
			start += 1
		}
	}

	// End of Collision
	if a.end >= b.end {
		end = a.end
	} else {
		end = b.end
	}

	c.TimeSpan = NewTimeSpan(start, end)
	goto EXIT

CT_FROM_SIDE_TIMESPAN:
	if a.start > b.start {
		start = a.start
	} else {
		start = b.start
	}

	if a.end > b.end {
		end = a.end
	} else {
		end = b.end
	}

	c.TimeSpan = NewTimeSpan(start, end)
	goto EXIT

CT_SWAP_TIMESPAN:
	// TODO this is a.TimeSpan.Add(b.TimeSpan)
	if a.start <= b.start {
		start = a.start
	} else {
		start = b.start
	}

	if a.end >= b.end {
		end = a.end
	} else {
		end = b.end
	}

	c.TimeSpan = NewTimeSpan(start, end)
	goto EXIT

CT_A_INTO_B_TIMESPAN:
	if a.start <= b.start {
		start = a.start
	} else {
		var as, ae, bs, be float64
		as, ae = float64(a.start), float64(a.end)
		bs, be = float64(b.start), float64(b.end)

		start = WorldTime(math.Floor(((as / (ae - as)) - (bs / (be - bs))) / ((1 / (ae - as)) - (1 / (be - bs)))))

		// TODO Check if this floating point work around hack can be avoided or done differently
		if c.OverlapAt(start+1) == 0.0 {
			start += 1
		}
	}
	c.TimeSpan = NewTimeSpan(start, b.end)
	goto EXIT

CT_A_INTO_B_FROM_SIDE_TIMESPAN:
	start = a.start
	end = b.end
	c.TimeSpan = NewTimeSpan(start, end)

EXIT:
	return
}

func cellCollision(p PathAction, c Cell) (cc CellCollision) {
	cc.Path, cc.Cell = p, c
	switch c {
	case p.Dest:
		cc.CollisionType = CT_CELL_DEST
		cc.TimeSpan = p.TimeSpan
	case p.Orig:
		cc.CollisionType = CT_CELL_ORIG
		cc.TimeSpan = p.TimeSpan
	}
	return
}

func (c PathCollision) Type() CollisionType { return c.CollisionType }
func (c PathCollision) Start() WorldTime    { return c.TimeSpan.start }
func (c PathCollision) End() WorldTime      { return c.TimeSpan.end }
func (c PathCollision) OverlapAt(t WorldTime) (overlap float64) {

	switch c.CollisionType {
	case CT_SAME_ORIG:
		p := [...]PartialCell{
			c.A.OrigPartial(t),
			c.B.OrigPartial(t),
		}

		overlap = p[0].Percentage + p[1].Percentage - 1.0
		if overlap < 0.0 {
			overlap = 0.0
		}

	case CT_SAME_ORIG_PERP:
		p := [...]PartialCell{
			c.A.OrigPartial(t),
			c.B.OrigPartial(t),
		}
		overlap = p[0].Percentage * p[1].Percentage

	case CT_HEAD_TO_HEAD:
		p := [...]PartialCell{
			c.A.DestPartial(t),
			c.B.DestPartial(t),
		}
		sum := p[0].Percentage + p[1].Percentage
		if sum > 1.0 {
			overlap = sum - 1.0
		}

	case CT_FROM_SIDE:
		p := [...]PartialCell{
			c.A.DestPartial(t),
			c.B.DestPartial(t),
		}
		overlap = p[0].Percentage * p[1].Percentage

	case CT_SWAP:
		p := [...]PartialCell{
			c.A.DestPartial(t),
			c.B.DestPartial(t),
		}
		overlap = p[0].Percentage + p[1].Percentage
		if overlap > 1.0 {
			p = [...]PartialCell{
				c.A.OrigPartial(t),
				c.B.OrigPartial(t),
			}
			overlap = p[0].Percentage + p[1].Percentage
		}

	case CT_A_INTO_B:
		p := [...]PartialCell{
			c.A.DestPartial(t),
			c.B.OrigPartial(t),
		}
		sum := p[0].Percentage + p[1].Percentage
		if sum > 1.0 {
			overlap = sum - 1.0
		}

	case CT_A_INTO_B_FROM_SIDE:
		p := [...]PartialCell{
			c.A.DestPartial(t),
			c.B.OrigPartial(t),
		}
		overlap = p[0].Percentage * p[1].Percentage
	}
	return
}

func (c CellCollision) Type() CollisionType { return c.CollisionType }
func (c CellCollision) Start() WorldTime    { return c.TimeSpan.start }
func (c CellCollision) End() WorldTime      { return c.TimeSpan.end }
func (c CellCollision) OverlapAt(t WorldTime) (overlap float64) {
	switch c.CollisionType {
	case CT_CELL_DEST:
		overlap = c.Path.DestPartial(t).Percentage
	case CT_CELL_ORIG:
		overlap = c.Path.OrigPartial(t).Percentage
	}
	return
}
<|endoftext|>


<commit_before>package expr

import (
	"strconv"
	"testing"

	"github.com/grafana/metrictank/api/models"
	"github.com/grafana/metrictank/test"
	"github.com/raintank/schema"
)

func getNewSubstr(in []models.Series, start, stop int64) *FuncSubstr {
	f := NewSubstr()
	s := f.(*FuncSubstr)
	s.in = NewMock(in)
	s.start = start
	s.stop = stop
	return s
}

func TestSubstrNoArgs(t *testing.T) {
	f := getNewSubstr(
		[]models.Series{
			{
				Interval:   10,
				QueryPatt:  "a.b.c.d.*",
				Target:     "a.b.c.d.e",
				Datapoints: getCopy(a),
			},
		},
		0,
		0,
	)
	out := []models.Series{
		{
			Interval:   10,
			QueryPatt:  "a.b.c.d.*",
			Target:     "a.b.c.d.e",
			Datapoints: getCopy(a),
		},
	}

	got, err := f.Exec(make(map[Req][]models.Series))
	if err := equalOutput(out, got, nil, err); err != nil {
		t.Fatal(err)
	}
}

func TestSubstrStart(t *testing.T) {
	f := getNewSubstr(
		[]models.Series{
			{
				Interval:   10,
				QueryPatt:  "a.b.c.d.*",
				Target:     "a.b.c.d.e",
				Datapoints: getCopy(a),
			},
		},
		2,
		0,
	)
	out := []models.Series{
		{
			Interval:   10,
			QueryPatt:  "a.b.c.d.*",
			Target:     "c.d.e",
			Datapoints: getCopy(a),
		},
	}

	got, err := f.Exec(make(map[Req][]models.Series))
	if err := equalOutput(out, got, nil, err); err != nil {
		t.Fatal(err)
	}
}

func TestSubstrStartStop(t *testing.T) {
	f := getNewSubstr(
		[]models.Series{
			{
				Interval:   10,
				QueryPatt:  "a.b.c.d.*",
				Target:     "a.b.c.d.e",
				Datapoints: getCopy(a),
			},
		},
		2,
		4,
	)
	out := []models.Series{
		{
			Interval:   10,
			QueryPatt:  "a.b.c.d.*",
			Target:     "c.d",
			Datapoints: getCopy(a),
		},
	}

	got, err := f.Exec(make(map[Req][]models.Series))
	if err := equalOutput(out, got, nil, err); err != nil {
		t.Fatal(err)
	}
}

func TestSubstrWithFuncs(t *testing.T) {
	f := getNewSubstr(
		[]models.Series{
			{
				Interval:   10,
				QueryPatt:  "foo(bar(a.b.c.d.*,foo))",
				Target:     "foo(bar(a.b.c.d.e,foo))",
				Datapoints: getCopy(a),
			},
		},
		2,
		4,
	)
	out := []models.Series{
		{
			Interval:   10,
			QueryPatt:  "foo(bar(a.b.c.d.*,foo))",
			Target:     "c.d",
			Datapoints: getCopy(a),
		},
	}

	got, err := f.Exec(make(map[Req][]models.Series))
	if err := equalOutput(out, got, nil, err); err != nil {
		t.Fatal(err)
	}
}

func BenchmarkSubstr10k_1NoNulls(b *testing.B) {
	benchmarkSubstr(b, 1, test.RandFloats10k, test.RandFloats10k)
}
func BenchmarkSubstr10k_10NoNulls(b *testing.B) {
	benchmarkSubstr(b, 10, test.RandFloats10k, test.RandFloats10k)
}
func BenchmarkSubstr10k_100NoNulls(b *testing.B) {
	benchmarkSubstr(b, 100, test.RandFloats10k, test.RandFloats10k)
}
func BenchmarkSubstr10k_1000NoNulls(b *testing.B) {
	benchmarkSubstr(b, 1000, test.RandFloats10k, test.RandFloats10k)
}
func BenchmarkSubstr10k_1SomeSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 1, test.RandFloats10k, test.RandFloatsWithNulls10k)
}
func BenchmarkSubstr10k_10SomeSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 10, test.RandFloats10k, test.RandFloatsWithNulls10k)
}
func BenchmarkSubstr10k_100SomeSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 100, test.RandFloats10k, test.RandFloatsWithNulls10k)
}
func BenchmarkSubstr10k_1000SomeSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 1000, test.RandFloats10k, test.RandFloatsWithNulls10k)
}
func BenchmarkSubstr10k_1AllSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 1, test.RandFloatsWithNulls10k, test.RandFloatsWithNulls10k)
}
func BenchmarkSubstr10k_10AllSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 10, test.RandFloatsWithNulls10k, test.RandFloatsWithNulls10k)
}
func BenchmarkSubstr10k_100AllSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 100, test.RandFloatsWithNulls10k, test.RandFloatsWithNulls10k)
}
func BenchmarkSubstr10k_1000AllSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 1000, test.RandFloatsWithNulls10k, test.RandFloatsWithNulls10k)
}
func benchmarkSubstr(b *testing.B, numSeries int, fn0, fn1 func() []schema.Point) {
	var input []models.Series
	for i := 0; i < numSeries; i++ {
		series := models.Series{
			QueryPatt: strconv.Itoa(i),
		}
		if i%2 == 0 {
			series.Datapoints = fn0()
		} else {
			series.Datapoints = fn1()
		}
		input = append(input, series)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		f := NewSubstr()
		f.(*FuncSubstr).in = NewMock(input)
		got, err := f.Exec(make(map[Req][]models.Series))
		if err != nil {
			b.Fatalf("%s", err)
		}
		results = got
	}
}
<commit_msg>use new testing paradigm<commit_after>package expr

import (
	"strconv"
	"testing"

	"github.com/grafana/metrictank/api/models"
	"github.com/grafana/metrictank/test"
	"github.com/raintank/schema"
)

func TestSubstrNoArgs(t *testing.T) {
	input := []models.Series{
		{
			Interval:   10,
			QueryFrom:  10,
			QueryTo:    61,
			QueryPatt:  "a.b.c.d.*",
			Target:     "a.b.c.d.e",
			Datapoints: getCopy(a),
		},
	}
	exp := []models.Series{
		{
			Interval:   10,
			QueryFrom:  10,
			QueryTo:    61,
			QueryPatt:  "a.b.c.d.*",
			Target:     "a.b.c.d.e",
			Datapoints: getCopy(a),
		},
	}
	testSubstr("TestSubstrNoArgs", input, exp, 0, 0, t)
}

func TestSubstrStart(t *testing.T) {
	input := []models.Series{
		{
			Interval:   10,
			QueryFrom:  10,
			QueryTo:    61,
			QueryPatt:  "a.b.c.d.*",
			Target:     "a.b.c.d.e",
			Datapoints: getCopy(a),
		},
	}
	exp := []models.Series{
		{
			Interval:   10,
			QueryFrom:  10,
			QueryTo:    61,
			QueryPatt:  "a.b.c.d.*",
			Target:     "c.d.e",
			Datapoints: getCopy(a),
		},
	}
	testSubstr("TestSubstrStart", input, exp, 2, 0, t)
}

func TestSubstrStartStop(t *testing.T) {
	input := []models.Series{
		{
			Interval:   10,
			QueryFrom:  10,
			QueryTo:    61,
			QueryPatt:  "a.b.c.d.*",
			Target:     "a.b.c.d.e",
			Datapoints: getCopy(a),
		},
	}
	exp := []models.Series{
		{
			Interval:   10,
			QueryFrom:  10,
			QueryTo:    61,
			QueryPatt:  "a.b.c.d.*",
			Target:     "c.d",
			Datapoints: getCopy(a),
		},
	}
	testSubstr("TestSubstrStartStop", input, exp, 2, 4, t)
}

func TestSubstrWithFuncs(t *testing.T) {
	input := []models.Series{
		{
			Interval:   10,
			QueryFrom:  10,
			QueryTo:    61,
			QueryPatt:  "foo(bar(a.b.c.d.*,foo))",
			Target:     "foo(bar(a.b.c.d.e,foo))",
			Datapoints: getCopy(a),
		},
	}
	exp := []models.Series{
		{
			Interval:   10,
			QueryFrom:  10,
			QueryTo:    61,
			QueryPatt:  "foo(bar(a.b.c.d.*,foo))",
			Target:     "c.d",
			Datapoints: getCopy(a),
		},
	}
	testSubstr("TestSubstrWithFuncs", input, exp, 2, 4, t)
}

func testSubstr(name string, in []models.Series, out []models.Series, start, stop int64, t *testing.T) {
	f := NewSubstr()
	substr := f.(*FuncSubstr)
	substr.in = NewMock(in)
	substr.start = start
	substr.stop = stop

	inputCopy := models.SeriesCopy(in) // to later verify that it is unchanged

	dataMap := initDataMap(in)

	got, err := f.Exec(dataMap)
	if err := equalOutput(out, got, nil, err); err != nil {
		t.Fatalf("Case %s: %s", name, err)
	}

	t.Run("DidNotModifyInput", func(t *testing.T) {
		if err := equalOutput(inputCopy, in, nil, nil); err != nil {
			t.Fatalf("Case %s: Input was modified, err = %s", name, err)
		}
	})

	t.Run("DoesNotDoubleReturnPoints", func(t *testing.T) {
		if err := dataMap.CheckForOverlappingPoints(); err != nil {
			t.Fatalf("Case %s: Point slices in datamap overlap, err = %s", name, err)
		}
	})
	t.Run("OutputIsCanonical", func(t *testing.T) {
		for i, s := range got {
			if !s.IsCanonical() {
				t.Fatalf("Case %s: output series %d is not canonical: %v", name, i, s)
			}
		}
	})
}

func BenchmarkSubstr10k_1NoNulls(b *testing.B) {
	benchmarkSubstr(b, 1, test.RandFloats10k, test.RandFloats10k)
}
func BenchmarkSubstr10k_10NoNulls(b *testing.B) {
	benchmarkSubstr(b, 10, test.RandFloats10k, test.RandFloats10k)
}
func BenchmarkSubstr10k_100NoNulls(b *testing.B) {
	benchmarkSubstr(b, 100, test.RandFloats10k, test.RandFloats10k)
}
func BenchmarkSubstr10k_1000NoNulls(b *testing.B) {
	benchmarkSubstr(b, 1000, test.RandFloats10k, test.RandFloats10k)
}
func BenchmarkSubstr10k_1SomeSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 1, test.RandFloats10k, test.RandFloatsWithNulls10k)
}
func BenchmarkSubstr10k_10SomeSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 10, test.RandFloats10k, test.RandFloatsWithNulls10k)
}
func BenchmarkSubstr10k_100SomeSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 100, test.RandFloats10k, test.RandFloatsWithNulls10k)
}
func BenchmarkSubstr10k_1000SomeSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 1000, test.RandFloats10k, test.RandFloatsWithNulls10k)
}
func BenchmarkSubstr10k_1AllSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 1, test.RandFloatsWithNulls10k, test.RandFloatsWithNulls10k)
}
func BenchmarkSubstr10k_10AllSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 10, test.RandFloatsWithNulls10k, test.RandFloatsWithNulls10k)
}
func BenchmarkSubstr10k_100AllSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 100, test.RandFloatsWithNulls10k, test.RandFloatsWithNulls10k)
}
func BenchmarkSubstr10k_1000AllSeriesHalfNulls(b *testing.B) {
	benchmarkSubstr(b, 1000, test.RandFloatsWithNulls10k, test.RandFloatsWithNulls10k)
}
func benchmarkSubstr(b *testing.B, numSeries int, fn0, fn1 func() []schema.Point) {
	var input []models.Series
	for i := 0; i < numSeries; i++ {
		series := models.Series{
			QueryPatt: strconv.Itoa(i),
		}
		if i%2 == 0 {
			series.Datapoints = fn0()
		} else {
			series.Datapoints = fn1()
		}
		input = append(input, series)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		f := NewSubstr()
		f.(*FuncSubstr).in = NewMock(input)
		got, err := f.Exec(make(map[Req][]models.Series))
		if err != nil {
			b.Fatalf("%s", err)
		}
		results = got
	}
}
<|endoftext|>


<commit_before>package grandcentral

import (
	"fmt"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
	datastore "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	dhtpb "github.com/jbenet/go-ipfs/routing/dht/pb"
	proxy "github.com/jbenet/go-ipfs/routing/grandcentral/proxy"
	util "github.com/jbenet/go-ipfs/util"
	errors "github.com/jbenet/go-ipfs/util/debugerror"
)

// Server handles routing queries using a database backend
type Server struct {
	local           peer.ID
	routingBackend  datastore.ThreadSafeDatastore
	peerstore       peer.Peerstore
	*proxy.Loopback // so server can be injected into client
}

// NewServer creates a new GrandCentral routing Server
func NewServer(ds datastore.ThreadSafeDatastore, ps peer.Peerstore, local peer.ID) (*Server, error) {
	s := &Server{local, ds, ps, nil}
	s.Loopback = &proxy.Loopback{
		Handler: s,
		Local:   local,
	}
	return s, nil
}

// HandleLocalRequest implements the proxy.RequestHandler interface. This is
// where requests are received from the outside world.
func (s *Server) HandleRequest(ctx context.Context, p peer.ID, req *dhtpb.Message) *dhtpb.Message {
	_, response := s.handleMessage(ctx, p, req) // ignore response peer. it's local.
	return response
}

// TODO extract backend. backend can be implemented with whatever database we desire
func (s *Server) handleMessage(
	ctx context.Context, p peer.ID, req *dhtpb.Message) (peer.ID, *dhtpb.Message) {

	log.EventBegin(ctx, "routingMessageReceived", req, p, s.local).Done() // TODO may need to differentiate between local and remote

	var response = dhtpb.NewMessage(req.GetType(), req.GetKey(), req.GetClusterLevel())
	switch req.GetType() {

	case dhtpb.Message_GET_VALUE:
		rawRecord, err := getRoutingRecord(s.routingBackend, util.Key(req.GetKey()))
		if err != nil {
			return "", nil
		}
		response.Record = rawRecord
		// TODO before merging: if we know any providers for the requested value, return those.
		return p, response

	case dhtpb.Message_PUT_VALUE:
		// TODO before merging: verifyRecord(req.GetRecord())
		putRoutingRecord(s.routingBackend, util.Key(req.GetKey()), req.GetRecord())
		return p, req // TODO before merging: verify that we should return record

	case dhtpb.Message_FIND_NODE:
		p := s.peerstore.PeerInfo(peer.ID(req.GetKey()))
		pri := []dhtpb.PeerRoutingInfo{
			dhtpb.PeerRoutingInfo{
				PeerInfo: p,
				// Connectedness: TODO
			},
		}
		response.CloserPeers = dhtpb.PeerRoutingInfosToPBPeers(pri)
		return p.ID, response

	case dhtpb.Message_ADD_PROVIDER:
		// FIXME(btc): do we want to store these locally? I think the
		// storeProvidersToPeerstore behavior is straight from the DHT message
		// handler.
		storeProvidersToPeerstore(s.peerstore, p, req.GetProviderPeers())

		if err := putRoutingProviders(s.routingBackend, util.Key(req.GetKey()), req.GetProviderPeers()); err != nil {
			return "", nil
		}
		return "", nil

	case dhtpb.Message_GET_PROVIDERS:
		providers, err := getRoutingProviders(s.local, s.routingBackend, util.Key(req.GetKey()))
		if err != nil {
			return "", nil
		}
		response.ProviderPeers = providers
		return p, response

	case dhtpb.Message_PING:
		return p, req
	default:
	}
	return "", nil
}

var _ proxy.RequestHandler = &Server{}
var _ proxy.Proxy = &Server{}

func getRoutingRecord(ds datastore.Datastore, k util.Key) (*dhtpb.Record, error) {
	dskey := k.DsKey()
	val, err := ds.Get(dskey)
	if err != nil {
		return nil, errors.Wrap(err)
	}
	recordBytes, ok := val.([]byte)
	if !ok {
		return nil, fmt.Errorf("datastore had non byte-slice value for %v", dskey)
	}
	var record dhtpb.Record
	if err := proto.Unmarshal(recordBytes, &record); err != nil {
		return nil, errors.New("failed to unmarshal dht record from datastore")
	}
	return &record, nil
}

func putRoutingRecord(ds datastore.Datastore, k util.Key, value *dhtpb.Record) error {
	data, err := proto.Marshal(value)
	if err != nil {
		return err
	}
	dskey := k.DsKey()
	// TODO namespace
	if err := ds.Put(dskey, data); err != nil {
		return err
	}
	return nil
}

func putRoutingProviders(ds datastore.Datastore, k util.Key, providers []*dhtpb.Message_Peer) error {
	log.Event(context.Background(), "putRoutingProviders", &k)
	pkey := datastore.KeyWithNamespaces([]string{"routing", "providers", k.String()})
	if v, err := ds.Get(pkey); err == nil {
		if msg, ok := v.([]byte); ok {
			var protomsg dhtpb.Message
			if err := proto.Unmarshal(msg, &protomsg); err != nil {
				log.Error("failed to unmarshal routing provider record. programmer error")
			} else {
				providers = append(providers, protomsg.ProviderPeers...)
			}
		}
	}
	var protomsg dhtpb.Message
	protomsg.ProviderPeers = providers
	data, err := proto.Marshal(&protomsg)
	if err != nil {
		return err
	}
	return ds.Put(pkey, data)
}

func storeProvidersToPeerstore(ps peer.Peerstore, p peer.ID, providers []*dhtpb.Message_Peer) {
	for _, provider := range providers {
		providerID := peer.ID(provider.GetId())
		if providerID != p {
			log.Errorf("provider message came from third-party %s", p)
			continue
		}
		for _, maddr := range provider.Addresses() {
			// as a router, we want to store addresses for peers who have provided
			ps.AddAddr(p, maddr, peer.AddressTTL)
		}
	}
}

func getRoutingProviders(local peer.ID, ds datastore.Datastore, k util.Key) ([]*dhtpb.Message_Peer, error) {
	e := log.EventBegin(context.Background(), "getProviders", &k)
	defer e.Done()
	var providers []*dhtpb.Message_Peer
	pkey := datastore.KeyWithNamespaces([]string{"routing", "providers", k.String()}) // TODO key fmt
	if v, err := ds.Get(pkey); err == nil {
		if data, ok := v.([]byte); ok {
			var msg dhtpb.Message
			if err := proto.Unmarshal(data, &msg); err != nil {
				return nil, err
			}
			providers = append(providers, msg.GetProviderPeers()...)
		}
	}
	return providers, nil
}
<commit_msg>misc(gcr/s) rm unused param<commit_after>package grandcentral

import (
	"fmt"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
	datastore "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	dhtpb "github.com/jbenet/go-ipfs/routing/dht/pb"
	proxy "github.com/jbenet/go-ipfs/routing/grandcentral/proxy"
	util "github.com/jbenet/go-ipfs/util"
	errors "github.com/jbenet/go-ipfs/util/debugerror"
)

// Server handles routing queries using a database backend
type Server struct {
	local           peer.ID
	routingBackend  datastore.ThreadSafeDatastore
	peerstore       peer.Peerstore
	*proxy.Loopback // so server can be injected into client
}

// NewServer creates a new GrandCentral routing Server
func NewServer(ds datastore.ThreadSafeDatastore, ps peer.Peerstore, local peer.ID) (*Server, error) {
	s := &Server{local, ds, ps, nil}
	s.Loopback = &proxy.Loopback{
		Handler: s,
		Local:   local,
	}
	return s, nil
}

// HandleLocalRequest implements the proxy.RequestHandler interface. This is
// where requests are received from the outside world.
func (s *Server) HandleRequest(ctx context.Context, p peer.ID, req *dhtpb.Message) *dhtpb.Message {
	_, response := s.handleMessage(ctx, p, req) // ignore response peer. it's local.
	return response
}

// TODO extract backend. backend can be implemented with whatever database we desire
func (s *Server) handleMessage(
	ctx context.Context, p peer.ID, req *dhtpb.Message) (peer.ID, *dhtpb.Message) {

	log.EventBegin(ctx, "routingMessageReceived", req, p, s.local).Done() // TODO may need to differentiate between local and remote

	var response = dhtpb.NewMessage(req.GetType(), req.GetKey(), req.GetClusterLevel())
	switch req.GetType() {

	case dhtpb.Message_GET_VALUE:
		rawRecord, err := getRoutingRecord(s.routingBackend, util.Key(req.GetKey()))
		if err != nil {
			return "", nil
		}
		response.Record = rawRecord
		// TODO before merging: if we know any providers for the requested value, return those.
		return p, response

	case dhtpb.Message_PUT_VALUE:
		// TODO before merging: verifyRecord(req.GetRecord())
		putRoutingRecord(s.routingBackend, util.Key(req.GetKey()), req.GetRecord())
		return p, req // TODO before merging: verify that we should return record

	case dhtpb.Message_FIND_NODE:
		p := s.peerstore.PeerInfo(peer.ID(req.GetKey()))
		pri := []dhtpb.PeerRoutingInfo{
			dhtpb.PeerRoutingInfo{
				PeerInfo: p,
				// Connectedness: TODO
			},
		}
		response.CloserPeers = dhtpb.PeerRoutingInfosToPBPeers(pri)
		return p.ID, response

	case dhtpb.Message_ADD_PROVIDER:
		// FIXME(btc): do we want to store these locally? I think the
		// storeProvidersToPeerstore behavior is straight from the DHT message
		// handler.
		storeProvidersToPeerstore(s.peerstore, p, req.GetProviderPeers())

		if err := putRoutingProviders(s.routingBackend, util.Key(req.GetKey()), req.GetProviderPeers()); err != nil {
			return "", nil
		}
		return "", nil

	case dhtpb.Message_GET_PROVIDERS:
		providers, err := getRoutingProviders(s.routingBackend, util.Key(req.GetKey()))
		if err != nil {
			return "", nil
		}
		response.ProviderPeers = providers
		return p, response

	case dhtpb.Message_PING:
		return p, req
	default:
	}
	return "", nil
}

var _ proxy.RequestHandler = &Server{}
var _ proxy.Proxy = &Server{}

func getRoutingRecord(ds datastore.Datastore, k util.Key) (*dhtpb.Record, error) {
	dskey := k.DsKey()
	val, err := ds.Get(dskey)
	if err != nil {
		return nil, errors.Wrap(err)
	}
	recordBytes, ok := val.([]byte)
	if !ok {
		return nil, fmt.Errorf("datastore had non byte-slice value for %v", dskey)
	}
	var record dhtpb.Record
	if err := proto.Unmarshal(recordBytes, &record); err != nil {
		return nil, errors.New("failed to unmarshal dht record from datastore")
	}
	return &record, nil
}

func putRoutingRecord(ds datastore.Datastore, k util.Key, value *dhtpb.Record) error {
	data, err := proto.Marshal(value)
	if err != nil {
		return err
	}
	dskey := k.DsKey()
	// TODO namespace
	if err := ds.Put(dskey, data); err != nil {
		return err
	}
	return nil
}

func putRoutingProviders(ds datastore.Datastore, k util.Key, providers []*dhtpb.Message_Peer) error {
	log.Event(context.Background(), "putRoutingProviders", &k)
	pkey := datastore.KeyWithNamespaces([]string{"routing", "providers", k.String()})
	if v, err := ds.Get(pkey); err == nil {
		if msg, ok := v.([]byte); ok {
			var protomsg dhtpb.Message
			if err := proto.Unmarshal(msg, &protomsg); err != nil {
				log.Error("failed to unmarshal routing provider record. programmer error")
			} else {
				providers = append(providers, protomsg.ProviderPeers...)
			}
		}
	}
	var protomsg dhtpb.Message
	protomsg.ProviderPeers = providers
	data, err := proto.Marshal(&protomsg)
	if err != nil {
		return err
	}
	return ds.Put(pkey, data)
}

func storeProvidersToPeerstore(ps peer.Peerstore, p peer.ID, providers []*dhtpb.Message_Peer) {
	for _, provider := range providers {
		providerID := peer.ID(provider.GetId())
		if providerID != p {
			log.Errorf("provider message came from third-party %s", p)
			continue
		}
		for _, maddr := range provider.Addresses() {
			// as a router, we want to store addresses for peers who have provided
			ps.AddAddr(p, maddr, peer.AddressTTL)
		}
	}
}

func getRoutingProviders(ds datastore.Datastore, k util.Key) ([]*dhtpb.Message_Peer, error) {
	e := log.EventBegin(context.Background(), "getProviders", &k)
	defer e.Done()
	var providers []*dhtpb.Message_Peer
	pkey := datastore.KeyWithNamespaces([]string{"routing", "providers", k.String()}) // TODO key fmt
	if v, err := ds.Get(pkey); err == nil {
		if data, ok := v.([]byte); ok {
			var msg dhtpb.Message
			if err := proto.Unmarshal(data, &msg); err != nil {
				return nil, err
			}
			providers = append(providers, msg.GetProviderPeers()...)
		}
	}
	return providers, nil
}
<|endoftext|>


<commit_before>package grandcentral

import (
	"fmt"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
	datastore "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	dhtpb "github.com/jbenet/go-ipfs/routing/dht/pb"
	proxy "github.com/jbenet/go-ipfs/routing/grandcentral/proxy"
	util "github.com/jbenet/go-ipfs/util"
	errors "github.com/jbenet/go-ipfs/util/debugerror"
)

// Server handles routing queries using a database backend
type Server struct {
	local           peer.ID
	routingBackend  datastore.ThreadSafeDatastore
	peerstore       peer.Peerstore
	*proxy.Loopback // so server can be injected into client
}

// NewServer creates a new GrandCentral routing Server
func NewServer(ds datastore.ThreadSafeDatastore, ps peer.Peerstore, local peer.ID) (*Server, error) {
	s := &Server{local, ds, ps, nil}
	s.Loopback = &proxy.Loopback{
		Handler: s,
		Local:   local,
	}
	return s, nil
}

// HandleLocalRequest implements the proxy.RequestHandler interface. This is
// where requests are received from the outside world.
func (s *Server) HandleRequest(ctx context.Context, p peer.ID, req *dhtpb.Message) *dhtpb.Message {
	_, response := s.handleMessage(ctx, p, req) // ignore response peer. it's local.
	return response
}

func (s *Server) handleMessage(
	ctx context.Context, p peer.ID, req *dhtpb.Message) (peer.ID, *dhtpb.Message) {

	defer log.EventBegin(ctx, "routingMessageReceived", req, p, s.local).Done() // TODO may need to differentiate between local and remote

	var response = dhtpb.NewMessage(req.GetType(), req.GetKey(), req.GetClusterLevel())
	switch req.GetType() {

	case dhtpb.Message_GET_VALUE:
		rawRecord, err := getRoutingRecord(s.routingBackend, util.Key(req.GetKey()))
		if err != nil {
			return "", nil
		}
		response.Record = rawRecord
		// TODO before merging: if we know any providers for the requested value, return those.
		return p, response

	case dhtpb.Message_PUT_VALUE:
		// TODO before merging: verifyRecord(req.GetRecord())
		putRoutingRecord(s.routingBackend, util.Key(req.GetKey()), req.GetRecord())
		return p, req // TODO before merging: verify that we should return record

	case dhtpb.Message_FIND_NODE:
		p := s.peerstore.PeerInfo(peer.ID(req.GetKey()))
		pri := []dhtpb.PeerRoutingInfo{
			dhtpb.PeerRoutingInfo{
				PeerInfo: p,
				// Connectedness: TODO
			},
		}
		response.CloserPeers = dhtpb.PeerRoutingInfosToPBPeers(pri)
		return p.ID, response

	case dhtpb.Message_ADD_PROVIDER:
		// FIXME(btc): do we want to store these locally? I think the
		// storeProvidersToPeerstore behavior is straight from the DHT message
		// handler.
		storeProvidersToPeerstore(s.peerstore, p, req.GetProviderPeers())

		if err := putRoutingProviders(s.routingBackend, util.Key(req.GetKey()), req.GetProviderPeers()); err != nil {
			return "", nil
		}
		return "", nil

	case dhtpb.Message_GET_PROVIDERS:
		providers, err := getRoutingProviders(s.routingBackend, util.Key(req.GetKey()))
		if err != nil {
			return "", nil
		}
		response.ProviderPeers = providers
		return p, response

	case dhtpb.Message_PING:
		return p, req
	default:
	}
	return "", nil
}

var _ proxy.RequestHandler = &Server{}
var _ proxy.Proxy = &Server{}

func getRoutingRecord(ds datastore.Datastore, k util.Key) (*dhtpb.Record, error) {
	dskey := k.DsKey()
	val, err := ds.Get(dskey)
	if err != nil {
		return nil, errors.Wrap(err)
	}
	recordBytes, ok := val.([]byte)
	if !ok {
		return nil, fmt.Errorf("datastore had non byte-slice value for %v", dskey)
	}
	var record dhtpb.Record
	if err := proto.Unmarshal(recordBytes, &record); err != nil {
		return nil, errors.New("failed to unmarshal dht record from datastore")
	}
	return &record, nil
}

func putRoutingRecord(ds datastore.Datastore, k util.Key, value *dhtpb.Record) error {
	data, err := proto.Marshal(value)
	if err != nil {
		return err
	}
	dskey := k.DsKey()
	// TODO namespace
	if err := ds.Put(dskey, data); err != nil {
		return err
	}
	return nil
}

func putRoutingProviders(ds datastore.Datastore, k util.Key, newRecords []*dhtpb.Message_Peer) error {
	log.Event(context.Background(), "putRoutingProviders", &k)
	oldRecords, err := getRoutingProviders(ds, k)
	if err != nil {
		return err
	}
	mergedRecords := make(map[string]*dhtpb.Message_Peer)
	for _, provider := range oldRecords {
		mergedRecords[provider.GetId()] = provider // add original records
	}
	for _, provider := range newRecords {
		mergedRecords[provider.GetId()] = provider // overwrite old record if new exists
	}
	var protomsg dhtpb.Message
	protomsg.ProviderPeers = make([]*dhtpb.Message_Peer, 0, len(mergedRecords))
	for _, provider := range mergedRecords {
		protomsg.ProviderPeers = append(protomsg.ProviderPeers, provider)
	}
	data, err := proto.Marshal(&protomsg)
	if err != nil {
		return err
	}
	return ds.Put(providerKey(k), data)
}

func storeProvidersToPeerstore(ps peer.Peerstore, p peer.ID, providers []*dhtpb.Message_Peer) {
	for _, provider := range providers {
		providerID := peer.ID(provider.GetId())
		if providerID != p {
			log.Errorf("provider message came from third-party %s", p)
			continue
		}
		for _, maddr := range provider.Addresses() {
			// as a router, we want to store addresses for peers who have provided
			ps.AddAddr(p, maddr, peer.AddressTTL)
		}
	}
}

func getRoutingProviders(ds datastore.Datastore, k util.Key) ([]*dhtpb.Message_Peer, error) {
	e := log.EventBegin(context.Background(), "getProviders", &k)
	defer e.Done()
	var providers []*dhtpb.Message_Peer
	if v, err := ds.Get(providerKey(k)); err == nil {
		if data, ok := v.([]byte); ok {
			var msg dhtpb.Message
			if err := proto.Unmarshal(data, &msg); err != nil {
				return nil, err
			}
			providers = append(providers, msg.GetProviderPeers()...)
		}
	}
	return providers, nil
}

func providerKey(k util.Key) datastore.Key {
	return datastore.KeyWithNamespaces([]string{"routing", "providers", k.String()})
}
<commit_msg>log(gcr/s) remove local peer in message-received event<commit_after>package grandcentral

import (
	"fmt"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
	datastore "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	dhtpb "github.com/jbenet/go-ipfs/routing/dht/pb"
	proxy "github.com/jbenet/go-ipfs/routing/grandcentral/proxy"
	util "github.com/jbenet/go-ipfs/util"
	errors "github.com/jbenet/go-ipfs/util/debugerror"
)

// Server handles routing queries using a database backend
type Server struct {
	local           peer.ID
	routingBackend  datastore.ThreadSafeDatastore
	peerstore       peer.Peerstore
	*proxy.Loopback // so server can be injected into client
}

// NewServer creates a new GrandCentral routing Server
func NewServer(ds datastore.ThreadSafeDatastore, ps peer.Peerstore, local peer.ID) (*Server, error) {
	s := &Server{local, ds, ps, nil}
	s.Loopback = &proxy.Loopback{
		Handler: s,
		Local:   local,
	}
	return s, nil
}

// HandleLocalRequest implements the proxy.RequestHandler interface. This is
// where requests are received from the outside world.
func (s *Server) HandleRequest(ctx context.Context, p peer.ID, req *dhtpb.Message) *dhtpb.Message {
	_, response := s.handleMessage(ctx, p, req) // ignore response peer. it's local.
	return response
}

func (s *Server) handleMessage(
	ctx context.Context, p peer.ID, req *dhtpb.Message) (peer.ID, *dhtpb.Message) {

	defer log.EventBegin(ctx, "routingMessageReceived", req, p).Done()

	var response = dhtpb.NewMessage(req.GetType(), req.GetKey(), req.GetClusterLevel())
	switch req.GetType() {

	case dhtpb.Message_GET_VALUE:
		rawRecord, err := getRoutingRecord(s.routingBackend, util.Key(req.GetKey()))
		if err != nil {
			return "", nil
		}
		response.Record = rawRecord
		// TODO before merging: if we know any providers for the requested value, return those.
		return p, response

	case dhtpb.Message_PUT_VALUE:
		// TODO before merging: verifyRecord(req.GetRecord())
		putRoutingRecord(s.routingBackend, util.Key(req.GetKey()), req.GetRecord())
		return p, req // TODO before merging: verify that we should return record

	case dhtpb.Message_FIND_NODE:
		p := s.peerstore.PeerInfo(peer.ID(req.GetKey()))
		pri := []dhtpb.PeerRoutingInfo{
			dhtpb.PeerRoutingInfo{
				PeerInfo: p,
				// Connectedness: TODO
			},
		}
		response.CloserPeers = dhtpb.PeerRoutingInfosToPBPeers(pri)
		return p.ID, response

	case dhtpb.Message_ADD_PROVIDER:
		// FIXME(btc): do we want to store these locally? I think the
		// storeProvidersToPeerstore behavior is straight from the DHT message
		// handler.
		storeProvidersToPeerstore(s.peerstore, p, req.GetProviderPeers())

		if err := putRoutingProviders(s.routingBackend, util.Key(req.GetKey()), req.GetProviderPeers()); err != nil {
			return "", nil
		}
		return "", nil

	case dhtpb.Message_GET_PROVIDERS:
		providers, err := getRoutingProviders(s.routingBackend, util.Key(req.GetKey()))
		if err != nil {
			return "", nil
		}
		response.ProviderPeers = providers
		return p, response

	case dhtpb.Message_PING:
		return p, req
	default:
	}
	return "", nil
}

var _ proxy.RequestHandler = &Server{}
var _ proxy.Proxy = &Server{}

func getRoutingRecord(ds datastore.Datastore, k util.Key) (*dhtpb.Record, error) {
	dskey := k.DsKey()
	val, err := ds.Get(dskey)
	if err != nil {
		return nil, errors.Wrap(err)
	}
	recordBytes, ok := val.([]byte)
	if !ok {
		return nil, fmt.Errorf("datastore had non byte-slice value for %v", dskey)
	}
	var record dhtpb.Record
	if err := proto.Unmarshal(recordBytes, &record); err != nil {
		return nil, errors.New("failed to unmarshal dht record from datastore")
	}
	return &record, nil
}

func putRoutingRecord(ds datastore.Datastore, k util.Key, value *dhtpb.Record) error {
	data, err := proto.Marshal(value)
	if err != nil {
		return err
	}
	dskey := k.DsKey()
	// TODO namespace
	if err := ds.Put(dskey, data); err != nil {
		return err
	}
	return nil
}

func putRoutingProviders(ds datastore.Datastore, k util.Key, newRecords []*dhtpb.Message_Peer) error {
	log.Event(context.Background(), "putRoutingProviders", &k)
	oldRecords, err := getRoutingProviders(ds, k)
	if err != nil {
		return err
	}
	mergedRecords := make(map[string]*dhtpb.Message_Peer)
	for _, provider := range oldRecords {
		mergedRecords[provider.GetId()] = provider // add original records
	}
	for _, provider := range newRecords {
		mergedRecords[provider.GetId()] = provider // overwrite old record if new exists
	}
	var protomsg dhtpb.Message
	protomsg.ProviderPeers = make([]*dhtpb.Message_Peer, 0, len(mergedRecords))
	for _, provider := range mergedRecords {
		protomsg.ProviderPeers = append(protomsg.ProviderPeers, provider)
	}
	data, err := proto.Marshal(&protomsg)
	if err != nil {
		return err
	}
	return ds.Put(providerKey(k), data)
}

func storeProvidersToPeerstore(ps peer.Peerstore, p peer.ID, providers []*dhtpb.Message_Peer) {
	for _, provider := range providers {
		providerID := peer.ID(provider.GetId())
		if providerID != p {
			log.Errorf("provider message came from third-party %s", p)
			continue
		}
		for _, maddr := range provider.Addresses() {
			// as a router, we want to store addresses for peers who have provided
			ps.AddAddr(p, maddr, peer.AddressTTL)
		}
	}
}

func getRoutingProviders(ds datastore.Datastore, k util.Key) ([]*dhtpb.Message_Peer, error) {
	e := log.EventBegin(context.Background(), "getProviders", &k)
	defer e.Done()
	var providers []*dhtpb.Message_Peer
	if v, err := ds.Get(providerKey(k)); err == nil {
		if data, ok := v.([]byte); ok {
			var msg dhtpb.Message
			if err := proto.Unmarshal(data, &msg); err != nil {
				return nil, err
			}
			providers = append(providers, msg.GetProviderPeers()...)
		}
	}
	return providers, nil
}

func providerKey(k util.Key) datastore.Key {
	return datastore.KeyWithNamespaces([]string{"routing", "providers", k.String()})
}
<|endoftext|>


<commit_before>/*--------------------------------------------------------*\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: https://hprose.com                     |
|                                                          |
| rpc/plugins/timeout/timeout.go                           |
|                                                          |
| LastModified: Feb 21, 2021                               |
| Author: Ma Bingyao <andot@hprose.com>                    |
|                                                          |
\*________________________________________________________*/

package timeout

import (
	"context"
	"time"

	"github.com/hprose/hprose-golang/v3/rpc/core"
)

// ExecuteTimeout .
type ExecuteTimeout struct {
	Timeout time.Duration
}

// Handler for ExecuteTimeout.
func (et ExecuteTimeout) Handler(ctx context.Context, name string, args []interface{}, next core.NextInvokeHandler) (result []interface{}, err error) {
	timeout := et.Timeout
	serviceContext := core.GetServiceContext(ctx)
	if t, ok := serviceContext.Method.Options().Get("timeout"); ok {
		switch t := t.(type) {
		case time.Duration:
			timeout = t
		case int:
			timeout = time.Duration(t)
		case uint:
			timeout = time.Duration(t)
		case int64:
			timeout = time.Duration(t)
		case uint64:
			timeout = time.Duration(t)
		}
	}
	if timeout <= 0 {
		return next(ctx, name, args)
	}
	var cancel context.CancelFunc
	ctx, cancel = context.WithTimeout(ctx, timeout)
	defer cancel()
	ch := make(chan struct{}, 1)
	go func() {
		result, err = next(ctx, name, args)
		ch <- struct{}{}
		close(ch)
	}()
	select {
	case <-ctx.Done():
		return nil, core.ErrTimeout
	case <-ch:
		return result, err
	}
}

// GetHandler returns an execute timeout invoke handler.
func GetHandler(timeout ...time.Duration) core.InvokeHandler {
	if len(timeout) > 0 {
		return ExecuteTimeout{timeout[0]}.Handler
	}
	return ExecuteTimeout{time.Second * 30}.Handler
}
<commit_msg>update timeout.go<commit_after>/*--------------------------------------------------------*\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: https://hprose.com                     |
|                                                          |
| rpc/plugins/timeout/timeout.go                           |
|                                                          |
| LastModified: Feb 21, 2021                               |
| Author: Ma Bingyao <andot@hprose.com>                    |
|                                                          |
\*________________________________________________________*/

package timeout

import (
	"context"
	"time"

	"github.com/hprose/hprose-golang/v3/rpc/core"
)

// ExecuteTimeout plugin for hprose.
type ExecuteTimeout struct {
	Timeout time.Duration
}

// Handler for ExecuteTimeout.
func (et ExecuteTimeout) Handler(ctx context.Context, name string, args []interface{}, next core.NextInvokeHandler) (result []interface{}, err error) {
	timeout := et.Timeout
	serviceContext := core.GetServiceContext(ctx)
	if t, ok := serviceContext.Method.Options().Get("timeout"); ok {
		switch t := t.(type) {
		case time.Duration:
			timeout = t
		case int:
			timeout = time.Duration(t)
		case uint:
			timeout = time.Duration(t)
		case int64:
			timeout = time.Duration(t)
		case uint64:
			timeout = time.Duration(t)
		}
	}
	if timeout <= 0 {
		return next(ctx, name, args)
	}
	var cancel context.CancelFunc
	ctx, cancel = context.WithTimeout(ctx, timeout)
	defer cancel()
	ch := make(chan struct{}, 1)
	go func() {
		result, err = next(ctx, name, args)
		ch <- struct{}{}
		close(ch)
	}()
	select {
	case <-ctx.Done():
		return nil, core.ErrTimeout
	case <-ch:
		return result, err
	}
}

// GetHandler returns an execute timeout invoke handler.
func GetHandler(timeout ...time.Duration) core.InvokeHandler {
	if len(timeout) > 0 {
		return ExecuteTimeout{timeout[0]}.Handler
	}
	return ExecuteTimeout{time.Second * 30}.Handler
}
<|endoftext|>