<commit_before>package lang

import (
	"fmt"

	"github.com/zclconf/go-cty/cty"
	"github.com/zclconf/go-cty/cty/function"
	"github.com/zclconf/go-cty/cty/function/stdlib"

	"github.com/hashicorp/terraform/lang/funcs"
)

var impureFunctions = []string{
	"bcrypt",
	"timestamp",
	"uuid",
}

// Functions returns the set of functions that should be used to when evaluating
// expressions in the receiving scope.
func (s *Scope) Functions() map[string]function.Function {
	s.funcsLock.Lock()
	if s.funcs == nil {
		// Some of our functions are just directly the cty stdlib functions.
		// Others are implemented in the subdirectory "funcs" here in this
		// repository. New functions should generally start out their lives
		// in the "funcs" directory and potentially graduate to cty stdlib
		// later if the functionality seems to be something domain-agnostic
		// that would be useful to all applications using cty functions.

		s.funcs = map[string]function.Function{
			"abs":              stdlib.AbsoluteFunc,
			"basename":         funcs.BasenameFunc,
			"base64decode":     funcs.Base64DecodeFunc,
			"base64encode":     funcs.Base64EncodeFunc,
			"base64gzip":       funcs.Base64GzipFunc,
			"base64sha256":     funcs.Base64Sha256Func,
			"base64sha512":     funcs.Base64Sha512Func,
			"bcrypt":           funcs.BcryptFunc,
			"ceil":             funcs.CeilFunc,
			"chomp":            funcs.ChompFunc,
			"cidrhost":         funcs.CidrHostFunc,
			"cidrnetmask":      funcs.CidrNetmaskFunc,
			"cidrsubnet":       funcs.CidrSubnetFunc,
			"coalesce":         funcs.CoalesceFunc,
			"coalescelist":     funcs.CoalesceListFunc,
			"compact":          funcs.CompactFunc,
			"concat":           stdlib.ConcatFunc,
			"contains":         funcs.ContainsFunc,
			"csvdecode":        stdlib.CSVDecodeFunc,
			"dirname":          funcs.DirnameFunc,
			"distinct":         funcs.DistinctFunc,
			"element":          funcs.ElementFunc,
			"chunklist":        funcs.ChunklistFunc,
			"file":             funcs.MakeFileFunc(s.BaseDir, false),
			"fileexists":       funcs.MakeFileExistsFunc(s.BaseDir),
			"filebase64":       funcs.MakeFileFunc(s.BaseDir, true),
			"filebase64sha256": funcs.MakeFileBase64Sha256Func(s.BaseDir),
			"filebase64sha512": funcs.MakeFileBase64Sha512Func(s.BaseDir),
			"filemd5":          funcs.MakeFileMd5Func(s.BaseDir),
			"filesha1":         funcs.MakeFileSha1Func(s.BaseDir),
			"filesha256":       funcs.MakeFileSha256Func(s.BaseDir),
			"filesha512":       funcs.MakeFileSha512Func(s.BaseDir),
			"flatten":          funcs.FlattenFunc,
			"floor":            funcs.FloorFunc,
			"format":           stdlib.FormatFunc,
			"formatdate":       stdlib.FormatDateFunc,
			"formatlist":       stdlib.FormatListFunc,
			"indent":           funcs.IndentFunc,
			"index":            funcs.IndexFunc,
			"join":             funcs.JoinFunc,
			"jsondecode":       stdlib.JSONDecodeFunc,
			"jsonencode":       stdlib.JSONEncodeFunc,
			"keys":             funcs.KeysFunc,
			"length":           funcs.LengthFunc,
			"list":             funcs.ListFunc,
			"log":              funcs.LogFunc,
			"lookup":           funcs.LookupFunc,
			"lower":            stdlib.LowerFunc,
			"map":              funcs.MapFunc,
			"matchkeys":        funcs.MatchkeysFunc,
			"max":              stdlib.MaxFunc,
			"md5":              funcs.Md5Func,
			"merge":            funcs.MergeFunc,
			"min":              stdlib.MinFunc,
			"pathexpand":       funcs.PathExpandFunc,
			"pow":              funcs.PowFunc,
			"replace":          funcs.ReplaceFunc,
			"reverse":          funcs.ReverseFunc,
			"rsadecrypt":       funcs.RsaDecryptFunc,
			"sethaselement":    stdlib.SetHasElementFunc,
			"setintersection":  stdlib.SetIntersectionFunc,
			"setproduct":       funcs.SetProductFunc,
			"setunion":         stdlib.SetUnionFunc,
			"sha1":             funcs.Sha1Func,
			"sha256":           funcs.Sha256Func,
			"sha512":           funcs.Sha512Func,
			"signum":           funcs.SignumFunc,
			"slice":            funcs.SliceFunc,
			"sort":             funcs.SortFunc,
			"split":            funcs.SplitFunc,
			"substr":           stdlib.SubstrFunc,
			"timestamp":        funcs.TimestampFunc,
			"timeadd":          funcs.TimeAddFunc,
			"title":            funcs.TitleFunc,
			"tostring":         funcs.MakeToFunc(cty.String),
			"tonumber":         funcs.MakeToFunc(cty.Number),
			"tobool":           funcs.MakeToFunc(cty.Bool),
			"toset":            funcs.MakeToFunc(cty.Set(cty.DynamicPseudoType)),
			"tolist":           funcs.MakeToFunc(cty.List(cty.DynamicPseudoType)),
			"tomap":            funcs.MakeToFunc(cty.Map(cty.DynamicPseudoType)),
			"transpose":        funcs.TransposeFunc,
			"trimspace":        funcs.TrimSpaceFunc,
			"upper":            stdlib.UpperFunc,
			"urlencode":        funcs.URLEncodeFunc,
			"uuid":             funcs.UUIDFunc,
			"values":           funcs.ValuesFunc,
			"zipmap":           funcs.ZipmapFunc,
		}

		s.funcs["templatefile"] = funcs.MakeTemplateFileFunc(s.BaseDir, func() map[string]function.Function {
			// The templatefile function prevents recursive calls to itself
			// by copying this map and overwriting the "templatefile" entry.
			return s.funcs
		})

		if s.PureOnly {
			// Force our few impure functions to return unknown so that we
			// can defer evaluating them until a later pass.
			for _, name := range impureFunctions {
				s.funcs[name] = function.Unpredictable(s.funcs[name])
			}
		}
	}
	s.funcsLock.Unlock()

	return s.funcs
}

var unimplFunc = function.New(&function.Spec{
	Type: func([]cty.Value) (cty.Type, error) {
		return cty.DynamicPseudoType, fmt.Errorf("function not yet implemented")
	},
	Impl: func([]cty.Value, cty.Type) (cty.Value, error) {
		return cty.DynamicVal, fmt.Errorf("function not yet implemented")
	},
})
<commit_msg>lang/funcs: add 'strrev' interpolation function. (#21091)<commit_after>package lang

import (
	"fmt"

	"github.com/zclconf/go-cty/cty"
	"github.com/zclconf/go-cty/cty/function"
	"github.com/zclconf/go-cty/cty/function/stdlib"

	"github.com/hashicorp/terraform/lang/funcs"
)

var impureFunctions = []string{
	"bcrypt",
	"timestamp",
	"uuid",
}

// Functions returns the set of functions that should be used to when evaluating
// expressions in the receiving scope.
func (s *Scope) Functions() map[string]function.Function {
	s.funcsLock.Lock()
	if s.funcs == nil {
		// Some of our functions are just directly the cty stdlib functions.
		// Others are implemented in the subdirectory "funcs" here in this
		// repository. New functions should generally start out their lives
		// in the "funcs" directory and potentially graduate to cty stdlib
		// later if the functionality seems to be something domain-agnostic
		// that would be useful to all applications using cty functions.

		s.funcs = map[string]function.Function{
			"abs":              stdlib.AbsoluteFunc,
			"basename":         funcs.BasenameFunc,
			"base64decode":     funcs.Base64DecodeFunc,
			"base64encode":     funcs.Base64EncodeFunc,
			"base64gzip":       funcs.Base64GzipFunc,
			"base64sha256":     funcs.Base64Sha256Func,
			"base64sha512":     funcs.Base64Sha512Func,
			"bcrypt":           funcs.BcryptFunc,
			"ceil":             funcs.CeilFunc,
			"chomp":            funcs.ChompFunc,
			"cidrhost":         funcs.CidrHostFunc,
			"cidrnetmask":      funcs.CidrNetmaskFunc,
			"cidrsubnet":       funcs.CidrSubnetFunc,
			"coalesce":         funcs.CoalesceFunc,
			"coalescelist":     funcs.CoalesceListFunc,
			"compact":          funcs.CompactFunc,
			"concat":           stdlib.ConcatFunc,
			"contains":         funcs.ContainsFunc,
			"csvdecode":        stdlib.CSVDecodeFunc,
			"dirname":          funcs.DirnameFunc,
			"distinct":         funcs.DistinctFunc,
			"element":          funcs.ElementFunc,
			"chunklist":        funcs.ChunklistFunc,
			"file":             funcs.MakeFileFunc(s.BaseDir, false),
			"fileexists":       funcs.MakeFileExistsFunc(s.BaseDir),
			"filebase64":       funcs.MakeFileFunc(s.BaseDir, true),
			"filebase64sha256": funcs.MakeFileBase64Sha256Func(s.BaseDir),
			"filebase64sha512": funcs.MakeFileBase64Sha512Func(s.BaseDir),
			"filemd5":          funcs.MakeFileMd5Func(s.BaseDir),
			"filesha1":         funcs.MakeFileSha1Func(s.BaseDir),
			"filesha256":       funcs.MakeFileSha256Func(s.BaseDir),
			"filesha512":       funcs.MakeFileSha512Func(s.BaseDir),
			"flatten":          funcs.FlattenFunc,
			"floor":            funcs.FloorFunc,
			"format":           stdlib.FormatFunc,
			"formatdate":       stdlib.FormatDateFunc,
			"formatlist":       stdlib.FormatListFunc,
			"indent":           funcs.IndentFunc,
			"index":            funcs.IndexFunc,
			"join":             funcs.JoinFunc,
			"jsondecode":       stdlib.JSONDecodeFunc,
			"jsonencode":       stdlib.JSONEncodeFunc,
			"keys":             funcs.KeysFunc,
			"length":           funcs.LengthFunc,
			"list":             funcs.ListFunc,
			"log":              funcs.LogFunc,
			"lookup":           funcs.LookupFunc,
			"lower":            stdlib.LowerFunc,
			"map":              funcs.MapFunc,
			"matchkeys":        funcs.MatchkeysFunc,
			"max":              stdlib.MaxFunc,
			"md5":              funcs.Md5Func,
			"merge":            funcs.MergeFunc,
			"min":              stdlib.MinFunc,
			"pathexpand":       funcs.PathExpandFunc,
			"pow":              funcs.PowFunc,
			"replace":          funcs.ReplaceFunc,
			"reverse":          funcs.ReverseFunc,
			"rsadecrypt":       funcs.RsaDecryptFunc,
			"sethaselement":    stdlib.SetHasElementFunc,
			"setintersection":  stdlib.SetIntersectionFunc,
			"setproduct":       funcs.SetProductFunc,
			"setunion":         stdlib.SetUnionFunc,
			"sha1":             funcs.Sha1Func,
			"sha256":           funcs.Sha256Func,
			"sha512":           funcs.Sha512Func,
			"signum":           funcs.SignumFunc,
			"slice":            funcs.SliceFunc,
			"sort":             funcs.SortFunc,
			"split":            funcs.SplitFunc,
			"strrev":           stdlib.ReverseFunc,
			"substr":           stdlib.SubstrFunc,
			"timestamp":        funcs.TimestampFunc,
			"timeadd":          funcs.TimeAddFunc,
			"title":            funcs.TitleFunc,
			"tostring":         funcs.MakeToFunc(cty.String),
			"tonumber":         funcs.MakeToFunc(cty.Number),
			"tobool":           funcs.MakeToFunc(cty.Bool),
			"toset":            funcs.MakeToFunc(cty.Set(cty.DynamicPseudoType)),
			"tolist":           funcs.MakeToFunc(cty.List(cty.DynamicPseudoType)),
			"tomap":            funcs.MakeToFunc(cty.Map(cty.DynamicPseudoType)),
			"transpose":        funcs.TransposeFunc,
			"trimspace":        funcs.TrimSpaceFunc,
			"upper":            stdlib.UpperFunc,
			"urlencode":        funcs.URLEncodeFunc,
			"uuid":             funcs.UUIDFunc,
			"values":           funcs.ValuesFunc,
			"zipmap":           funcs.ZipmapFunc,
		}

		s.funcs["templatefile"] = funcs.MakeTemplateFileFunc(s.BaseDir, func() map[string]function.Function {
			// The templatefile function prevents recursive calls to itself
			// by copying this map and overwriting the "templatefile" entry.
			return s.funcs
		})

		if s.PureOnly {
			// Force our few impure functions to return unknown so that we
			// can defer evaluating them until a later pass.
			for _, name := range impureFunctions {
				s.funcs[name] = function.Unpredictable(s.funcs[name])
			}
		}
	}
	s.funcsLock.Unlock()

	return s.funcs
}

var unimplFunc = function.New(&function.Spec{
	Type: func([]cty.Value) (cty.Type, error) {
		return cty.DynamicPseudoType, fmt.Errorf("function not yet implemented")
	},
	Impl: func([]cty.Value, cty.Type) (cty.Value, error) {
		return cty.DynamicVal, fmt.Errorf("function not yet implemented")
	},
})
<|endoftext|>


<commit_before>// Copyright 2016 e-Xpert Solutions SA. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package diff_test

import (
	"log"

	"e-xpert_solutions/go-diff/diff"
)

type Foo struct {
	IntVal    int
	FloatVal  float32
	StringVal string
	Bar       Bar
	FooPtr    *Foo
	IntList   []int
}

type Bar struct {
	StringVal string
}

func Example() {
	f1 := Foo{
		IntVal:    42,
		FloatVal:  53.032,
		StringVal: "bar",
		Bar: Bar{
			StringVal: "ok",
		},
		FooPtr:  nil,
		IntList: []int{1, 3, 4},
	}
	f2 := Foo{
		IntVal:    42,
		FloatVal:  53.042,
		StringVal: "baraca",
		Bar: Bar{
			StringVal: "ok",
		},
		FooPtr: &Foo{
			IntVal: 42,
		},
		IntList: []int{1, 2, 4, 5},
	}
	delta, err := diff.Compute(f1, f2)
	if err != nil {
		log.Fatal(err)
	}
	log.Print("delta = ", delta)
}
<commit_msg>diff: update example<commit_after>// Copyright 2016 e-Xpert Solutions SA. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package diff_test

import (
	"log"

	"e-xpert_solutions/go-diff/diff"
)

type Foo struct {
	IntVal    int
	FloatVal  float32
	StringVal string
	Bar       Bar
	FooPtr    *Foo
	IntList   []int
}

type Bar struct {
	StringVal string
}

func Example() {
	f1 := Foo{
		IntVal:    42,
		FloatVal:  53.032,
		StringVal: "bar",
		Bar: Bar{
			StringVal: "ok",
		},
		FooPtr:  nil,
		IntList: []int{1, 3, 4},
	}
	f2 := Foo{
		IntVal:    42,
		FloatVal:  53.042,
		StringVal: "baraca",
		Bar: Bar{
			StringVal: "ok",
		},
		FooPtr: &Foo{
			IntVal: 42,
		},
		IntList: []int{1, 2, 4, 5},
	}

	// Basic example
	delta, err := diff.Compute(f1, f2)
	if err != nil {
		log.Fatal(err)
	}
	log.Print("delta = ", delta)

	// Example with more options
	engine := diff.Engine{
		ExcludeFieldList: []string{"StringVal"},
	}
	delta, err = engine.Compute(f1, f2)
	if err != nil {
		log.Fatal(err)
	}
	log.Print("delta = ", delta)
}
<|endoftext|>


<commit_before>package scenarios

import (
	"bytes"
	"crypto/rand"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"testing"

	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"

	"v2ray.com/core"
	"v2ray.com/core/app/proxyman"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/serial"
	"v2ray.com/core/proxy/freedom"
	v2http "v2ray.com/core/proxy/http"
	v2httptest "v2ray.com/core/testing/servers/http"
	"v2ray.com/core/testing/servers/tcp"
	. "v2ray.com/ext/assert"
)

func TestHttpConformance(t *testing.T) {
	assert := With(t)

	httpServerPort := tcp.PickPort()
	httpServer := &v2httptest.Server{
		Port:        httpServerPort,
		PathHandler: make(map[string]http.HandlerFunc),
	}
	_, err := httpServer.Start()
	assert(err, IsNil)
	defer httpServer.Close()

	serverPort := tcp.PickPort()
	serverConfig := &core.Config{
		Inbound: []*core.InboundHandlerConfig{
			{
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
					PortRange: net.SinglePortRange(serverPort),
					Listen:    net.NewIPOrDomain(net.LocalHostIP),
				}),
				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
			},
		},
		Outbound: []*core.OutboundHandlerConfig{
			{
				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
			},
		},
	}

	servers, err := InitializeServerConfigs(serverConfig)
	assert(err, IsNil)

	{
		transport := &http.Transport{
			Proxy: func(req *http.Request) (*url.URL, error) {
				return url.Parse("http://127.0.0.1:" + serverPort.String())
			},
		}

		client := &http.Client{
			Transport: transport,
		}

		resp, err := client.Get("http://127.0.0.1:" + httpServerPort.String())
		assert(err, IsNil)
		assert(resp.StatusCode, Equals, 200)

		content, err := ioutil.ReadAll(resp.Body)
		assert(err, IsNil)
		assert(string(content), Equals, "Home")

	}

	CloseAllServers(servers)
}

func TestHttpConnectMethod(t *testing.T) {
	assert := With(t)

	tcpServer := tcp.Server{
		MsgProcessor: xor,
	}
	dest, err := tcpServer.Start()
	assert(err, IsNil)
	defer tcpServer.Close()

	serverPort := tcp.PickPort()
	serverConfig := &core.Config{
		Inbound: []*core.InboundHandlerConfig{
			{
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
					PortRange: net.SinglePortRange(serverPort),
					Listen:    net.NewIPOrDomain(net.LocalHostIP),
				}),
				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
			},
		},
		Outbound: []*core.OutboundHandlerConfig{
			{
				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
			},
		},
	}

	servers, err := InitializeServerConfigs(serverConfig)
	assert(err, IsNil)

	{
		transport := &http.Transport{
			Proxy: func(req *http.Request) (*url.URL, error) {
				return url.Parse("http://127.0.0.1:" + serverPort.String())
			},
		}

		client := &http.Client{
			Transport: transport,
		}

		payload := make([]byte, 1024*64)
		common.Must2(rand.Read(payload))
		req, err := http.NewRequest("Connect", "http://"+dest.NetAddr()+"/", bytes.NewReader(payload))
		req.Header.Set("X-a", "b")
		req.Header.Set("X-b", "d")
		common.Must(err)

		resp, err := client.Do(req)
		assert(err, IsNil)
		assert(resp.StatusCode, Equals, 200)

		content := make([]byte, len(payload))
		common.Must2(io.ReadFull(resp.Body, content))
		assert(err, IsNil)
		assert(content, Equals, xor(payload))

	}

	CloseAllServers(servers)
}

func TestHttpPost(t *testing.T) {
	assert := With(t)

	httpServerPort := tcp.PickPort()
	httpServer := &v2httptest.Server{
		Port: httpServerPort,
		PathHandler: map[string]http.HandlerFunc{
			"/testpost": func(w http.ResponseWriter, r *http.Request) {
				payload, err := buf.ReadAllToBytes(r.Body)
				r.Body.Close()

				if err != nil {
					w.WriteHeader(500)
					w.Write([]byte("Unable to read all payload"))
					return
				}
				payload = xor(payload)
				w.Write(payload)
			},
		},
	}

	_, err := httpServer.Start()
	assert(err, IsNil)
	defer httpServer.Close()

	serverPort := tcp.PickPort()
	serverConfig := &core.Config{
		Inbound: []*core.InboundHandlerConfig{
			{
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
					PortRange: net.SinglePortRange(serverPort),
					Listen:    net.NewIPOrDomain(net.LocalHostIP),
				}),
				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
			},
		},
		Outbound: []*core.OutboundHandlerConfig{
			{
				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
			},
		},
	}

	servers, err := InitializeServerConfigs(serverConfig)
	assert(err, IsNil)

	{
		transport := &http.Transport{
			Proxy: func(req *http.Request) (*url.URL, error) {
				return url.Parse("http://127.0.0.1:" + serverPort.String())
			},
		}

		client := &http.Client{
			Transport: transport,
		}

		payload := make([]byte, 1024*64)
		common.Must2(rand.Read(payload))

		resp, err := client.Post("http://127.0.0.1:"+httpServerPort.String()+"/testpost", "application/x-www-form-urlencoded", bytes.NewReader(payload))
		assert(err, IsNil)
		assert(resp.StatusCode, Equals, 200)

		content, err := ioutil.ReadAll(resp.Body)
		assert(err, IsNil)
		assert(content, Equals, xor(payload))

	}

	CloseAllServers(servers)
}

func setProxyBasicAuth(req *http.Request, user, pass string) {
	req.SetBasicAuth(user, pass)
	req.Header.Set("Proxy-Authorization", req.Header.Get("Authorization"))
	req.Header.Del("Authorization")
}

func TestHttpBasicAuth(t *testing.T) {
	assert := With(t)

	httpServerPort := tcp.PickPort()
	httpServer := &v2httptest.Server{
		Port:        httpServerPort,
		PathHandler: make(map[string]http.HandlerFunc),
	}
	_, err := httpServer.Start()
	assert(err, IsNil)
	defer httpServer.Close()

	serverPort := tcp.PickPort()
	serverConfig := &core.Config{
		Inbound: []*core.InboundHandlerConfig{
			{
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
					PortRange: net.SinglePortRange(serverPort),
					Listen:    net.NewIPOrDomain(net.LocalHostIP),
				}),
				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{
					Accounts: map[string]string{
						"a": "b",
					},
				}),
			},
		},
		Outbound: []*core.OutboundHandlerConfig{
			{
				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
			},
		},
	}

	servers, err := InitializeServerConfigs(serverConfig)
	assert(err, IsNil)

	{
		transport := &http.Transport{
			Proxy: func(req *http.Request) (*url.URL, error) {
				return url.Parse("http://127.0.0.1:" + serverPort.String())
			},
		}

		client := &http.Client{
			Transport: transport,
		}

		{
			resp, err := client.Get("http://127.0.0.1:" + httpServerPort.String())
			assert(err, IsNil)
			assert(resp.StatusCode, Equals, 407)
		}

		{
			req, err := http.NewRequest("GET", "http://127.0.0.1:"+httpServerPort.String(), nil)
			assert(err, IsNil)

			setProxyBasicAuth(req, "a", "c")
			resp, err := client.Do(req)
			assert(err, IsNil)
			assert(resp.StatusCode, Equals, 407)
		}

		{
			req, err := http.NewRequest("GET", "http://127.0.0.1:"+httpServerPort.String(), nil)
			assert(err, IsNil)

			setProxyBasicAuth(req, "a", "b")
			resp, err := client.Do(req)
			assert(err, IsNil)
			assert(resp.StatusCode, Equals, 200)

			content, err := ioutil.ReadAll(resp.Body)
			assert(err, IsNil)
			assert(string(content), Equals, "Home")
		}
	}

	CloseAllServers(servers)
}
<commit_msg>test case for http proxy error<commit_after>package scenarios

import (
	"bytes"
	"crypto/rand"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"testing"

	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"

	"v2ray.com/core"
	"v2ray.com/core/app/proxyman"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/serial"
	"v2ray.com/core/proxy/blackhole"
	"v2ray.com/core/proxy/freedom"
	v2http "v2ray.com/core/proxy/http"
	v2httptest "v2ray.com/core/testing/servers/http"
	"v2ray.com/core/testing/servers/tcp"
	. "v2ray.com/ext/assert"
)

func TestHttpConformance(t *testing.T) {
	assert := With(t)

	httpServerPort := tcp.PickPort()
	httpServer := &v2httptest.Server{
		Port:        httpServerPort,
		PathHandler: make(map[string]http.HandlerFunc),
	}
	_, err := httpServer.Start()
	assert(err, IsNil)
	defer httpServer.Close()

	serverPort := tcp.PickPort()
	serverConfig := &core.Config{
		Inbound: []*core.InboundHandlerConfig{
			{
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
					PortRange: net.SinglePortRange(serverPort),
					Listen:    net.NewIPOrDomain(net.LocalHostIP),
				}),
				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
			},
		},
		Outbound: []*core.OutboundHandlerConfig{
			{
				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
			},
		},
	}

	servers, err := InitializeServerConfigs(serverConfig)
	assert(err, IsNil)

	{
		transport := &http.Transport{
			Proxy: func(req *http.Request) (*url.URL, error) {
				return url.Parse("http://127.0.0.1:" + serverPort.String())
			},
		}

		client := &http.Client{
			Transport: transport,
		}

		resp, err := client.Get("http://127.0.0.1:" + httpServerPort.String())
		assert(err, IsNil)
		assert(resp.StatusCode, Equals, 200)

		content, err := ioutil.ReadAll(resp.Body)
		assert(err, IsNil)
		assert(string(content), Equals, "Home")

	}

	CloseAllServers(servers)
}

func TestHttpError(t *testing.T) {
	assert := With(t)

	serverPort := tcp.PickPort()
	serverConfig := &core.Config{
		Inbound: []*core.InboundHandlerConfig{
			{
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
					PortRange: net.SinglePortRange(serverPort),
					Listen:    net.NewIPOrDomain(net.LocalHostIP),
				}),
				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
			},
		},
		Outbound: []*core.OutboundHandlerConfig{
			{
				ProxySettings: serial.ToTypedMessage(&blackhole.Config{}),
			},
		},
	}

	servers, err := InitializeServerConfigs(serverConfig)
	assert(err, IsNil)

	{
		transport := &http.Transport{
			Proxy: func(req *http.Request) (*url.URL, error) {
				return url.Parse("http://127.0.0.1:" + serverPort.String())
			},
		}

		client := &http.Client{
			Transport: transport,
		}

		resp, err := client.Get("http://127.0.0.1:80")
		assert(err, IsNil)
		assert(resp.StatusCode, Equals, 503)
	}

	CloseAllServers(servers)
}

func TestHttpConnectMethod(t *testing.T) {
	assert := With(t)

	tcpServer := tcp.Server{
		MsgProcessor: xor,
	}
	dest, err := tcpServer.Start()
	assert(err, IsNil)
	defer tcpServer.Close()

	serverPort := tcp.PickPort()
	serverConfig := &core.Config{
		Inbound: []*core.InboundHandlerConfig{
			{
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
					PortRange: net.SinglePortRange(serverPort),
					Listen:    net.NewIPOrDomain(net.LocalHostIP),
				}),
				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
			},
		},
		Outbound: []*core.OutboundHandlerConfig{
			{
				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
			},
		},
	}

	servers, err := InitializeServerConfigs(serverConfig)
	assert(err, IsNil)

	{
		transport := &http.Transport{
			Proxy: func(req *http.Request) (*url.URL, error) {
				return url.Parse("http://127.0.0.1:" + serverPort.String())
			},
		}

		client := &http.Client{
			Transport: transport,
		}

		payload := make([]byte, 1024*64)
		common.Must2(rand.Read(payload))
		req, err := http.NewRequest("Connect", "http://"+dest.NetAddr()+"/", bytes.NewReader(payload))
		req.Header.Set("X-a", "b")
		req.Header.Set("X-b", "d")
		common.Must(err)

		resp, err := client.Do(req)
		assert(err, IsNil)
		assert(resp.StatusCode, Equals, 200)

		content := make([]byte, len(payload))
		common.Must2(io.ReadFull(resp.Body, content))
		assert(err, IsNil)
		assert(content, Equals, xor(payload))

	}

	CloseAllServers(servers)
}

func TestHttpPost(t *testing.T) {
	assert := With(t)

	httpServerPort := tcp.PickPort()
	httpServer := &v2httptest.Server{
		Port: httpServerPort,
		PathHandler: map[string]http.HandlerFunc{
			"/testpost": func(w http.ResponseWriter, r *http.Request) {
				payload, err := buf.ReadAllToBytes(r.Body)
				r.Body.Close()

				if err != nil {
					w.WriteHeader(500)
					w.Write([]byte("Unable to read all payload"))
					return
				}
				payload = xor(payload)
				w.Write(payload)
			},
		},
	}

	_, err := httpServer.Start()
	assert(err, IsNil)
	defer httpServer.Close()

	serverPort := tcp.PickPort()
	serverConfig := &core.Config{
		Inbound: []*core.InboundHandlerConfig{
			{
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
					PortRange: net.SinglePortRange(serverPort),
					Listen:    net.NewIPOrDomain(net.LocalHostIP),
				}),
				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
			},
		},
		Outbound: []*core.OutboundHandlerConfig{
			{
				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
			},
		},
	}

	servers, err := InitializeServerConfigs(serverConfig)
	assert(err, IsNil)

	{
		transport := &http.Transport{
			Proxy: func(req *http.Request) (*url.URL, error) {
				return url.Parse("http://127.0.0.1:" + serverPort.String())
			},
		}

		client := &http.Client{
			Transport: transport,
		}

		payload := make([]byte, 1024*64)
		common.Must2(rand.Read(payload))

		resp, err := client.Post("http://127.0.0.1:"+httpServerPort.String()+"/testpost", "application/x-www-form-urlencoded", bytes.NewReader(payload))
		assert(err, IsNil)
		assert(resp.StatusCode, Equals, 200)

		content, err := ioutil.ReadAll(resp.Body)
		assert(err, IsNil)
		assert(content, Equals, xor(payload))

	}

	CloseAllServers(servers)
}

func setProxyBasicAuth(req *http.Request, user, pass string) {
	req.SetBasicAuth(user, pass)
	req.Header.Set("Proxy-Authorization", req.Header.Get("Authorization"))
	req.Header.Del("Authorization")
}

func TestHttpBasicAuth(t *testing.T) {
	assert := With(t)

	httpServerPort := tcp.PickPort()
	httpServer := &v2httptest.Server{
		Port:        httpServerPort,
		PathHandler: make(map[string]http.HandlerFunc),
	}
	_, err := httpServer.Start()
	assert(err, IsNil)
	defer httpServer.Close()

	serverPort := tcp.PickPort()
	serverConfig := &core.Config{
		Inbound: []*core.InboundHandlerConfig{
			{
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
					PortRange: net.SinglePortRange(serverPort),
					Listen:    net.NewIPOrDomain(net.LocalHostIP),
				}),
				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{
					Accounts: map[string]string{
						"a": "b",
					},
				}),
			},
		},
		Outbound: []*core.OutboundHandlerConfig{
			{
				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
			},
		},
	}

	servers, err := InitializeServerConfigs(serverConfig)
	assert(err, IsNil)

	{
		transport := &http.Transport{
			Proxy: func(req *http.Request) (*url.URL, error) {
				return url.Parse("http://127.0.0.1:" + serverPort.String())
			},
		}

		client := &http.Client{
			Transport: transport,
		}

		{
			resp, err := client.Get("http://127.0.0.1:" + httpServerPort.String())
			assert(err, IsNil)
			assert(resp.StatusCode, Equals, 407)
		}

		{
			req, err := http.NewRequest("GET", "http://127.0.0.1:"+httpServerPort.String(), nil)
			assert(err, IsNil)

			setProxyBasicAuth(req, "a", "c")
			resp, err := client.Do(req)
			assert(err, IsNil)
			assert(resp.StatusCode, Equals, 407)
		}

		{
			req, err := http.NewRequest("GET", "http://127.0.0.1:"+httpServerPort.String(), nil)
			assert(err, IsNil)

			setProxyBasicAuth(req, "a", "b")
			resp, err := client.Do(req)
			assert(err, IsNil)
			assert(resp.StatusCode, Equals, 200)

			content, err := ioutil.ReadAll(resp.Body)
			assert(err, IsNil)
			assert(string(content), Equals, "Home")
		}
	}

	CloseAllServers(servers)
}
<|endoftext|>


<commit_before>package dispatch

type ActionType int
const (
    READ_DIRECT ActionType = iota
    //READ_DIRECT_BLOCKING
    WRITE_DIRECT
    READ_CUSTOM
    WRITE_CUSTOM
)

//ReturnType
type ReturnType int
const (
    STRING ReturnType = iota
    INT
    FLOAT
    LIST
    MAP
)

type commandInfo struct {
    ActionType ActionType
    ReturnType ReturnType
    MultipleKeys bool
}

var commandMap = map[string]*commandInfo{

    //Keys
    "del":              &commandInfo{ WRITE_DIRECT, INT,    true  },
    "exists":           &commandInfo{ READ_DIRECT,  INT,    false },
    "expire":           &commandInfo{ WRITE_DIRECT, INT,    false },
    "expireat":         &commandInfo{ WRITE_DIRECT, INT,    false },
    "persist":          &commandInfo{ WRITE_DIRECT, INT,    false },
    "pexpire":          &commandInfo{ WRITE_DIRECT, INT,    false },
    "pexpireat":        &commandInfo{ WRITE_DIRECT, INT,    false },
    "pttl":             &commandInfo{ READ_DIRECT,  INT,    false },
    "ttl":              &commandInfo{ READ_DIRECT,  INT,    false },
    "type":             &commandInfo{ READ_DIRECT,  STRING, false },

    //Strings
    "append":           &commandInfo{ WRITE_DIRECT, INT,    false },
    "bitcount":         &commandInfo{ READ_DIRECT,  INT,    false },
    "decr":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "decrby":           &commandInfo{ WRITE_DIRECT, INT,    false },
    "get":              &commandInfo{ READ_DIRECT,  STRING, false },
    "getbit":           &commandInfo{ READ_DIRECT,  INT,    false },
    "getrange":         &commandInfo{ READ_DIRECT,  STRING, false },
    "getset":           &commandInfo{ WRITE_DIRECT, STRING, false },
    "incr":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "incrby":           &commandInfo{ WRITE_DIRECT, INT,    false },
    "incrbyfloat":      &commandInfo{ WRITE_DIRECT, STRING, false },
    "mget":             &commandInfo{ READ_DIRECT,  LIST,   true  },
    "mset":             &commandInfo{ WRITE_DIRECT, STRING, true  },
    "msetnx":           &commandInfo{ WRITE_DIRECT, INT,    true  },
    "psetex":           &commandInfo{ WRITE_DIRECT, STRING, false },
    "set":              &commandInfo{ WRITE_DIRECT, STRING, false },
    "setbit":           &commandInfo{ WRITE_DIRECT, INT,    false },
    "setex":            &commandInfo{ WRITE_DIRECT, STRING, false },
    "setnx":            &commandInfo{ WRITE_DIRECT, INT,    false },
    "setrange":         &commandInfo{ WRITE_DIRECT, INT,    false },
    "strlen":           &commandInfo{ READ_DIRECT,  INT,    false },

    //Hashes
    "hdel":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "hexists":          &commandInfo{ READ_DIRECT,  INT,    false },
    "hget":             &commandInfo{ READ_DIRECT,  STRING, false },
    "hgetall":          &commandInfo{ READ_DIRECT,  MAP,    false },
    "hincrby":          &commandInfo{ WRITE_DIRECT, INT,    false },
    "hincrbyfloat":     &commandInfo{ WRITE_DIRECT, STRING, false },
    "hkeys":            &commandInfo{ READ_DIRECT,  LIST,   false },
    "hlen":             &commandInfo{ READ_DIRECT,  INT,    false },
    "hmget":            &commandInfo{ READ_DIRECT,  LIST,   false },
    "hmset":            &commandInfo{ WRITE_DIRECT, STRING, true  },
    "hset":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "hsetnx":           &commandInfo{ WRITE_DIRECT, INT,    false },
    "hvals":            &commandInfo{ READ_DIRECT,  LIST,   false },

    //Lists
    //blpop
    //brpop
    "lindex":           &commandInfo{ READ_DIRECT,  STRING, false },
    "linsert":          &commandInfo{ WRITE_DIRECT, INT,    false },
    "llen":             &commandInfo{ READ_DIRECT,  INT,    false },
    "lpop":             &commandInfo{ WRITE_DIRECT, STRING, false },
    "lpush":            &commandInfo{ WRITE_DIRECT, INT,    false },
    "lpushx":           &commandInfo{ WRITE_DIRECT, INT,    false },
    "lrange":           &commandInfo{ READ_DIRECT,  LIST,   false },
    "lrem":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "lset":             &commandInfo{ WRITE_DIRECT, STRING, false },
    "ltrim":            &commandInfo{ WRITE_DIRECT, STRING, false },
    "rpop":             &commandInfo{ WRITE_DIRECT, STRING, false },
    "rpush":            &commandInfo{ WRITE_DIRECT, INT,    false },
    "rpushx":           &commandInfo{ WRITE_DIRECT, INT,    false },

    //Sets
    "sadd":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "scard":            &commandInfo{ READ_DIRECT,  INT,    false },
    "sismember":        &commandInfo{ READ_DIRECT,  INT,    false },
    "smembers":         &commandInfo{ READ_DIRECT,  LIST,   false },
    "spop":             &commandInfo{ WRITE_DIRECT, STRING, false },
    "srandmember":      &commandInfo{ READ_DIRECT,  STRING, false },
    "srem":             &commandInfo{ WRITE_DIRECT, INT,    false },

    //Sorted Sets
    "zadd":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "zcard":            &commandInfo{ READ_DIRECT,  INT,    false },
    "zcount":           &commandInfo{ READ_DIRECT,  INT,    false },
    "zincrby":          &commandInfo{ WRITE_DIRECT, STRING, false },
    "zrange":           &commandInfo{ READ_DIRECT,  LIST,   false },
    "zrangebyscore":    &commandInfo{ READ_DIRECT,  LIST,   false },
    "zrank":            &commandInfo{ READ_DIRECT,  INT,    false }, //TODO two different return values?
    "zrem":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "zremrangebyrank":  &commandInfo{ WRITE_DIRECT, INT,    false },
    "zremrangebyscore": &commandInfo{ WRITE_DIRECT, INT,    false },
    "zrevrange":        &commandInfo{ READ_DIRECT,  LIST,   false },
    "zrevrangebyscore": &commandInfo{ READ_DIRECT,  LIST,   false },
    "zrevrank":         &commandInfo{ READ_DIRECT,  INT,    false }, //TODO two different return values?
    "zscore":           &commandInfo{ READ_DIRECT,  STRING, false },
}
<commit_msg>took out all multikey commands<commit_after>package dispatch

type ActionType int
const (
    READ_DIRECT ActionType = iota
    //READ_DIRECT_BLOCKING
    WRITE_DIRECT
    READ_CUSTOM
    WRITE_CUSTOM
)

//ReturnType
type ReturnType int
const (
    STRING ReturnType = iota
    INT
    FLOAT
    LIST
    MAP
)

type commandInfo struct {
    ActionType ActionType
    ReturnType ReturnType
    MultipleKeys bool
}

var commandMap = map[string]*commandInfo{

    //Keys
    "exists":           &commandInfo{ READ_DIRECT,  INT,    false },
    "expire":           &commandInfo{ WRITE_DIRECT, INT,    false },
    "expireat":         &commandInfo{ WRITE_DIRECT, INT,    false },
    "persist":          &commandInfo{ WRITE_DIRECT, INT,    false },
    "pexpire":          &commandInfo{ WRITE_DIRECT, INT,    false },
    "pexpireat":        &commandInfo{ WRITE_DIRECT, INT,    false },
    "pttl":             &commandInfo{ READ_DIRECT,  INT,    false },
    "ttl":              &commandInfo{ READ_DIRECT,  INT,    false },
    "type":             &commandInfo{ READ_DIRECT,  STRING, false },

    //Strings
    "append":           &commandInfo{ WRITE_DIRECT, INT,    false },
    "bitcount":         &commandInfo{ READ_DIRECT,  INT,    false },
    "decr":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "decrby":           &commandInfo{ WRITE_DIRECT, INT,    false },
    "get":              &commandInfo{ READ_DIRECT,  STRING, false },
    "getbit":           &commandInfo{ READ_DIRECT,  INT,    false },
    "getrange":         &commandInfo{ READ_DIRECT,  STRING, false },
    "getset":           &commandInfo{ WRITE_DIRECT, STRING, false },
    "incr":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "incrby":           &commandInfo{ WRITE_DIRECT, INT,    false },
    "incrbyfloat":      &commandInfo{ WRITE_DIRECT, STRING, false },
    "psetex":           &commandInfo{ WRITE_DIRECT, STRING, false },
    "set":              &commandInfo{ WRITE_DIRECT, STRING, false },
    "setbit":           &commandInfo{ WRITE_DIRECT, INT,    false },
    "setex":            &commandInfo{ WRITE_DIRECT, STRING, false },
    "setnx":            &commandInfo{ WRITE_DIRECT, INT,    false },
    "setrange":         &commandInfo{ WRITE_DIRECT, INT,    false },
    "strlen":           &commandInfo{ READ_DIRECT,  INT,    false },

    //Hashes
    "hdel":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "hexists":          &commandInfo{ READ_DIRECT,  INT,    false },
    "hget":             &commandInfo{ READ_DIRECT,  STRING, false },
    "hgetall":          &commandInfo{ READ_DIRECT,  MAP,    false },
    "hincrby":          &commandInfo{ WRITE_DIRECT, INT,    false },
    "hincrbyfloat":     &commandInfo{ WRITE_DIRECT, STRING, false },
    "hkeys":            &commandInfo{ READ_DIRECT,  LIST,   false },
    "hlen":             &commandInfo{ READ_DIRECT,  INT,    false },
    "hmget":            &commandInfo{ READ_DIRECT,  LIST,   false },
    "hset":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "hsetnx":           &commandInfo{ WRITE_DIRECT, INT,    false },
    "hvals":            &commandInfo{ READ_DIRECT,  LIST,   false },

    //Lists
    //blpop
    //brpop
    "lindex":           &commandInfo{ READ_DIRECT,  STRING, false },
    "linsert":          &commandInfo{ WRITE_DIRECT, INT,    false },
    "llen":             &commandInfo{ READ_DIRECT,  INT,    false },
    "lpop":             &commandInfo{ WRITE_DIRECT, STRING, false },
    "lpush":            &commandInfo{ WRITE_DIRECT, INT,    false },
    "lpushx":           &commandInfo{ WRITE_DIRECT, INT,    false },
    "lrange":           &commandInfo{ READ_DIRECT,  LIST,   false },
    "lrem":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "lset":             &commandInfo{ WRITE_DIRECT, STRING, false },
    "ltrim":            &commandInfo{ WRITE_DIRECT, STRING, false },
    "rpop":             &commandInfo{ WRITE_DIRECT, STRING, false },
    "rpush":            &commandInfo{ WRITE_DIRECT, INT,    false },
    "rpushx":           &commandInfo{ WRITE_DIRECT, INT,    false },

    //Sets
    "sadd":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "scard":            &commandInfo{ READ_DIRECT,  INT,    false },
    "sismember":        &commandInfo{ READ_DIRECT,  INT,    false },
    "smembers":         &commandInfo{ READ_DIRECT,  LIST,   false },
    "spop":             &commandInfo{ WRITE_DIRECT, STRING, false },
    "srandmember":      &commandInfo{ READ_DIRECT,  STRING, false },
    "srem":             &commandInfo{ WRITE_DIRECT, INT,    false },

    //Sorted Sets
    "zadd":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "zcard":            &commandInfo{ READ_DIRECT,  INT,    false },
    "zcount":           &commandInfo{ READ_DIRECT,  INT,    false },
    "zincrby":          &commandInfo{ WRITE_DIRECT, STRING, false },
    "zrange":           &commandInfo{ READ_DIRECT,  LIST,   false },
    "zrangebyscore":    &commandInfo{ READ_DIRECT,  LIST,   false },
    "zrank":            &commandInfo{ READ_DIRECT,  INT,    false }, //TODO two different return values?
    "zrem":             &commandInfo{ WRITE_DIRECT, INT,    false },
    "zremrangebyrank":  &commandInfo{ WRITE_DIRECT, INT,    false },
    "zremrangebyscore": &commandInfo{ WRITE_DIRECT, INT,    false },
    "zrevrange":        &commandInfo{ READ_DIRECT,  LIST,   false },
    "zrevrangebyscore": &commandInfo{ READ_DIRECT,  LIST,   false },
    "zrevrank":         &commandInfo{ READ_DIRECT,  INT,    false }, //TODO two different return values?
    "zscore":           &commandInfo{ READ_DIRECT,  STRING, false },
}
<|endoftext|>


<commit_before>package main

import (
	"net/url"
	"regexp"
	"strings"
	"sync"
	"time"
)

const formatValues = "values"
const formatTabSeparated = "tabseparated"

var regexFormat = regexp.MustCompile("(?i)format\\s\\S+(\\s+)")
var regexValues = regexp.MustCompile("(?i)\\svalues\\s")
var regexGetFormat = regexp.MustCompile("(?i)format\\s(\\S+)")

// Table - store query table info
type Table struct {
	Name          string
	Format        string
	Query         string
	Params        string
	Rows          []string
	count         int
	FlushCount    int
	FlushInterval int
	mu            sync.Mutex
	Sender        Sender
	// todo add Last Error
}

// Collector - query collector
type Collector struct {
	Tables        map[string]*Table
	mu            sync.RWMutex
	Count         int
	FlushInterval int
	Sender        Sender
}

// NewTable - default table constructor
func NewTable(name string, sender Sender, count int, interval int) (t *Table) {
	t = new(Table)
	t.Name = name
	t.Sender = sender
	t.FlushCount = count
	t.FlushInterval = interval
	return t
}

// NewCollector - default collector constructor
func NewCollector(sender Sender, count int, interval int) (c *Collector) {
	c = new(Collector)
	c.Sender = sender
	c.Tables = make(map[string]*Table)
	c.Count = count
	c.FlushInterval = interval
	return c
}

// Content - get text content of rowsfor query
func (t *Table) Content() string {
	return t.Query + "\n" + strings.Join(t.Rows, "\n")
}

// Flush - sends collected data in table to clickhouse
func (t *Table) Flush() {
	req := ClickhouseRequest{
		Params:  t.Params,
		Query:   t.Query,
		Content: t.Content(),
		Count:   t.count,
	}
	t.Sender.Send(&req)
	t.Rows = make([]string, 0, t.FlushCount)
	t.count = 0
}

// CheckFlush - check if flush is need and sends data to clickhouse
func (t *Table) CheckFlush() bool {
	t.mu.Lock()
	defer t.mu.Unlock()
	if t.count > 0 {
		t.Flush()
		return true
	}
	return false
}

// Empty - Checks if table is empty
func (t *Table) Empty() bool {
	return t.GetCount() == 0
}

// GetCount - Checks if table is empty
func (t *Table) GetCount() int {
	t.mu.Lock()
	defer t.mu.Unlock()
	return t.count
}

// RunTimer - timer for periodical savings data
func (t *Table) RunTimer() {
	ticker := time.NewTicker(time.Millisecond * time.Duration(t.FlushInterval))
	go func() {
		for range ticker.C {
			t.CheckFlush()
		}
	}()
}

// Add - Adding query to table
func (t *Table) Add(text string) {
	t.mu.Lock()
	defer t.mu.Unlock()
	t.count++
	t.Rows = append(t.Rows, text)
	if len(t.Rows) >= t.FlushCount {
		t.Flush()
	}
}

// Empty - check if all tables are empty
func (c *Collector) Empty() bool {
	c.mu.Lock()
	defer c.mu.Unlock()
	for _, t := range c.Tables {
		if ok := t.Empty(); !ok {
			return false
		}
	}
	return true
}

// FlushAll - flush all tables to clickhouse
func (c *Collector) FlushAll() (count int) {
	c.mu.Lock()
	defer c.mu.Unlock()
	count = 0
	for _, t := range c.Tables {
		if ok := t.CheckFlush(); ok {
			count++
		}

	}
	return count
}

// WaitFlush - wait for flush all tables
func (c *Collector) WaitFlush() (err error) {
	return c.Sender.WaitFlush()
}

// AddTable - adding table to collector
func (c *Collector) AddTable(name string) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.addTable(name)
}

func (c *Collector) separateQuery(name string) (query string, params string) {
	items := strings.Split(name, "&")
	for _, p := range items {
		if HasPrefix(p, "query=") {
			query = p[6:]
		} else {
			params += "&" + p
		}
	}
	if len(params) > 0 {
		params = strings.TrimSpace(params[1:])
	}
	q, err := url.QueryUnescape(query)
	if err != nil {
		return "", name
	}
	return q, params
}

func (c *Collector) getFormat(query string) (format string) {
	format = formatValues
	f := regexGetFormat.FindSubmatch([]byte(query))
	if len(f) > 1 {
		format = strings.TrimSpace(string(f[1]))
	}
	return format
}

func (c *Collector) addTable(name string) *Table {
	t := NewTable(name, c.Sender, c.Count, c.FlushInterval)
	query, params := c.separateQuery(name)
	t.Query = query
	t.Params = params
	t.Format = c.getFormat(query)
	c.Tables[name] = t
	t.RunTimer()
	return t
}

// Push - adding query to collector with query params (with query) and rows
func (c *Collector) Push(params string, content string) {
	c.mu.RLock()
	table, ok := c.Tables[params]
	if ok {
		table.Add(content)
		c.mu.RUnlock()
		pushCounter.Inc()
		return
	}
	c.mu.RUnlock()
	c.mu.Lock()
	table, ok = c.Tables[params]
	if !ok {
		table = c.addTable(params)
	}
	table.Add(content)
	c.mu.Unlock()
	pushCounter.Inc()
}

// ParseQuery - parsing inbound query to unified format (params/query), content (query data)
func (c *Collector) ParseQuery(queryString string, body string) (params string, content string, insert bool) {
	i := strings.Index(queryString, "query=")
	if i >= 0 {
		if HasPrefix(queryString[i+6:], "insert") {
			insert = true
		}
		var q string
		eoq := strings.Index(queryString[i+6:], "&")
		if eoq >= 0 {
			q = queryString[i+6 : eoq+6]
			params = queryString[:i] + queryString[eoq+7:]
		} else {
			q = queryString[i+6:]
			params = queryString[:i]
		}
		uq, err := url.QueryUnescape(q)
		if body != "" {
			uq += " " + body
		}
		if err != nil {
			return queryString, body, false
		}
		prefix, cnt := c.Parse(uq)
		if strings.HasSuffix(params, "&") || params == "" {
			params += "query=" + url.QueryEscape(strings.TrimSpace(prefix))
		} else {
			params += "&query=" + url.QueryEscape(strings.TrimSpace(prefix))
		}
		content = cnt
	} else {
		var q string
		q, content = c.Parse(body)
		q = strings.TrimSpace(q)
		if HasPrefix(q, "insert") {
			insert = true
		}
		if queryString != "" {
			params = queryString + "&query=" + url.QueryEscape(q)
		} else {
			params = "query=" + url.QueryEscape(q)
		}
	}
	return strings.TrimSpace(params), strings.TrimSpace(content), insert
}

// Parse - parsing text for query and data
func (c *Collector) Parse(text string) (prefix string, content string) {
	i := strings.Index(text, "FORMAT")
	k := strings.Index(text, "VALUES")
	if k == -1 {
		k = strings.Index(text, "values")
	}
	if i >= 0 && i < k {
		w := false
		off := -1
		for c := i + 7; c < len(text); c++ {
			if !w && text[c] != ' ' && text[c] != '\n' && text[c] != ';' {
				w = true
			}
			if w && (text[c] == ' ' || text[c] == '\n' || text[c] == ';') {
				off = c + 1
				break
			}
		}
		if off >= 0 {
			prefix = text[:off]
			content = text[off:]
		}
	} else {
		if k >= 0 {
			prefix = strings.TrimSpace(text[:k+6])
			content = strings.TrimSpace(text[k+6:])
		} else {
			off := regexFormat.FindStringSubmatchIndex(text)
			if len(off) > 3 {
				prefix = text[:off[3]]
				content = text[off[3]:]
			} else {
				off := regexValues.FindStringSubmatchIndex(text)
				if len(off) > 0 {
					prefix = text[:off[1]]
					content = text[off[1]:]
				} else {
					prefix = text
				}
			}
		}
	}
	return prefix, content
}
<commit_msg>Fixed collection of RowBinary rows<commit_after>package main

import (
	"net/url"
	"regexp"
	"strings"
	"sync"
	"time"
)

const formatValues = "values"
const formatTabSeparated = "tabseparated"

var regexFormat = regexp.MustCompile("(?i)format\\s\\S+(\\s+)")
var regexValues = regexp.MustCompile("(?i)\\svalues\\s")
var regexGetFormat = regexp.MustCompile("(?i)format\\s(\\S+)")

// Table - store query table info
type Table struct {
	Name          string
	Format        string
	Query         string
	Params        string
	Rows          []string
	count         int
	FlushCount    int
	FlushInterval int
	mu            sync.Mutex
	Sender        Sender
	// todo add Last Error
}

// Collector - query collector
type Collector struct {
	Tables        map[string]*Table
	mu            sync.RWMutex
	Count         int
	FlushInterval int
	Sender        Sender
}

// NewTable - default table constructor
func NewTable(name string, sender Sender, count int, interval int) (t *Table) {
	t = new(Table)
	t.Name = name
	t.Sender = sender
	t.FlushCount = count
	t.FlushInterval = interval
	return t
}

// NewCollector - default collector constructor
func NewCollector(sender Sender, count int, interval int) (c *Collector) {
	c = new(Collector)
	c.Sender = sender
	c.Tables = make(map[string]*Table)
	c.Count = count
	c.FlushInterval = interval
	return c
}

// Content - get text content of rowsfor query
func (t *Table) Content() string {
	rowDelimiter := "\n"
	if t.Format == "RowBinary" {
		rowDelimiter = ""
	}
	return t.Query + "\n" + strings.Join(t.Rows, rowDelimiter)
}

// Flush - sends collected data in table to clickhouse
func (t *Table) Flush() {
	req := ClickhouseRequest{
		Params:  t.Params,
		Query:   t.Query,
		Content: t.Content(),
		Count:   t.count,
	}
	t.Sender.Send(&req)
	t.Rows = make([]string, 0, t.FlushCount)
	t.count = 0
}

// CheckFlush - check if flush is need and sends data to clickhouse
func (t *Table) CheckFlush() bool {
	t.mu.Lock()
	defer t.mu.Unlock()
	if t.count > 0 {
		t.Flush()
		return true
	}
	return false
}

// Empty - Checks if table is empty
func (t *Table) Empty() bool {
	return t.GetCount() == 0
}

// GetCount - Checks if table is empty
func (t *Table) GetCount() int {
	t.mu.Lock()
	defer t.mu.Unlock()
	return t.count
}

// RunTimer - timer for periodical savings data
func (t *Table) RunTimer() {
	ticker := time.NewTicker(time.Millisecond * time.Duration(t.FlushInterval))
	go func() {
		for range ticker.C {
			t.CheckFlush()
		}
	}()
}

// Add - Adding query to table
func (t *Table) Add(text string) {
	t.mu.Lock()
	defer t.mu.Unlock()
	t.count++
	t.Rows = append(t.Rows, text)
	if len(t.Rows) >= t.FlushCount {
		t.Flush()
	}
}

// Empty - check if all tables are empty
func (c *Collector) Empty() bool {
	c.mu.Lock()
	defer c.mu.Unlock()
	for _, t := range c.Tables {
		if ok := t.Empty(); !ok {
			return false
		}
	}
	return true
}

// FlushAll - flush all tables to clickhouse
func (c *Collector) FlushAll() (count int) {
	c.mu.Lock()
	defer c.mu.Unlock()
	count = 0
	for _, t := range c.Tables {
		if ok := t.CheckFlush(); ok {
			count++
		}

	}
	return count
}

// WaitFlush - wait for flush all tables
func (c *Collector) WaitFlush() (err error) {
	return c.Sender.WaitFlush()
}

// AddTable - adding table to collector
func (c *Collector) AddTable(name string) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.addTable(name)
}

func (c *Collector) separateQuery(name string) (query string, params string) {
	items := strings.Split(name, "&")
	for _, p := range items {
		if HasPrefix(p, "query=") {
			query = p[6:]
		} else {
			params += "&" + p
		}
	}
	if len(params) > 0 {
		params = strings.TrimSpace(params[1:])
	}
	q, err := url.QueryUnescape(query)
	if err != nil {
		return "", name
	}
	return q, params
}

func (c *Collector) getFormat(query string) (format string) {
	format = formatValues
	f := regexGetFormat.FindSubmatch([]byte(query))
	if len(f) > 1 {
		format = strings.TrimSpace(string(f[1]))
	}
	return format
}

func (c *Collector) addTable(name string) *Table {
	t := NewTable(name, c.Sender, c.Count, c.FlushInterval)
	query, params := c.separateQuery(name)
	t.Query = query
	t.Params = params
	t.Format = c.getFormat(query)
	c.Tables[name] = t
	t.RunTimer()
	return t
}

// Push - adding query to collector with query params (with query) and rows
func (c *Collector) Push(params string, content string) {
	c.mu.RLock()
	table, ok := c.Tables[params]
	if ok {
		table.Add(content)
		c.mu.RUnlock()
		pushCounter.Inc()
		return
	}
	c.mu.RUnlock()
	c.mu.Lock()
	table, ok = c.Tables[params]
	if !ok {
		table = c.addTable(params)
	}
	table.Add(content)
	c.mu.Unlock()
	pushCounter.Inc()
}

// ParseQuery - parsing inbound query to unified format (params/query), content (query data)
func (c *Collector) ParseQuery(queryString string, body string) (params string, content string, insert bool) {
	i := strings.Index(queryString, "query=")
	if i >= 0 {
		if HasPrefix(queryString[i+6:], "insert") {
			insert = true
		}
		var q string
		eoq := strings.Index(queryString[i+6:], "&")
		if eoq >= 0 {
			q = queryString[i+6 : eoq+6]
			params = queryString[:i] + queryString[eoq+7:]
		} else {
			q = queryString[i+6:]
			params = queryString[:i]
		}
		uq, err := url.QueryUnescape(q)
		if body != "" {
			uq += " " + body
		}
		if err != nil {
			return queryString, body, false
		}
		prefix, cnt := c.Parse(uq)
		if strings.HasSuffix(params, "&") || params == "" {
			params += "query=" + url.QueryEscape(strings.TrimSpace(prefix))
		} else {
			params += "&query=" + url.QueryEscape(strings.TrimSpace(prefix))
		}
		content = cnt
	} else {
		var q string
		q, content = c.Parse(body)
		q = strings.TrimSpace(q)
		if HasPrefix(q, "insert") {
			insert = true
		}
		if queryString != "" {
			params = queryString + "&query=" + url.QueryEscape(q)
		} else {
			params = "query=" + url.QueryEscape(q)
		}
	}
	return strings.TrimSpace(params), strings.TrimSpace(content), insert
}

// Parse - parsing text for query and data
func (c *Collector) Parse(text string) (prefix string, content string) {
	i := strings.Index(text, "FORMAT")
	k := strings.Index(text, "VALUES")
	if k == -1 {
		k = strings.Index(text, "values")
	}
	if i >= 0 && i < k {
		w := false
		off := -1
		for c := i + 7; c < len(text); c++ {
			if !w && text[c] != ' ' && text[c] != '\n' && text[c] != ';' {
				w = true
			}
			if w && (text[c] == ' ' || text[c] == '\n' || text[c] == ';') {
				off = c + 1
				break
			}
		}
		if off >= 0 {
			prefix = text[:off]
			content = text[off:]
		}
	} else {
		if k >= 0 {
			prefix = strings.TrimSpace(text[:k+6])
			content = strings.TrimSpace(text[k+6:])
		} else {
			off := regexFormat.FindStringSubmatchIndex(text)
			if len(off) > 3 {
				prefix = text[:off[3]]
				content = text[off[3]:]
			} else {
				off := regexValues.FindStringSubmatchIndex(text)
				if len(off) > 0 {
					prefix = text[:off[1]]
					content = text[off[1]:]
				} else {
					prefix = text
				}
			}
		}
	}
	return prefix, content
}
<|endoftext|>


<commit_before>package manager

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

	gorun "github.com/micro/go-micro/v3/runtime"
	"github.com/micro/go-micro/v3/runtime/local/source/git"
	gostore "github.com/micro/go-micro/v3/store"
	"github.com/micro/micro/v3/service/auth"
	"github.com/micro/micro/v3/service/client"
	"github.com/micro/micro/v3/service/logger"
	"github.com/micro/micro/v3/service/runtime"
	"github.com/micro/micro/v3/service/runtime/builder"
	"github.com/micro/micro/v3/service/runtime/builder/golang"
	"github.com/micro/micro/v3/service/runtime/util/tar"
	"github.com/micro/micro/v3/service/store"
)

func (m *manager) buildAndRun(srv *service) {
	if err := m.build(srv); err != nil {
		return
	}

	srv.Status = runtime.Starting
	m.writeService(srv)

	if err := m.createServiceInRuntime(srv); err != nil {
		srv.Status = runtime.Error
		srv.Error = fmt.Sprintf("Error creating service: %v", err)
		m.writeService(srv)
	}
}

func (m *manager) buildAndUpdate(srv *service) {
	if err := m.build(srv); err != nil {
		return
	}

	srv.Status = runtime.Starting
	m.writeService(srv)

	if err := m.updateServiceInRuntime(srv); err != nil {
		srv.Status = runtime.Error
		srv.Error = fmt.Sprintf("Error updating service: %v", err)
		m.writeService(srv)
	}
}

func (m *manager) build(srv *service) error {
	// set the service status to building
	srv.Status = runtime.Building
	m.writeService(srv)

	// handleError will set the error status on the service
	handleError := func(err error, msg string) {
		srv.Status = runtime.Error
		srv.Error = fmt.Sprintf("%v: %v", msg, err)
		m.writeService(srv)
	}

	// load the source
	var source io.Reader
	var err error
	if strings.HasPrefix(srv.Service.Source, "source://") {
		// if the source was uploaded to the blob store, it'll have source:// as the prefix
		nsOpt := gostore.BlobNamespace(srv.Options.Namespace)
		source, err = store.DefaultBlobStore.Read(srv.Service.Source, nsOpt)
	} else {
		// the source will otherwise be a git remote, we'll clone it and then tar archive the result
		gitSrc, err := git.ParseSource(srv.Service.Source)
		if err != nil {
			handleError(err, "Error parsing git source")
			return err
		}
		if len(srv.Options.Entrypoint) == 0 {
			srv.Options.Entrypoint = gitSrc.Folder
		}

		// checkout the source
		gitSrc.Ref = srv.Service.Version
		dir, err := git.CheckoutSource(gitSrc, srv.Options.Secrets)
		if err != nil {
			handleError(err, "Error fetching git source")
			return err
		}

		// archive the source so it can be passed to the builder
		source, err = tar.Archive(dir)
	}
	if err != nil {
		handleError(err, "Error loading source")
		return err
	}

	// if we're building the build service, override the default builder implementation to prevent
	// a circular dependancy
	bldr := builder.DefaultBuilder
	if srv.Service.Source == "github.com/m3o/services/build" {
		bldr, _ = golang.NewBuilder()
	}

	// build the source
	build, err := bldr.Build(source,
		builder.Archive("tar"),
		builder.Entrypoint(srv.Options.Entrypoint),
	)
	if err != nil {
		handleError(err, "Error building service")
		return err
	}

	// for the kubernetes runtime, the container needs to pull the source (it's not got access to the
	// local filesystem like the local runtime does). hence we'll upload the source to the blob store
	// which the cell (container) can then pull via the Runtime.Build.Read RPC.
	if m.Runtime.String() != "local" {
		nsOpt := gostore.BlobNamespace(srv.Options.Namespace)
		key := fmt.Sprintf("build://%v:%v", srv.Service.Name, srv.Service.Version)
		if err := store.DefaultBlobStore.Write(key, build, nsOpt); err != nil {
			handleError(err, "Error uploading build")
			return err
		}
	}

	return nil
}

func (m *manager) updateServiceInRuntime(srv *service) error {
	// construct the options
	options := []gorun.UpdateOption{
		gorun.UpdateEntrypoint(srv.Options.Entrypoint),
		gorun.UpdateNamespace(srv.Options.Namespace),
	}

	// add the secrets
	for key, value := range srv.Options.Secrets {
		options = append(options, gorun.UpdateSecret(key, value))
	}

	// update the service
	return m.Runtime.Update(srv.Service, options...)
}

// createServiceInRuntime will add all the required env vars and secrets and then create the service
func (m *manager) createServiceInRuntime(srv *service) error {
	// generate an auth account for the service to use
	acc, err := m.generateAccount(srv)
	if err != nil {
		return err
	}

	// construct the options
	options := []gorun.CreateOption{
		gorun.CreateEntrypoint(srv.Options.Entrypoint),
		gorun.CreateImage(srv.Options.Image),
		gorun.CreateType(srv.Options.Type),
		gorun.CreateNamespace(srv.Options.Namespace),
		gorun.WithArgs(srv.Options.Args...),
		gorun.WithCommand(srv.Options.Command...),
		gorun.WithEnv(m.runtimeEnv(srv.Service, srv.Options)),
	}

	// add the secrets
	for key, value := range srv.Options.Secrets {
		options = append(options, gorun.WithSecret(key, value))
	}

	// inject the credentials into the service if present
	if len(acc.ID) > 0 && len(acc.Secret) > 0 {
		options = append(options, gorun.WithSecret("MICRO_AUTH_ID", acc.ID))
		options = append(options, gorun.WithSecret("MICRO_AUTH_SECRET", acc.Secret))
	}

	// create the service
	return m.Runtime.Create(srv.Service, options...)
}

// checkoutSource will take a service and download the source into a temp directory. This source
// could be a git remote or a reference to some source in the blob store (used for running local
// code on the server).
func (m *manager) checkoutSource(srv *service) (string, error) {
	if strings.HasPrefix(srv.Service.Source, "source://") {
		return m.checkoutBlobSource(srv)
	} else {
		return m.checkoutGitSource(srv)
	}
}

// checkoutBlobSource will checkout source from the blob store using the key in the service's source
// attribute. It will then unarchive the source into a temp directory and return the location of
// said directory.
func (m *manager) checkoutBlobSource(srv *service) (string, error) {
	nsOpt := gostore.BlobNamespace(srv.Options.Namespace)
	source, err := store.DefaultBlobStore.Read(srv.Service.Source, nsOpt)
	if err != nil {
		return "", err
	}

	dir, err := ioutil.TempDir(os.TempDir(), "blob-*")
	if err != nil {
		return "", err
	}

	if err := tar.Unarchive(source, dir); err != nil {
		return "", err
	}

	return dir, nil
}

// checkoutGitSource will download source from a git remote into a temp dir and then return the
// location of that temp directory
func (m *manager) checkoutGitSource(srv *service) (string, error) {
	gitSrc, err := git.ParseSource(srv.Service.Source)
	if err != nil {
		return "", err
	}
	gitSrc.Ref = srv.Service.Version

	dir, err := git.CheckoutSource(gitSrc, srv.Options.Secrets)
	if err != nil {
		return "", err
	}

	// the dir will contain the entire repo, however the use could've specified a subfolder within
	// that repo. this is the case for mono-repos
	if len(srv.Options.Entrypoint) == 0 {
		srv.Options.Entrypoint = gitSrc.Folder
	}

	return dir, nil
}

// runtimeEnv returns the environment variables which should  be used when creating a service.
func (m *manager) runtimeEnv(srv *gorun.Service, options *gorun.CreateOptions) []string {
	setEnv := func(p []string, env map[string]string) {
		for _, v := range p {
			parts := strings.Split(v, "=")
			if len(parts) <= 1 {
				continue
			}
			env[parts[0]] = strings.Join(parts[1:], "=")
		}
	}

	// overwrite any values
	env := map[string]string{
		// ensure a profile for the services isn't set, they
		// should use the default RPC clients
		"MICRO_PROFILE": "",
		// pass the service's name and version
		"MICRO_SERVICE_NAME":    srv.Name,
		"MICRO_SERVICE_VERSION": srv.Version,
		// set the proxy for the service to use (e.g. micro network)
		// using the proxy which has been configured for the runtime
		"MICRO_PROXY": client.DefaultClient.Options().Proxy,
	}

	// bind to port 8080, this is what the k8s tcp readiness check will use
	if runtime.DefaultRuntime.String() == "kubernetes" {
		env["MICRO_SERVICE_ADDRESS"] = ":8080"
	}

	// set the env vars provided
	setEnv(options.Env, env)

	// set the service namespace
	if len(options.Namespace) > 0 {
		env["MICRO_NAMESPACE"] = options.Namespace
	}

	// create a new env
	var vars []string
	for k, v := range env {
		vars = append(vars, k+"="+v)
	}

	// setup the runtime env
	return vars
}

func (m *manager) generateAccount(srv *service) (*auth.Account, error) {
	accName := srv.Service.Name + "-" + srv.Service.Version

	opts := []auth.GenerateOption{
		auth.WithIssuer(srv.Options.Namespace),
		auth.WithScopes("service"),
		auth.WithType("service"),
	}

	acc, err := auth.Generate(accName, opts...)
	if err != nil {
		if logger.V(logger.WarnLevel, logger.DefaultLogger) {
			logger.Warnf("Error generating account %v: %v", accName, err)
		}
		return nil, err
	}
	if logger.V(logger.DebugLevel, logger.DefaultLogger) {
		logger.Debugf("Generated auth account: %v, secret: [len: %v]", acc.ID, len(acc.Secret))
	}

	return acc, nil
}

// cleanupBlobStore deletes the source code and build from the blob store once the service finishes
// running.
func (m *manager) cleanupBlobStore(srv *service) {
	// delete the raw source code
	opt := gostore.BlobNamespace(srv.Options.Namespace)
	srcKey := fmt.Sprintf("source://%v:%v", srv.Service.Name, srv.Service.Version)
	if err := store.DefaultBlobStore.Delete(srcKey, opt); err != nil && err != store.ErrNotFound {
		logger.Warnf("Error deleting source %v: %v", srcKey, err)
	}

	// if there is no builder enabled, there won't be any build to delete
	if builder.DefaultBuilder == nil {
		return
	}

	// delete the binary
	buildKey := fmt.Sprintf("build://%v:%v", srv.Service.Name, srv.Service.Version)
	if err := store.DefaultBlobStore.Delete(buildKey, opt); err != nil && err != store.ErrNotFound {
		logger.Warnf("Error deleting build %v: %v", srcKey, err)
	}
}
<commit_msg>service/runtime/manager: add logging to build process (#1437)<commit_after>package manager

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

	gorun "github.com/micro/go-micro/v3/runtime"
	"github.com/micro/go-micro/v3/runtime/local/source/git"
	gostore "github.com/micro/go-micro/v3/store"
	"github.com/micro/micro/v3/service/auth"
	"github.com/micro/micro/v3/service/client"
	"github.com/micro/micro/v3/service/logger"
	"github.com/micro/micro/v3/service/runtime"
	"github.com/micro/micro/v3/service/runtime/builder"
	"github.com/micro/micro/v3/service/runtime/builder/golang"
	"github.com/micro/micro/v3/service/runtime/util/tar"
	"github.com/micro/micro/v3/service/store"
)

func (m *manager) buildAndRun(srv *service) {
	if err := m.build(srv); err != nil {
		return
	}

	srv.Status = runtime.Starting
	m.writeService(srv)

	if err := m.createServiceInRuntime(srv); err != nil {
		srv.Status = runtime.Error
		srv.Error = fmt.Sprintf("Error creating service: %v", err)
		m.writeService(srv)
	}
}

func (m *manager) buildAndUpdate(srv *service) {
	if err := m.build(srv); err != nil {
		return
	}

	srv.Status = runtime.Starting
	m.writeService(srv)

	if err := m.updateServiceInRuntime(srv); err != nil {
		srv.Status = runtime.Error
		srv.Error = fmt.Sprintf("Error updating service: %v", err)
		m.writeService(srv)
	}
}

func (m *manager) build(srv *service) error {
	logger.Infof("Preparing to build %v:%v", srv.Service.Name, srv.Service.Version)

	// set the service status to building
	srv.Status = runtime.Building
	m.writeService(srv)

	// handleError will set the error status on the service
	handleError := func(err error, msg string) {
		logger.Warnf("Build failed %v:%v: %v %v", srv.Service.Name, srv.Service.Version, msg, err)
		srv.Status = runtime.Error
		srv.Error = fmt.Sprintf("%v: %v", msg, err)
		m.writeService(srv)
	}

	// load the source
	var source io.Reader
	var err error
	if strings.HasPrefix(srv.Service.Source, "source://") {
		// if the source was uploaded to the blob store, it'll have source:// as the prefix
		nsOpt := gostore.BlobNamespace(srv.Options.Namespace)
		source, err = store.DefaultBlobStore.Read(srv.Service.Source, nsOpt)
	} else {
		// the source will otherwise be a git remote, we'll clone it and then tar archive the result
		gitSrc, err := git.ParseSource(srv.Service.Source)
		if err != nil {
			handleError(err, "Error parsing git source")
			return err
		}
		if len(srv.Options.Entrypoint) == 0 {
			srv.Options.Entrypoint = gitSrc.Folder
		}

		// checkout the source
		gitSrc.Ref = srv.Service.Version
		dir, err := git.CheckoutSource(gitSrc, srv.Options.Secrets)
		if err != nil {
			handleError(err, "Error fetching git source")
			return err
		}

		// archive the source so it can be passed to the builder
		source, err = tar.Archive(dir)
	}
	if err != nil {
		handleError(err, "Error loading source")
		return err
	}

	// if we're building the build service, override the default builder implementation to prevent
	// a circular dependancy
	bldr := builder.DefaultBuilder
	if srv.Service.Source == "github.com/m3o/services/build" {
		logger.Infof("Building build service using golang builder")

		var err error
		bldr, err = golang.NewBuilder()
		if err != nil {
			handleError(err, "Golang builder could not be configured")
			return err
		}
	}

	// build the source
	logger.Infof("Build starting %v:%v", srv.Service.Name, srv.Service.Version)
	build, err := bldr.Build(source,
		builder.Archive("tar"),
		builder.Entrypoint(srv.Options.Entrypoint),
	)
	logger.Infof("Build finished %v:%v %v", srv.Service.Name, srv.Service.Version, err)
	if err != nil {
		handleError(err, "Error building service")
		return err
	}

	// for the kubernetes runtime, the container needs to pull the source (it's not got access to the
	// local filesystem like the local runtime does). hence we'll upload the source to the blob store
	// which the cell (container) can then pull via the Runtime.Build.Read RPC.
	if m.Runtime.String() != "local" {
		logger.Infof("Uploading build %v:%v", srv.Service.Name, srv.Service.Version)
		nsOpt := gostore.BlobNamespace(srv.Options.Namespace)
		key := fmt.Sprintf("build://%v:%v", srv.Service.Name, srv.Service.Version)
		if err := store.DefaultBlobStore.Write(key, build, nsOpt); err != nil {
			handleError(err, "Error uploading build")
			return err
		}
	}

	return nil
}

func (m *manager) updateServiceInRuntime(srv *service) error {
	// construct the options
	options := []gorun.UpdateOption{
		gorun.UpdateEntrypoint(srv.Options.Entrypoint),
		gorun.UpdateNamespace(srv.Options.Namespace),
	}

	// add the secrets
	for key, value := range srv.Options.Secrets {
		options = append(options, gorun.UpdateSecret(key, value))
	}

	// update the service
	return m.Runtime.Update(srv.Service, options...)
}

// createServiceInRuntime will add all the required env vars and secrets and then create the service
func (m *manager) createServiceInRuntime(srv *service) error {
	// generate an auth account for the service to use
	acc, err := m.generateAccount(srv)
	if err != nil {
		return err
	}

	// construct the options
	options := []gorun.CreateOption{
		gorun.CreateEntrypoint(srv.Options.Entrypoint),
		gorun.CreateImage(srv.Options.Image),
		gorun.CreateType(srv.Options.Type),
		gorun.CreateNamespace(srv.Options.Namespace),
		gorun.WithArgs(srv.Options.Args...),
		gorun.WithCommand(srv.Options.Command...),
		gorun.WithEnv(m.runtimeEnv(srv.Service, srv.Options)),
	}

	// add the secrets
	for key, value := range srv.Options.Secrets {
		options = append(options, gorun.WithSecret(key, value))
	}

	// inject the credentials into the service if present
	if len(acc.ID) > 0 && len(acc.Secret) > 0 {
		options = append(options, gorun.WithSecret("MICRO_AUTH_ID", acc.ID))
		options = append(options, gorun.WithSecret("MICRO_AUTH_SECRET", acc.Secret))
	}

	// create the service
	return m.Runtime.Create(srv.Service, options...)
}

// checkoutSource will take a service and download the source into a temp directory. This source
// could be a git remote or a reference to some source in the blob store (used for running local
// code on the server).
func (m *manager) checkoutSource(srv *service) (string, error) {
	if strings.HasPrefix(srv.Service.Source, "source://") {
		return m.checkoutBlobSource(srv)
	} else {
		return m.checkoutGitSource(srv)
	}
}

// checkoutBlobSource will checkout source from the blob store using the key in the service's source
// attribute. It will then unarchive the source into a temp directory and return the location of
// said directory.
func (m *manager) checkoutBlobSource(srv *service) (string, error) {
	nsOpt := gostore.BlobNamespace(srv.Options.Namespace)
	source, err := store.DefaultBlobStore.Read(srv.Service.Source, nsOpt)
	if err != nil {
		return "", err
	}

	dir, err := ioutil.TempDir(os.TempDir(), "blob-*")
	if err != nil {
		return "", err
	}

	if err := tar.Unarchive(source, dir); err != nil {
		return "", err
	}

	return dir, nil
}

// checkoutGitSource will download source from a git remote into a temp dir and then return the
// location of that temp directory
func (m *manager) checkoutGitSource(srv *service) (string, error) {
	gitSrc, err := git.ParseSource(srv.Service.Source)
	if err != nil {
		return "", err
	}
	gitSrc.Ref = srv.Service.Version

	dir, err := git.CheckoutSource(gitSrc, srv.Options.Secrets)
	if err != nil {
		return "", err
	}

	// the dir will contain the entire repo, however the use could've specified a subfolder within
	// that repo. this is the case for mono-repos
	if len(srv.Options.Entrypoint) == 0 {
		srv.Options.Entrypoint = gitSrc.Folder
	}

	return dir, nil
}

// runtimeEnv returns the environment variables which should  be used when creating a service.
func (m *manager) runtimeEnv(srv *gorun.Service, options *gorun.CreateOptions) []string {
	setEnv := func(p []string, env map[string]string) {
		for _, v := range p {
			parts := strings.Split(v, "=")
			if len(parts) <= 1 {
				continue
			}
			env[parts[0]] = strings.Join(parts[1:], "=")
		}
	}

	// overwrite any values
	env := map[string]string{
		// ensure a profile for the services isn't set, they
		// should use the default RPC clients
		"MICRO_PROFILE": "",
		// pass the service's name and version
		"MICRO_SERVICE_NAME":    srv.Name,
		"MICRO_SERVICE_VERSION": srv.Version,
		// set the proxy for the service to use (e.g. micro network)
		// using the proxy which has been configured for the runtime
		"MICRO_PROXY": client.DefaultClient.Options().Proxy,
	}

	// bind to port 8080, this is what the k8s tcp readiness check will use
	if runtime.DefaultRuntime.String() == "kubernetes" {
		env["MICRO_SERVICE_ADDRESS"] = ":8080"
	}

	// set the env vars provided
	setEnv(options.Env, env)

	// set the service namespace
	if len(options.Namespace) > 0 {
		env["MICRO_NAMESPACE"] = options.Namespace
	}

	// create a new env
	var vars []string
	for k, v := range env {
		vars = append(vars, k+"="+v)
	}

	// setup the runtime env
	return vars
}

func (m *manager) generateAccount(srv *service) (*auth.Account, error) {
	accName := srv.Service.Name + "-" + srv.Service.Version

	opts := []auth.GenerateOption{
		auth.WithIssuer(srv.Options.Namespace),
		auth.WithScopes("service"),
		auth.WithType("service"),
	}

	acc, err := auth.Generate(accName, opts...)
	if err != nil {
		if logger.V(logger.WarnLevel, logger.DefaultLogger) {
			logger.Warnf("Error generating account %v: %v", accName, err)
		}
		return nil, err
	}
	if logger.V(logger.DebugLevel, logger.DefaultLogger) {
		logger.Debugf("Generated auth account: %v, secret: [len: %v]", acc.ID, len(acc.Secret))
	}

	return acc, nil
}

// cleanupBlobStore deletes the source code and build from the blob store once the service finishes
// running.
func (m *manager) cleanupBlobStore(srv *service) {
	// delete the raw source code
	opt := gostore.BlobNamespace(srv.Options.Namespace)
	srcKey := fmt.Sprintf("source://%v:%v", srv.Service.Name, srv.Service.Version)
	if err := store.DefaultBlobStore.Delete(srcKey, opt); err != nil && err != store.ErrNotFound {
		logger.Warnf("Error deleting source %v: %v", srcKey, err)
	}

	// if there is no builder enabled, there won't be any build to delete
	if builder.DefaultBuilder == nil {
		return
	}

	// delete the binary
	buildKey := fmt.Sprintf("build://%v:%v", srv.Service.Name, srv.Service.Version)
	if err := store.DefaultBlobStore.Delete(buildKey, opt); err != nil && err != store.ErrNotFound {
		logger.Warnf("Error deleting build %v: %v", srcKey, err)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, Rob Thornton
// All rights reserved.
// This source code is governed by a Simplied BSD-License. Please see the
// LICENSE included in this distribution for a copy of the full license
// or, if one is not included, you may also find a copy at
// http://opensource.org/licenses/BSD-2-Clause

package comp

import (
	"fmt"
	"os"
	"strconv"

	"github.com/rthornton128/calc/ast"
	"github.com/rthornton128/calc/parse"
	"github.com/rthornton128/calc/token"
)

type compiler struct {
	fp *os.File
}

func CompileFile(fname, src string) {

	var c compiler
	fp, err := os.Create(fname + ".c")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer fp.Close()

	f := parse.ParseFile(fname, src)
	if f == nil {
		os.Exit(1)
	}
	c.fp = fp
	c.compFile(f)
}

func (c *compiler) compNode(node ast.Node) int {
	switch n := node.(type) {
	case *ast.BasicLit:
		i, err := strconv.Atoi(n.Lit)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		return i
	case *ast.BinaryExpr:
		return c.compBinaryExpr(n)
	default:
		return 0 /* can't be reached */
	}
}

func (c *compiler) compBinaryExpr(b *ast.BinaryExpr) int {
	var tmp int

	tmp = c.compNode(b.List[0])

	for _, node := range b.List[1:] {
		switch b.Op {
		case token.ADD:
			tmp += c.compNode(node)
		case token.SUB:
			tmp -= c.compNode(node)
		case token.MUL:
			tmp *= c.compNode(node)
		case token.QUO:
			tmp /= c.compNode(node)
		case token.REM:
			tmp %= c.compNode(node)
		}
	}

	return tmp
}

func (c *compiler) compFile(f *ast.File) {
	fmt.Fprintln(c.fp, "#include <stdio.h>")
	fmt.Fprintln(c.fp, "int main(void) {")
	fmt.Fprintf(c.fp, "printf(\"%%d\", %d);\n", c.compNode(f.Scope.Lookup("main")))
	fmt.Fprintln(c.fp, "return 0;")
	fmt.Fprintln(c.fp, "}")
}
<commit_msg>implement initial function declaration code<commit_after>// Copyright (c) 2014, Rob Thornton
// All rights reserved.
// This source code is governed by a Simplied BSD-License. Please see the
// LICENSE included in this distribution for a copy of the full license
// or, if one is not included, you may also find a copy at
// http://opensource.org/licenses/BSD-2-Clause

package comp

import (
	"fmt"
	"os"
	"strconv"

	"github.com/rthornton128/calc/ast"
	"github.com/rthornton128/calc/parse"
	"github.com/rthornton128/calc/token"
)

type compiler struct {
	fp *os.File
}

func CompileFile(fname, src string) {

	var c compiler
	fp, err := os.Create(fname + ".c")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer fp.Close()

	f := parse.ParseFile(fname, src)
	if f == nil {
		os.Exit(1)
	}
	c.fp = fp
	c.compFile(f)
}

func (c *compiler) compNode(node ast.Node) int {
	switch n := node.(type) {
	case *ast.BasicLit:
		i, err := strconv.Atoi(n.Lit)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		return i
	case *ast.BinaryExpr:
		return c.compBinaryExpr(n)
	default:
		return 0 /* can't be reached */
	}
}

func (c *compiler) compBinaryExpr(b *ast.BinaryExpr) int {
	var tmp int

	tmp = c.compNode(b.List[0])

	for _, node := range b.List[1:] {
		switch b.Op {
		case token.ADD:
			tmp += c.compNode(node)
		case token.SUB:
			tmp -= c.compNode(node)
		case token.MUL:
			tmp *= c.compNode(node)
		case token.QUO:
			tmp /= c.compNode(node)
		case token.REM:
			tmp %= c.compNode(node)
		}
	}

	return tmp
}

func (c *compiler) compDecl(ob *ast.Object) {
	fmt.Fprintf(c.fp, "%s %s(void) {\n", ob.Type.Name, ob.Name)
	fmt.Fprintf(c.fp, "printf(\"%%d\", %d);\n", c.compNode(ob.Value))
	fmt.Fprintf(c.fp, "return *(int32_t *)eax;\n")
	fmt.Fprintln(c.fp, "}")
}

func (c *compiler) compFile(f *ast.File) {
	fmt.Fprintln(c.fp, "#include <stdio.h>")
	fmt.Fprintln(c.fp, "#include \"runtime.h\"")
	c.compDecl(f.Scope.Lookup("main"))
}
<|endoftext|>


<commit_before>package sms // import "github.com/mndrix/sms-over-xmpp"

import (
	"encoding/xml"
	"fmt"
	"log"
	"strings"

	"github.com/mndrix/go-xco"
	"github.com/pkg/errors"
)

func Main(config Config) {
	opts := xco.Options{
		Name:         config.ComponentName(),
		SharedSecret: config.SharedSecret(),
		Address:      fmt.Sprintf("%s:%d", config.XmppHost(), config.XmppPort()),
	}
	c, err := xco.NewComponent(opts)
	if err != nil {
		panic(err)
	}

	// Uppercase Echo Component
	c.MessageHandler = func(c *xco.Component, m *xco.Message) error {
		log.Printf("Message: %+v", m)
		if m.Body == "" {
			log.Printf("  ignoring message with empty body")
			return nil
		}
		resp := &xco.Message{
			Header: xco.Header{
				From: m.To,
				To:   m.From,
				ID:   m.ID,
			},
			Subject: m.Subject,
			Thread:  m.Thread,
			Type:    m.Type,
			Body:    strings.ToUpper(m.Body),
			XMLName: m.XMLName,
		}
		log.Printf("Responding: %+v", resp)
		return errors.Wrap(c.Send(resp), "sending response")
	}
	c.PresenceHandler = func(c *xco.Component, p *xco.Presence) error {
		log.Printf("Presence: %+v", p)
		return nil
	}
	c.IqHandler = func(c *xco.Component, iq *xco.Iq) error {
		log.Printf("Iq: %+v", iq)
		return nil
	}
	c.UnknownHandler = func(c *xco.Component, x *xml.StartElement) error {
		log.Printf("Unknown: %+v", x)
		return nil
	}

	err = c.Run()
	if err != nil {
		log.Printf("ERROR: Run: %s", err)
	}
}
<commit_msg>Use Message.Response() to craft our reply<commit_after>package sms // import "github.com/mndrix/sms-over-xmpp"

import (
	"encoding/xml"
	"fmt"
	"log"
	"strings"

	"github.com/mndrix/go-xco"
	"github.com/pkg/errors"
)

func Main(config Config) {
	opts := xco.Options{
		Name:         config.ComponentName(),
		SharedSecret: config.SharedSecret(),
		Address:      fmt.Sprintf("%s:%d", config.XmppHost(), config.XmppPort()),
	}
	c, err := xco.NewComponent(opts)
	if err != nil {
		panic(err)
	}

	// Uppercase Echo Component
	c.MessageHandler = func(c *xco.Component, m *xco.Message) error {
		log.Printf("Message: %+v", m)
		if m.Body == "" {
			log.Printf("  ignoring message with empty body")
			return nil
		}
		resp := m.Response()
		resp.Body = strings.ToUpper(m.Body)
		log.Printf("Responding: %+v", resp)
		return errors.Wrap(c.Send(resp), "sending response")
	}
	c.PresenceHandler = func(c *xco.Component, p *xco.Presence) error {
		log.Printf("Presence: %+v", p)
		return nil
	}
	c.IqHandler = func(c *xco.Component, iq *xco.Iq) error {
		log.Printf("Iq: %+v", iq)
		return nil
	}
	c.UnknownHandler = func(c *xco.Component, x *xml.StartElement) error {
		log.Printf("Unknown: %+v", x)
		return nil
	}

	err = c.Run()
	if err != nil {
		log.Printf("ERROR: Run: %s", err)
	}
}
<|endoftext|>


<commit_before>package Golf

import (
	"io"
	"net/http"
	"net/http/httptest"
	"testing"
)

func makeTestHTTPRequest(body io.Reader) *http.Request {
	req, err := http.NewRequest("GET", "/foo/bar", body)
	if err != nil {
		return nil
	}
	return req
}

func TestContextCreate(t *testing.T) {
	r := makeTestHttpRequest(nil)
	w := httptest.NewRecorder()
	app := New()
	ctx := NewContext(r, w, app)
	if ctx == nil {
		t.Errorf("Can not create context.")
	}
}

func TestCookieSet(t *testing.T) {
	r := makeTestHttpRequest(nil)
	w := httptest.NewRecorder()
	app := New()
	ctx := NewContext(r, w, app)
	ctx.SetCookie("foo", "bar", 0)
	ctx.Send()
	if w.HeaderMap.Get("Set-Cookie") != `foo=bar; Path=/` {
		t.Errorf("Cookie test failed: %q != %q", w.HeaderMap.Get("Set-Cookie"), `foo=bar; Path=/`)
	}
}
<commit_msg>[fix] Fixed undefined method call.<commit_after>package Golf

import (
	"io"
	"net/http"
	"net/http/httptest"
	"testing"
)

func makeTestHTTPRequest(body io.Reader) *http.Request {
	req, err := http.NewRequest("GET", "/foo/bar", body)
	if err != nil {
		return nil
	}
	return req
}

func TestContextCreate(t *testing.T) {
	r := makeTestHTTPRequest(nil)
	w := httptest.NewRecorder()
	app := New()
	ctx := NewContext(r, w, app)
	if ctx == nil {
		t.Errorf("Can not create context.")
	}
}

func TestCookieSet(t *testing.T) {
	r := makeTestHTTPRequest(nil)
	w := httptest.NewRecorder()
	app := New()
	ctx := NewContext(r, w, app)
	ctx.SetCookie("foo", "bar", 0)
	ctx.Send()
	if w.HeaderMap.Get("Set-Cookie") != `foo=bar; Path=/` {
		t.Errorf("Cookie test failed: %q != %q", w.HeaderMap.Get("Set-Cookie"), `foo=bar; Path=/`)
	}
}
<|endoftext|>


<commit_before>package gin

import (
	"errors"
	"html/template"
	"net/http"
	"net/http/httptest"
	"testing"
)

// TestContextParamsGet tests that a parameter can be parsed from the URL.
func TestContextParamsByName(t *testing.T) {
	req, _ := http.NewRequest("GET", "/test/alexandernyquist", nil)
	w := httptest.NewRecorder()
	name := ""

	r := Default()
	r.GET("/test/:name", func(c *Context) {
		name = c.Params.ByName("name")
	})

	r.ServeHTTP(w, req)

	if name != "alexandernyquist" {
		t.Errorf("Url parameter was not correctly parsed. Should be alexandernyquist, was %s.", name)
	}
}

// TestContextSetGet tests that a parameter is set correctly on the
// current context and can be retrieved using Get.
func TestContextSetGet(t *testing.T) {
	req, _ := http.NewRequest("GET", "/test", nil)
	w := httptest.NewRecorder()

	r := Default()
	r.GET("/test", func(c *Context) {
		// Key should be lazily created
		if c.Keys != nil {
			t.Error("Keys should be nil")
		}

		// Set
		c.Set("foo", "bar")

		v, err := c.Get("foo")
		if err != nil {
			t.Errorf("Error on exist key")
		}
		if v != "bar" {
			t.Errorf("Value should be bar, was %s", v)
		}
	})

	r.ServeHTTP(w, req)
}

// TestContextJSON tests that the response is serialized as JSON
// and Content-Type is set to application/json
func TestContextJSON(t *testing.T) {
	req, _ := http.NewRequest("GET", "/test", nil)
	w := httptest.NewRecorder()

	r := Default()
	r.GET("/test", func(c *Context) {
		c.JSON(200, H{"foo": "bar"})
	})

	r.ServeHTTP(w, req)

	if w.Body.String() != "{\"foo\":\"bar\"}\n" {
		t.Errorf("Response should be {\"foo\":\"bar\"}, was: %s", w.Body.String())
	}

	if w.HeaderMap.Get("Content-Type") != "application/json" {
		t.Errorf("Content-Type should be application/json, was %s", w.HeaderMap.Get("Content-Type"))
	}
}

// TestContextHTML tests that the response executes the templates
// and responds with Content-Type set to text/html
func TestContextHTML(t *testing.T) {
	req, _ := http.NewRequest("GET", "/test", nil)
	w := httptest.NewRecorder()

	r := Default()
	templ, _ := template.New("t").Parse(`Hello {{.Name}}`)
	r.SetHTMLTemplate(templ)

	type TestData struct{ Name string }

	r.GET("/test", func(c *Context) {
		c.HTML(200, "t", TestData{"alexandernyquist"})
	})

	r.ServeHTTP(w, req)

	if w.Body.String() != "Hello alexandernyquist" {
		t.Errorf("Response should be Hello alexandernyquist, was: %s", w.Body.String())
	}

	if w.HeaderMap.Get("Content-Type") != "text/html" {
		t.Errorf("Content-Type should be text/html, was %s", w.HeaderMap.Get("Content-Type"))
	}
}

// TestContextString tests that the response is returned
// with Content-Type set to text/plain
func TestContextString(t *testing.T) {
	req, _ := http.NewRequest("GET", "/test", nil)
	w := httptest.NewRecorder()

	r := Default()
	r.GET("/test", func(c *Context) {
		c.String(200, "test")
	})

	r.ServeHTTP(w, req)

	if w.Body.String() != "test" {
		t.Errorf("Response should be test, was: %s", w.Body.String())
	}

	if w.HeaderMap.Get("Content-Type") != "text/plain" {
		t.Errorf("Content-Type should be text/plain, was %s", w.HeaderMap.Get("Content-Type"))
	}
}

// TestHandlerFunc - ensure that custom middleware works properly
func TestHandlerFunc(t *testing.T) {

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

	r := Default()
	var stepsPassed int = 0

	r.Use(func(context *Context) {
		stepsPassed += 1
		context.Next()
		stepsPassed += 1
	})

	r.ServeHTTP(w, req)

	if w.Code != 404 {
		t.Errorf("Response code should be Not found, was: %s", w.Code)
	}

	if stepsPassed != 2 {
		t.Errorf("Falied to switch context in handler function: %s", stepsPassed)
	}
}

// TestBadAbortHandlersChain - ensure that Abort after switch context will not interrupt pending handlers
func TestBadAbortHandlersChain(t *testing.T) {

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

	r := Default()
	var stepsPassed int = 0

	r.Use(func(context *Context) {
		stepsPassed += 1
		context.Next()
		stepsPassed += 1
		// after check and abort
		context.Abort(409)
	},
		func(context *Context) {
			stepsPassed += 1
			context.Next()
			stepsPassed += 1
			context.Abort(403)
		},
	)

	r.ServeHTTP(w, req)

	if w.Code != 403 {
		t.Errorf("Response code should be Forbiden, was: %s", w.Code)
	}

	if stepsPassed != 4 {
		t.Errorf("Falied to switch context in handler function: %s", stepsPassed)
	}
}

// TestAbortHandlersChain - ensure that Abort interrupt used middlewares in fifo order
func TestAbortHandlersChain(t *testing.T) {

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

	r := Default()
	var stepsPassed int = 0

	r.Use(func(context *Context) {
		stepsPassed += 1
		context.Abort(409)
	},
		func(context *Context) {
			stepsPassed += 1
			context.Next()
			stepsPassed += 1
		},
	)

	r.ServeHTTP(w, req)

	if w.Code != 409 {
		t.Errorf("Response code should be Conflict, was: %s", w.Code)
	}

	if stepsPassed != 1 {
		t.Errorf("Falied to switch context in handler function: %s", stepsPassed)
	}
}

// TestFailHandlersChain - ensure that Fail interrupt used middlewares in fifo order as
// as well as Abort
func TestFailHandlersChain(t *testing.T) {

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

	r := Default()
	var stepsPassed int = 0

	r.Use(func(context *Context) {
		stepsPassed += 1

		context.Fail(500, errors.New("foo"))
	},
		func(context *Context) {
			stepsPassed += 1
			context.Next()
			stepsPassed += 1
		},
	)

	r.ServeHTTP(w, req)

	if w.Code != 500 {
		t.Errorf("Response code should be Server error, was: %s", w.Code)
	}

	if stepsPassed != 1 {
		t.Errorf("Falied to switch context in handler function: %s", stepsPassed)
	}

}
<commit_msg>Added test cases for context file, data, XML response writers.<commit_after>package gin

import (
	"errors"
	"html/template"
	"net/http"
	"net/http/httptest"
	"testing"
)

// TestContextParamsGet tests that a parameter can be parsed from the URL.
func TestContextParamsByName(t *testing.T) {
	req, _ := http.NewRequest("GET", "/test/alexandernyquist", nil)
	w := httptest.NewRecorder()
	name := ""

	r := Default()
	r.GET("/test/:name", func(c *Context) {
		name = c.Params.ByName("name")
	})

	r.ServeHTTP(w, req)

	if name != "alexandernyquist" {
		t.Errorf("Url parameter was not correctly parsed. Should be alexandernyquist, was %s.", name)
	}
}

// TestContextSetGet tests that a parameter is set correctly on the
// current context and can be retrieved using Get.
func TestContextSetGet(t *testing.T) {
	req, _ := http.NewRequest("GET", "/test", nil)
	w := httptest.NewRecorder()

	r := Default()
	r.GET("/test", func(c *Context) {
		// Key should be lazily created
		if c.Keys != nil {
			t.Error("Keys should be nil")
		}

		// Set
		c.Set("foo", "bar")

		v, err := c.Get("foo")
		if err != nil {
			t.Errorf("Error on exist key")
		}
		if v != "bar" {
			t.Errorf("Value should be bar, was %s", v)
		}
	})

	r.ServeHTTP(w, req)
}

// TestContextJSON tests that the response is serialized as JSON
// and Content-Type is set to application/json
func TestContextJSON(t *testing.T) {
	req, _ := http.NewRequest("GET", "/test", nil)
	w := httptest.NewRecorder()

	r := Default()
	r.GET("/test", func(c *Context) {
		c.JSON(200, H{"foo": "bar"})
	})

	r.ServeHTTP(w, req)

	if w.Body.String() != "{\"foo\":\"bar\"}\n" {
		t.Errorf("Response should be {\"foo\":\"bar\"}, was: %s", w.Body.String())
	}

	if w.HeaderMap.Get("Content-Type") != "application/json" {
		t.Errorf("Content-Type should be application/json, was %s", w.HeaderMap.Get("Content-Type"))
	}
}

// TestContextHTML tests that the response executes the templates
// and responds with Content-Type set to text/html
func TestContextHTML(t *testing.T) {
	req, _ := http.NewRequest("GET", "/test", nil)
	w := httptest.NewRecorder()

	r := Default()
	templ, _ := template.New("t").Parse(`Hello {{.Name}}`)
	r.SetHTMLTemplate(templ)

	type TestData struct{ Name string }

	r.GET("/test", func(c *Context) {
		c.HTML(200, "t", TestData{"alexandernyquist"})
	})

	r.ServeHTTP(w, req)

	if w.Body.String() != "Hello alexandernyquist" {
		t.Errorf("Response should be Hello alexandernyquist, was: %s", w.Body.String())
	}

	if w.HeaderMap.Get("Content-Type") != "text/html" {
		t.Errorf("Content-Type should be text/html, was %s", w.HeaderMap.Get("Content-Type"))
	}
}

// TestContextString tests that the response is returned
// with Content-Type set to text/plain
func TestContextString(t *testing.T) {
	req, _ := http.NewRequest("GET", "/test", nil)
	w := httptest.NewRecorder()

	r := Default()
	r.GET("/test", func(c *Context) {
		c.String(200, "test")
	})

	r.ServeHTTP(w, req)

	if w.Body.String() != "test" {
		t.Errorf("Response should be test, was: %s", w.Body.String())
	}

	if w.HeaderMap.Get("Content-Type") != "text/plain" {
		t.Errorf("Content-Type should be text/plain, was %s", w.HeaderMap.Get("Content-Type"))
	}
}

// TestContextXML tests that the response is serialized as XML
// and Content-Type is set to application/xml
func TestContextXML(t *testing.T) {
	req, _ := http.NewRequest("GET", "/test", nil)
	w := httptest.NewRecorder()

	r := Default()
	r.GET("/test", func(c *Context) {
		c.XML(200, H{"foo": "bar"})
	})

	r.ServeHTTP(w, req)

	if w.Body.String() != "<map><foo>bar</foo></map>" {
		t.Errorf("Response should be <map><foo>bar</foo></map>, was: %s", w.Body.String())
	}

	if w.HeaderMap.Get("Content-Type") != "application/xml" {
		t.Errorf("Content-Type should be application/xml, was %s", w.HeaderMap.Get("Content-Type"))
	}
}

// TestContextData tests that the response can be written from `bytesting`
// with specified MIME type
func TestContextData(t *testing.T) {
	req, _ := http.NewRequest("GET", "/test/csv", nil)
	w := httptest.NewRecorder()

	r := Default()
	r.GET("/test/csv", func(c *Context) {
		c.Data(200, "text/csv", []byte(`foo,bar`))
	})

	r.ServeHTTP(w, req)

	if w.Body.String() != "foo,bar" {
		t.Errorf("Response should be foo&bar, was: %s", w.Body.String())
	}

	if w.HeaderMap.Get("Content-Type") != "text/csv" {
		t.Errorf("Content-Type should be text/csv, was %s", w.HeaderMap.Get("Content-Type"))
	}
}

func TestContextFile(t *testing.T) {
	req, _ := http.NewRequest("GET", "/test/file", nil)
	w := httptest.NewRecorder()

	r := Default()
	r.GET("/test/file", func(c *Context) {
		c.File("./gin.go")
	})

	r.ServeHTTP(w, req)

	bodyAsString := w.Body.String()

	if len(bodyAsString) == 0 {
		t.Errorf("Got empty body instead of file data")
	}

	if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" {
		t.Errorf("Content-Type should be text/plain; charset=utf-8, was %s", w.HeaderMap.Get("Content-Type"))
	}
}

// TestHandlerFunc - ensure that custom middleware works properly
func TestHandlerFunc(t *testing.T) {

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

	r := Default()
	var stepsPassed int = 0

	r.Use(func(context *Context) {
		stepsPassed += 1
		context.Next()
		stepsPassed += 1
	})

	r.ServeHTTP(w, req)

	if w.Code != 404 {
		t.Errorf("Response code should be Not found, was: %s", w.Code)
	}

	if stepsPassed != 2 {
		t.Errorf("Falied to switch context in handler function: %s", stepsPassed)
	}
}

// TestBadAbortHandlersChain - ensure that Abort after switch context will not interrupt pending handlers
func TestBadAbortHandlersChain(t *testing.T) {

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

	r := Default()
	var stepsPassed int = 0

	r.Use(func(context *Context) {
		stepsPassed += 1
		context.Next()
		stepsPassed += 1
		// after check and abort
		context.Abort(409)
	},
		func(context *Context) {
			stepsPassed += 1
			context.Next()
			stepsPassed += 1
			context.Abort(403)
		},
	)

	r.ServeHTTP(w, req)

	if w.Code != 403 {
		t.Errorf("Response code should be Forbiden, was: %s", w.Code)
	}

	if stepsPassed != 4 {
		t.Errorf("Falied to switch context in handler function: %s", stepsPassed)
	}
}

// TestAbortHandlersChain - ensure that Abort interrupt used middlewares in fifo order
func TestAbortHandlersChain(t *testing.T) {

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

	r := Default()
	var stepsPassed int = 0

	r.Use(func(context *Context) {
		stepsPassed += 1
		context.Abort(409)
	},
		func(context *Context) {
			stepsPassed += 1
			context.Next()
			stepsPassed += 1
		},
	)

	r.ServeHTTP(w, req)

	if w.Code != 409 {
		t.Errorf("Response code should be Conflict, was: %s", w.Code)
	}

	if stepsPassed != 1 {
		t.Errorf("Falied to switch context in handler function: %s", stepsPassed)
	}
}

// TestFailHandlersChain - ensure that Fail interrupt used middlewares in fifo order as
// as well as Abort
func TestFailHandlersChain(t *testing.T) {

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

	r := Default()
	var stepsPassed int = 0

	r.Use(func(context *Context) {
		stepsPassed += 1

		context.Fail(500, errors.New("foo"))
	},
		func(context *Context) {
			stepsPassed += 1
			context.Next()
			stepsPassed += 1
		},
	)

	r.ServeHTTP(w, req)

	if w.Code != 500 {
		t.Errorf("Response code should be Server error, was: %s", w.Code)
	}

	if stepsPassed != 1 {
		t.Errorf("Falied to switch context in handler function: %s", stepsPassed)
	}

}
<|endoftext|>