<commit_before>package conf

import (
	"encoding/json"
	"errors"
	"strings"

	"io"
	"v2ray.com/core"
	"v2ray.com/core/common/loader"
	v2net "v2ray.com/core/common/net"
)

var (
	inboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
		"dokodemo-door": func() interface{} { return new(DokodemoConfig) },
		"http":          func() interface{} { return new(HttpServerConfig) },
		"shadowsocks":   func() interface{} { return new(ShadowsocksServerConfig) },
		"socks":         func() interface{} { return new(SocksServerConfig) },
		"vmess":         func() interface{} { return new(VMessInboundConfig) },
	}, "protocol", "settings")

	outboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
		"blackhole":   func() interface{} { return new(BlackholeConfig) },
		"freedom":     func() interface{} { return new(FreedomConfig) },
		"shadowsocks": func() interface{} { return new(ShadowsocksClientConfig) },
		"vmess":       func() interface{} { return new(VMessOutboundConfig) },
	}, "protocol", "settings")
)

type InboundConnectionConfig struct {
	Port          uint16          `json:"port"`
	Listen        *Address        `json:"listen"`
	Protocol      string          `json:"protocol"`
	StreamSetting *StreamConfig   `json:"streamSettings"`
	Settings      json.RawMessage `json:"settings"`
	AllowPassive  bool            `json:"allowPassive"`
}

func (this *InboundConnectionConfig) Build() (*core.InboundConnectionConfig, error) {
	config := new(core.InboundConnectionConfig)
	config.PortRange = &v2net.PortRange{
		From: uint32(this.Port),
		To:   uint32(this.Port),
	}
	if this.Listen != nil {
		if this.Listen.Family().IsDomain() {
			return nil, errors.New("Point: Unable to listen on domain address: " + this.Listen.Domain())
		}
		config.ListenOn = this.Listen.Build()
	}
	if this.StreamSetting != nil {
		ts, err := this.StreamSetting.Build()
		if err != nil {
			return nil, err
		}
		config.StreamSettings = ts
	}
	config.AllowPassiveConnection = this.AllowPassive

	jsonConfig, err := inboundConfigLoader.LoadWithID(this.Settings, this.Protocol)
	if err != nil {
		return nil, errors.New("Failed to load inbound config: " + err.Error())
	}
	ts, err := jsonConfig.(Buildable).Build()
	if err != nil {
		return nil, err
	}
	config.Settings = ts
	return config, nil
}

type OutboundConnectionConfig struct {
	Protocol      string          `json:"protocol"`
	SendThrough   *Address        `json:"sendThrough"`
	StreamSetting *StreamConfig   `json:"streamSettings"`
	ProxySettings *ProxyConfig    `json:"proxySettings"`
	Settings      json.RawMessage `json:"settings"`
}

func (this *OutboundConnectionConfig) Build() (*core.OutboundConnectionConfig, error) {
	config := new(core.OutboundConnectionConfig)
	rawConfig, err := outboundConfigLoader.LoadWithID(this.Settings, this.Protocol)
	if err != nil {
		return nil, errors.New("Failed to parse outbound config: " + err.Error())
	}
	ts, err := rawConfig.(Buildable).Build()
	if err != nil {
		return nil, err
	}
	config.Settings = ts

	if this.SendThrough != nil {
		address := this.SendThrough
		if address.Family().IsDomain() {
			return nil, errors.New("Point: Unable to send through: " + address.String())
		}
		config.SendThrough = address.Build()
	}
	if this.StreamSetting != nil {
		ss, err := this.StreamSetting.Build()
		if err != nil {
			return nil, err
		}
		config.StreamSettings = ss
	}
	if this.ProxySettings != nil {
		ps, err := this.ProxySettings.Build()
		if err != nil {
			return nil, errors.New("Outbound: invalid proxy settings: " + err.Error())
		}
		config.ProxySettings = ps
	}
	return config, nil
}

type InboundDetourAllocationConfig struct {
	Strategy    string  `json:"strategy"`
	Concurrency *uint32 `json:"concurrency"`
	RefreshMin  *uint32 `json:"refresh"`
}

func (this *InboundDetourAllocationConfig) Build() (*core.AllocationStrategy, error) {
	config := new(core.AllocationStrategy)
	switch strings.ToLower(this.Strategy) {
	case "always":
		config.Type = core.AllocationStrategy_Always
	case "random":
		config.Type = core.AllocationStrategy_Random
	case "external":
		config.Type = core.AllocationStrategy_External
	default:
		return nil, errors.New("Unknown allocation strategy: " + this.Strategy)
	}
	if this.Concurrency != nil {
		config.Concurrency = &core.AllocationStrategyConcurrency{
			Value: *this.Concurrency,
		}
	}

	if this.RefreshMin != nil {
		config.Refresh = &core.AllocationStrategyRefresh{
			Value: *this.RefreshMin,
		}
	}

	return config, nil
}

type InboundDetourConfig struct {
	Protocol      string                         `json:"protocol"`
	PortRange     *PortRange                     `json:"port"`
	ListenOn      *Address                       `json:"listen"`
	Settings      json.RawMessage                `json:"settings"`
	Tag           string                         `json:"tag"`
	Allocation    *InboundDetourAllocationConfig `json:"allocate"`
	StreamSetting *StreamConfig                  `json:"streamSettings"`
	AllowPassive  bool                           `json:"allowPassive"`
}

func (this *InboundDetourConfig) Build() (*core.InboundConnectionConfig, error) {
	config := new(core.InboundConnectionConfig)
	if this.PortRange == nil {
		return nil, errors.New("Point: Port range not specified in InboundDetour.")
	}
	config.PortRange = this.PortRange.Build()

	if this.ListenOn != nil {
		if this.ListenOn.Family().IsDomain() {
			return nil, errors.New("Point: Unable to listen on domain address: " + this.ListenOn.Domain())
		}
		config.ListenOn = this.ListenOn.Build()
	}
	config.Tag = this.Tag
	if this.Allocation != nil {
		as, err := this.Allocation.Build()
		if err != nil {
			return nil, err
		}
		config.AllocationStrategy = as
	}
	if this.StreamSetting != nil {
		ss, err := this.StreamSetting.Build()
		if err != nil {
			return nil, err
		}
		config.StreamSettings = ss
	}
	config.AllowPassiveConnection = this.AllowPassive

	rawConfig, err := inboundConfigLoader.LoadWithID(this.Settings, this.Protocol)
	if err != nil {
		return nil, errors.New("Failed to load inbound detour config: " + err.Error())
	}
	ts, err := rawConfig.(Buildable).Build()
	if err != nil {
		return nil, err
	}
	config.Settings = ts
	return config, nil
}

type OutboundDetourConfig struct {
	Protocol      string          `json:"protocol"`
	SendThrough   *Address        `json:"sendThrough"`
	Tag           string          `json:"tag"`
	Settings      json.RawMessage `json:"settings"`
	StreamSetting *StreamConfig   `json:"streamSettings"`
	ProxySettings *ProxyConfig    `json:"proxySettings"`
}

func (this *OutboundDetourConfig) Build() (*core.OutboundConnectionConfig, error) {
	config := new(core.OutboundConnectionConfig)
	config.Tag = this.Tag

	if this.SendThrough != nil {
		address := this.SendThrough
		if address.Family().IsDomain() {
			return nil, errors.New("Point: Unable to send through: " + address.String())
		}
		config.SendThrough = address.Build()
	}

	if this.StreamSetting != nil {
		ss, err := this.StreamSetting.Build()
		if err != nil {
			return nil, err
		}
		config.StreamSettings = ss
	}

	rawConfig, err := outboundConfigLoader.LoadWithID(this.Settings, this.Protocol)
	if err != nil {
		return nil, errors.New("Failed to parse to outbound detour config: " + err.Error())
	}
	ts, err := rawConfig.(Buildable).Build()
	if err != nil {
		return nil, err
	}

	if this.ProxySettings != nil {
		ps, err := this.ProxySettings.Build()
		if err != nil {
			return nil, errors.New("OutboundDetour: invalid proxy settings: " + err.Error())
		}
		config.ProxySettings = ps
	}
	config.Settings = ts
	return config, nil
}

type Config struct {
	Port            uint16                    `json:"port"` // Port of this Point server.
	LogConfig       *LogConfig                `json:"log"`
	RouterConfig    *RouterConfig             `json:"routing"`
	DNSConfig       *DnsConfig                `json:"dns"`
	InboundConfig   *InboundConnectionConfig  `json:"inbound"`
	OutboundConfig  *OutboundConnectionConfig `json:"outbound"`
	InboundDetours  []InboundDetourConfig     `json:"inboundDetour"`
	OutboundDetours []OutboundDetourConfig    `json:"outboundDetour"`
	Transport       *TransportConfig          `json:"transport"`
}

func (this *Config) Build() (*core.Config, error) {
	config := new(core.Config)

	if this.LogConfig != nil {
		config.Log = this.LogConfig.Build()
	}

	if this.Transport != nil {
		ts, err := this.Transport.Build()
		if err != nil {
			return nil, err
		}
		config.Transport = ts
	}

	if this.RouterConfig != nil {
		routerConfig, err := this.RouterConfig.Build()
		if err != nil {
			return nil, err
		}
		config.App = append(config.App, loader.NewTypedSettings(routerConfig))
	}

	if this.DNSConfig != nil {
		config.App = append(config.App, loader.NewTypedSettings(this.DNSConfig.Build()))
	}

	if this.InboundConfig == nil {
		return nil, errors.New("No inbound config specified.")
	}

	if this.InboundConfig.Port == 0 && this.Port > 0 {
		this.InboundConfig.Port = this.Port
	}

	ic, err := this.InboundConfig.Build()
	if err != nil {
		return nil, err
	}
	config.Inbound = append(config.Inbound, ic)

	for _, rawInboundConfig := range this.InboundDetours {
		ic, err := rawInboundConfig.Build()
		if err != nil {
			return nil, err
		}
		config.Inbound = append(config.Inbound, ic)
	}

	oc, err := this.OutboundConfig.Build()
	if err != nil {
		return nil, err
	}
	config.Outbound = append(config.Outbound, oc)

	for _, rawOutboundConfig := range this.OutboundDetours {
		oc, err := rawOutboundConfig.Build()
		if err != nil {
			return nil, err
		}
		config.Outbound = append(config.Outbound, oc)
	}

	return config, nil
}

func init() {
	core.RegisterConfigLoader(core.ConfigFormat_JSON, func(input io.Reader) (*core.Config, error) {
		jsonConfig := &Config{}
		decoder := json.NewDecoder(input)
		err := decoder.Decode(jsonConfig)
		if err != nil {
			return nil, errors.New("Point: Failed to load server config: " + err.Error())
		}

		return jsonConfig.Build()
	})
}
<commit_msg>tag for default inbound and outbound<commit_after>package conf

import (
	"encoding/json"
	"errors"
	"strings"

	"io"
	"v2ray.com/core"
	"v2ray.com/core/common/loader"
	v2net "v2ray.com/core/common/net"
)

var (
	inboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
		"dokodemo-door": func() interface{} { return new(DokodemoConfig) },
		"http":          func() interface{} { return new(HttpServerConfig) },
		"shadowsocks":   func() interface{} { return new(ShadowsocksServerConfig) },
		"socks":         func() interface{} { return new(SocksServerConfig) },
		"vmess":         func() interface{} { return new(VMessInboundConfig) },
	}, "protocol", "settings")

	outboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
		"blackhole":   func() interface{} { return new(BlackholeConfig) },
		"freedom":     func() interface{} { return new(FreedomConfig) },
		"shadowsocks": func() interface{} { return new(ShadowsocksClientConfig) },
		"vmess":       func() interface{} { return new(VMessOutboundConfig) },
	}, "protocol", "settings")
)

type InboundConnectionConfig struct {
	Port          uint16          `json:"port"`
	Listen        *Address        `json:"listen"`
	Protocol      string          `json:"protocol"`
	StreamSetting *StreamConfig   `json:"streamSettings"`
	Settings      json.RawMessage `json:"settings"`
	AllowPassive  bool            `json:"allowPassive"`
	Tag           string          `json:"tag"`
}

func (this *InboundConnectionConfig) Build() (*core.InboundConnectionConfig, error) {
	config := new(core.InboundConnectionConfig)
	config.PortRange = &v2net.PortRange{
		From: uint32(this.Port),
		To:   uint32(this.Port),
	}
	if this.Listen != nil {
		if this.Listen.Family().IsDomain() {
			return nil, errors.New("Point: Unable to listen on domain address: " + this.Listen.Domain())
		}
		config.ListenOn = this.Listen.Build()
	}
	if this.StreamSetting != nil {
		ts, err := this.StreamSetting.Build()
		if err != nil {
			return nil, err
		}
		config.StreamSettings = ts
	}
	config.AllowPassiveConnection = this.AllowPassive

	jsonConfig, err := inboundConfigLoader.LoadWithID(this.Settings, this.Protocol)
	if err != nil {
		return nil, errors.New("Failed to load inbound config: " + err.Error())
	}
	ts, err := jsonConfig.(Buildable).Build()
	if err != nil {
		return nil, err
	}
	config.Settings = ts
	if len(this.Tag) > 0 {
		config.Tag = this.Tag
	}
	return config, nil
}

type OutboundConnectionConfig struct {
	Protocol      string          `json:"protocol"`
	SendThrough   *Address        `json:"sendThrough"`
	StreamSetting *StreamConfig   `json:"streamSettings"`
	ProxySettings *ProxyConfig    `json:"proxySettings"`
	Settings      json.RawMessage `json:"settings"`
	Tag           string          `json:"tag"`
}

func (this *OutboundConnectionConfig) Build() (*core.OutboundConnectionConfig, error) {
	config := new(core.OutboundConnectionConfig)
	rawConfig, err := outboundConfigLoader.LoadWithID(this.Settings, this.Protocol)
	if err != nil {
		return nil, errors.New("Failed to parse outbound config: " + err.Error())
	}
	ts, err := rawConfig.(Buildable).Build()
	if err != nil {
		return nil, err
	}
	config.Settings = ts

	if this.SendThrough != nil {
		address := this.SendThrough
		if address.Family().IsDomain() {
			return nil, errors.New("Point: Unable to send through: " + address.String())
		}
		config.SendThrough = address.Build()
	}
	if this.StreamSetting != nil {
		ss, err := this.StreamSetting.Build()
		if err != nil {
			return nil, err
		}
		config.StreamSettings = ss
	}
	if this.ProxySettings != nil {
		ps, err := this.ProxySettings.Build()
		if err != nil {
			return nil, errors.New("Outbound: invalid proxy settings: " + err.Error())
		}
		config.ProxySettings = ps
	}
	if len(this.Tag) > 0 {
		config.Tag = this.Tag
	}
	return config, nil
}

type InboundDetourAllocationConfig struct {
	Strategy    string  `json:"strategy"`
	Concurrency *uint32 `json:"concurrency"`
	RefreshMin  *uint32 `json:"refresh"`
}

func (this *InboundDetourAllocationConfig) Build() (*core.AllocationStrategy, error) {
	config := new(core.AllocationStrategy)
	switch strings.ToLower(this.Strategy) {
	case "always":
		config.Type = core.AllocationStrategy_Always
	case "random":
		config.Type = core.AllocationStrategy_Random
	case "external":
		config.Type = core.AllocationStrategy_External
	default:
		return nil, errors.New("Unknown allocation strategy: " + this.Strategy)
	}
	if this.Concurrency != nil {
		config.Concurrency = &core.AllocationStrategyConcurrency{
			Value: *this.Concurrency,
		}
	}

	if this.RefreshMin != nil {
		config.Refresh = &core.AllocationStrategyRefresh{
			Value: *this.RefreshMin,
		}
	}

	return config, nil
}

type InboundDetourConfig struct {
	Protocol      string                         `json:"protocol"`
	PortRange     *PortRange                     `json:"port"`
	ListenOn      *Address                       `json:"listen"`
	Settings      json.RawMessage                `json:"settings"`
	Tag           string                         `json:"tag"`
	Allocation    *InboundDetourAllocationConfig `json:"allocate"`
	StreamSetting *StreamConfig                  `json:"streamSettings"`
	AllowPassive  bool                           `json:"allowPassive"`
}

func (this *InboundDetourConfig) Build() (*core.InboundConnectionConfig, error) {
	config := new(core.InboundConnectionConfig)
	if this.PortRange == nil {
		return nil, errors.New("Point: Port range not specified in InboundDetour.")
	}
	config.PortRange = this.PortRange.Build()

	if this.ListenOn != nil {
		if this.ListenOn.Family().IsDomain() {
			return nil, errors.New("Point: Unable to listen on domain address: " + this.ListenOn.Domain())
		}
		config.ListenOn = this.ListenOn.Build()
	}
	config.Tag = this.Tag
	if this.Allocation != nil {
		as, err := this.Allocation.Build()
		if err != nil {
			return nil, err
		}
		config.AllocationStrategy = as
	}
	if this.StreamSetting != nil {
		ss, err := this.StreamSetting.Build()
		if err != nil {
			return nil, err
		}
		config.StreamSettings = ss
	}
	config.AllowPassiveConnection = this.AllowPassive

	rawConfig, err := inboundConfigLoader.LoadWithID(this.Settings, this.Protocol)
	if err != nil {
		return nil, errors.New("Failed to load inbound detour config: " + err.Error())
	}
	ts, err := rawConfig.(Buildable).Build()
	if err != nil {
		return nil, err
	}
	config.Settings = ts
	return config, nil
}

type OutboundDetourConfig struct {
	Protocol      string          `json:"protocol"`
	SendThrough   *Address        `json:"sendThrough"`
	Tag           string          `json:"tag"`
	Settings      json.RawMessage `json:"settings"`
	StreamSetting *StreamConfig   `json:"streamSettings"`
	ProxySettings *ProxyConfig    `json:"proxySettings"`
}

func (this *OutboundDetourConfig) Build() (*core.OutboundConnectionConfig, error) {
	config := new(core.OutboundConnectionConfig)
	config.Tag = this.Tag

	if this.SendThrough != nil {
		address := this.SendThrough
		if address.Family().IsDomain() {
			return nil, errors.New("Point: Unable to send through: " + address.String())
		}
		config.SendThrough = address.Build()
	}

	if this.StreamSetting != nil {
		ss, err := this.StreamSetting.Build()
		if err != nil {
			return nil, err
		}
		config.StreamSettings = ss
	}

	rawConfig, err := outboundConfigLoader.LoadWithID(this.Settings, this.Protocol)
	if err != nil {
		return nil, errors.New("Failed to parse to outbound detour config: " + err.Error())
	}
	ts, err := rawConfig.(Buildable).Build()
	if err != nil {
		return nil, err
	}

	if this.ProxySettings != nil {
		ps, err := this.ProxySettings.Build()
		if err != nil {
			return nil, errors.New("OutboundDetour: invalid proxy settings: " + err.Error())
		}
		config.ProxySettings = ps
	}
	config.Settings = ts
	return config, nil
}

type Config struct {
	Port            uint16                    `json:"port"` // Port of this Point server.
	LogConfig       *LogConfig                `json:"log"`
	RouterConfig    *RouterConfig             `json:"routing"`
	DNSConfig       *DnsConfig                `json:"dns"`
	InboundConfig   *InboundConnectionConfig  `json:"inbound"`
	OutboundConfig  *OutboundConnectionConfig `json:"outbound"`
	InboundDetours  []InboundDetourConfig     `json:"inboundDetour"`
	OutboundDetours []OutboundDetourConfig    `json:"outboundDetour"`
	Transport       *TransportConfig          `json:"transport"`
}

func (this *Config) Build() (*core.Config, error) {
	config := new(core.Config)

	if this.LogConfig != nil {
		config.Log = this.LogConfig.Build()
	}

	if this.Transport != nil {
		ts, err := this.Transport.Build()
		if err != nil {
			return nil, err
		}
		config.Transport = ts
	}

	if this.RouterConfig != nil {
		routerConfig, err := this.RouterConfig.Build()
		if err != nil {
			return nil, err
		}
		config.App = append(config.App, loader.NewTypedSettings(routerConfig))
	}

	if this.DNSConfig != nil {
		config.App = append(config.App, loader.NewTypedSettings(this.DNSConfig.Build()))
	}

	if this.InboundConfig == nil {
		return nil, errors.New("No inbound config specified.")
	}

	if this.InboundConfig.Port == 0 && this.Port > 0 {
		this.InboundConfig.Port = this.Port
	}

	ic, err := this.InboundConfig.Build()
	if err != nil {
		return nil, err
	}
	config.Inbound = append(config.Inbound, ic)

	for _, rawInboundConfig := range this.InboundDetours {
		ic, err := rawInboundConfig.Build()
		if err != nil {
			return nil, err
		}
		config.Inbound = append(config.Inbound, ic)
	}

	oc, err := this.OutboundConfig.Build()
	if err != nil {
		return nil, err
	}
	config.Outbound = append(config.Outbound, oc)

	for _, rawOutboundConfig := range this.OutboundDetours {
		oc, err := rawOutboundConfig.Build()
		if err != nil {
			return nil, err
		}
		config.Outbound = append(config.Outbound, oc)
	}

	return config, nil
}

func init() {
	core.RegisterConfigLoader(core.ConfigFormat_JSON, func(input io.Reader) (*core.Config, error) {
		jsonConfig := &Config{}
		decoder := json.NewDecoder(input)
		err := decoder.Decode(jsonConfig)
		if err != nil {
			return nil, errors.New("Point: Failed to load server config: " + err.Error())
		}

		return jsonConfig.Build()
	})
}
<|endoftext|>


<commit_before>package handler_test

import (
	"encoding/json"
	"net/http"
	"time"

	"github.com/deiwin/praad-api/db"
	"github.com/deiwin/praad-api/db/model"
	. "github.com/deiwin/praad-api/handler"

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

type handlerFunc func(http.ResponseWriter, *http.Request)

var _ = Describe("OffersHandler", func() {
	var (
		mockOffersCollection db.Offers
		handler              handlerFunc
	)

	BeforeEach(func() {
		mockOffersCollection = &mockOffers{}
	})

	JustBeforeEach(func() {
		handler = Offers(mockOffersCollection)
	})

	Describe("GetForTimeRange", func() {
		Context("with simple mocked result from DB", func() {
			var (
				mockResult []*model.Offer
			)
			BeforeEach(func() {
				mockResult = []*model.Offer{&model.Offer{Title: "sometitle"}}
				mockOffersCollection = &mockOffers{
					func(startTime time.Time, endTime time.Time) (offers []*model.Offer, err error) {
						offers = mockResult
						return
					},
				}
			})

			It("should write the returned data to responsewriter", func(done Done) {
				defer close(done)
				handler(responseRecorder, request)
				// Expect(responseRecorder.Flushed).To(BeTrue()) // TODO check if this should be true
				var result []*model.Offer
				json.Unmarshal(responseRecorder.Body.Bytes(), &result)
				Expect(result).To(HaveLen(1))
				Expect(result[0].Title).To(Equal(mockResult[0].Title))
			})
		})
	})
})

type mockOffers struct {
	getForTimeRangeFunc func(time.Time, time.Time) ([]*model.Offer, error)
}

func (mock mockOffers) Insert(offersToInsert ...*model.Offer) (err error) {
	return
}

func (mock mockOffers) GetForTimeRange(startTime time.Time, endTime time.Time) (offers []*model.Offer, err error) {
	if mock.getForTimeRangeFunc != nil {
		offers, err = mock.getForTimeRangeFunc(startTime, endTime)
	}
	return
}
<commit_msg>add offer handler test for content-type:json<commit_after>package handler_test

import (
	"encoding/json"
	"net/http"
	"time"

	"github.com/deiwin/praad-api/db"
	"github.com/deiwin/praad-api/db/model"
	. "github.com/deiwin/praad-api/handler"

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

type handlerFunc func(http.ResponseWriter, *http.Request)

var _ = Describe("OffersHandler", func() {
	var (
		mockOffersCollection db.Offers
		handler              handlerFunc
	)

	BeforeEach(func() {
		mockOffersCollection = &mockOffers{}
	})

	JustBeforeEach(func() {
		handler = Offers(mockOffersCollection)
	})

	Describe("GetForTimeRange", func() {

		It("should return json", func(done Done) {
			defer close(done)
			handler(responseRecorder, request)
			contentTypes := responseRecorder.HeaderMap["Content-Type"]
			Expect(contentTypes).To(HaveLen(1))
			Expect(contentTypes[0]).To(Equal("application/json"))
			// TODO the header assertion could be made a custom matcher
		})

		Context("with simple mocked result from DB", func() {
			var (
				mockResult []*model.Offer
			)
			BeforeEach(func() {
				mockResult = []*model.Offer{&model.Offer{Title: "sometitle"}}
				mockOffersCollection = &mockOffers{
					func(startTime time.Time, endTime time.Time) (offers []*model.Offer, err error) {
						offers = mockResult
						return
					},
				}
			})

			It("should write the returned data to responsewriter", func(done Done) {
				defer close(done)
				handler(responseRecorder, request)
				// Expect(responseRecorder.Flushed).To(BeTrue()) // TODO check if this should be true
				var result []*model.Offer
				json.Unmarshal(responseRecorder.Body.Bytes(), &result)
				Expect(result).To(HaveLen(1))
				Expect(result[0].Title).To(Equal(mockResult[0].Title))
			})
		})
	})
})

type mockOffers struct {
	getForTimeRangeFunc func(time.Time, time.Time) ([]*model.Offer, error)
}

func (mock mockOffers) Insert(offersToInsert ...*model.Offer) (err error) {
	return
}

func (mock mockOffers) GetForTimeRange(startTime time.Time, endTime time.Time) (offers []*model.Offer, err error) {
	if mock.getForTimeRangeFunc != nil {
		offers, err = mock.getForTimeRangeFunc(startTime, endTime)
	}
	return
}
<|endoftext|>


<commit_before>package resource

import (
	"fmt"
	"log"
	"reflect"
	"strings"

	"github.com/davecgh/go-spew/spew"
	tfjson "github.com/hashicorp/terraform-json"
	testing "github.com/mitchellh/go-testing-interface"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func runPostTestDestroy(t testing.T, c TestCase, wd *plugintest.WorkingDir, factories map[string]func() (*schema.Provider, error), statePreDestroy *terraform.State) error {
	t.Helper()

	err := runProviderCommand(t, func() error {
		return wd.Destroy()
	}, wd, factories)
	if err != nil {
		return err
	}

	if c.CheckDestroy != nil {
		if err := c.CheckDestroy(statePreDestroy); err != nil {
			return err
		}
	}

	return nil
}

func runNewTest(t testing.T, c TestCase, helper *plugintest.Helper) {
	t.Helper()

	spewConf := spew.NewDefaultConfig()
	spewConf.SortKeys = true
	wd := helper.RequireNewWorkingDir(t)

	defer func() {
		var statePreDestroy *terraform.State
		var err error
		err = runProviderCommand(t, func() error {
			statePreDestroy, err = getState(t, wd)
			if err != nil {
				return err
			}
			return nil
		}, wd, c.ProviderFactories)
		if err != nil {
			t.Fatalf("Error retrieving state, there may be dangling resources: %s", err.Error())
			return
		}

		if !stateIsEmpty(statePreDestroy) {
			err := runPostTestDestroy(t, c, wd, c.ProviderFactories, statePreDestroy)
			if err != nil {
				t.Fatalf("Error running post-test destroy, there may be dangling resources: %s", err.Error())
			}
		}

		wd.Close()
	}()

	providerCfg, err := testProviderConfig(c)
	if err != nil {
		t.Fatal(err)
	}

	err = wd.SetConfig(providerCfg)
	if err != nil {
		t.Fatalf("Error setting test config: %s", err)
	}
	err = runProviderCommand(t, func() error {
		return wd.Init()
	}, wd, c.ProviderFactories)
	if err != nil {
		t.Fatalf("Error running init: %s", err.Error())
		return
	}

	// use this to track last step succesfully applied
	// acts as default for import tests
	var appliedCfg string

	for i, step := range c.Steps {
		if step.PreConfig != nil {
			step.PreConfig()
		}

		if step.SkipFunc != nil {
			skip, err := step.SkipFunc()
			if err != nil {
				t.Fatal(err)
			}
			if skip {
				log.Printf("[WARN] Skipping step %d/%d", i+1, len(c.Steps))
				continue
			}
		}

		if step.ImportState {
			err := testStepNewImportState(t, c, helper, wd, step, appliedCfg)
			if step.ExpectError != nil {
				if err == nil {
					t.Fatalf("Step %d/%d error running import: expected an error but got none", i+1, len(c.Steps))
				}
				if !step.ExpectError.MatchString(err.Error()) {
					t.Fatalf("Step %d/%d error running import, expected an error with pattern (%s), no match on: %s", i+1, len(c.Steps), step.ExpectError.String(), err)
				}
			} else {
				if err != nil {
					t.Fatalf("Step %d/%d error running import: %s", i+1, len(c.Steps), err)
				}
			}
			continue
		}

		if step.Config != "" {
			err := testStepNewConfig(t, c, wd, step)
			if step.ExpectError != nil {
				if err == nil {
					t.Fatalf("Step %d/%d, expected an error but got none", i+1, len(c.Steps))
				}
				if !step.ExpectError.MatchString(err.Error()) {
					t.Fatalf("Step %d/%d, expected an error with pattern, no match on: %s", i+1, len(c.Steps), err)
				}
			} else {
				if err != nil {
					t.Fatalf("Step %d/%d error: %s", i+1, len(c.Steps), err)
				}
			}
			appliedCfg = step.Config
			continue
		}

		t.Fatal("Unsupported test mode")
	}
}

func getState(t testing.T, wd *plugintest.WorkingDir) (*terraform.State, error) {
	t.Helper()

	jsonState, err := wd.State()
	if err != nil {
		return nil, err
	}
	state, err := shimStateFromJson(jsonState)
	if err != nil {
		t.Fatal(err)
	}
	return state, nil
}

func stateIsEmpty(state *terraform.State) bool {
	return state.Empty() || !state.HasResources()
}

func planIsEmpty(plan *tfjson.Plan) bool {
	for _, rc := range plan.ResourceChanges {
		if rc.Mode == tfjson.DataResourceMode {
			// Skip data sources as the current implementation ignores
			// existing state and they are all re-read every time
			continue
		}

		for _, a := range rc.Change.Actions {
			if a != tfjson.ActionNoop {
				return false
			}
		}
	}
	return true
}

func testIDRefresh(c TestCase, t testing.T, wd *plugintest.WorkingDir, step TestStep, r *terraform.ResourceState) error {
	t.Helper()

	spewConf := spew.NewDefaultConfig()
	spewConf.SortKeys = true

	// Build the state. The state is just the resource with an ID. There
	// are no attributes. We only set what is needed to perform a refresh.
	state := terraform.NewState()
	state.RootModule().Resources = make(map[string]*terraform.ResourceState)
	state.RootModule().Resources[c.IDRefreshName] = &terraform.ResourceState{}

	// Temporarily set the config to a minimal provider config for the refresh
	// test. After the refresh we can reset it.
	cfg, err := testProviderConfig(c)
	if err != nil {
		return err
	}
	err = wd.SetConfig(cfg)
	if err != nil {
		t.Fatalf("Error setting import test config: %s", err)
	}
	defer func() {
		err = wd.SetConfig(step.Config)
		if err != nil {
			t.Fatalf("Error resetting test config: %s", err)
		}
	}()

	// Refresh!
	err = runProviderCommand(t, func() error {
		err = wd.Refresh()
		if err != nil {
			t.Fatalf("Error running terraform refresh: %s", err)
		}
		state, err = getState(t, wd)
		if err != nil {
			return err
		}
		return nil
	}, wd, c.ProviderFactories)
	if err != nil {
		return err
	}

	// Verify attribute equivalence.
	actualR := state.RootModule().Resources[c.IDRefreshName]
	if actualR == nil {
		return fmt.Errorf("Resource gone!")
	}
	if actualR.Primary == nil {
		return fmt.Errorf("Resource has no primary instance")
	}
	actual := actualR.Primary.Attributes
	expected := r.Primary.Attributes
	// Remove fields we're ignoring
	for _, v := range c.IDRefreshIgnore {
		for k := range actual {
			if strings.HasPrefix(k, v) {
				delete(actual, k)
			}
		}
		for k := range expected {
			if strings.HasPrefix(k, v) {
				delete(expected, k)
			}
		}
	}

	if !reflect.DeepEqual(actual, expected) {
		// Determine only the different attributes
		for k, v := range expected {
			if av, ok := actual[k]; ok && v == av {
				delete(expected, k)
				delete(actual, k)
			}
		}

		spewConf := spew.NewDefaultConfig()
		spewConf.SortKeys = true
		return fmt.Errorf(
			"Attributes not equivalent. Difference is shown below. Top is actual, bottom is expected."+
				"\n\n%s\n\n%s",
			spewConf.Sdump(actual), spewConf.Sdump(expected))
	}

	return nil
}
<commit_msg>helper/resource: Remove data source exclusion from ExpectNonEmptyPlan handling<commit_after>package resource

import (
	"fmt"
	"log"
	"reflect"
	"strings"

	"github.com/davecgh/go-spew/spew"
	tfjson "github.com/hashicorp/terraform-json"
	testing "github.com/mitchellh/go-testing-interface"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func runPostTestDestroy(t testing.T, c TestCase, wd *plugintest.WorkingDir, factories map[string]func() (*schema.Provider, error), statePreDestroy *terraform.State) error {
	t.Helper()

	err := runProviderCommand(t, func() error {
		return wd.Destroy()
	}, wd, factories)
	if err != nil {
		return err
	}

	if c.CheckDestroy != nil {
		if err := c.CheckDestroy(statePreDestroy); err != nil {
			return err
		}
	}

	return nil
}

func runNewTest(t testing.T, c TestCase, helper *plugintest.Helper) {
	t.Helper()

	spewConf := spew.NewDefaultConfig()
	spewConf.SortKeys = true
	wd := helper.RequireNewWorkingDir(t)

	defer func() {
		var statePreDestroy *terraform.State
		var err error
		err = runProviderCommand(t, func() error {
			statePreDestroy, err = getState(t, wd)
			if err != nil {
				return err
			}
			return nil
		}, wd, c.ProviderFactories)
		if err != nil {
			t.Fatalf("Error retrieving state, there may be dangling resources: %s", err.Error())
			return
		}

		if !stateIsEmpty(statePreDestroy) {
			err := runPostTestDestroy(t, c, wd, c.ProviderFactories, statePreDestroy)
			if err != nil {
				t.Fatalf("Error running post-test destroy, there may be dangling resources: %s", err.Error())
			}
		}

		wd.Close()
	}()

	providerCfg, err := testProviderConfig(c)
	if err != nil {
		t.Fatal(err)
	}

	err = wd.SetConfig(providerCfg)
	if err != nil {
		t.Fatalf("Error setting test config: %s", err)
	}
	err = runProviderCommand(t, func() error {
		return wd.Init()
	}, wd, c.ProviderFactories)
	if err != nil {
		t.Fatalf("Error running init: %s", err.Error())
		return
	}

	// use this to track last step succesfully applied
	// acts as default for import tests
	var appliedCfg string

	for i, step := range c.Steps {
		if step.PreConfig != nil {
			step.PreConfig()
		}

		if step.SkipFunc != nil {
			skip, err := step.SkipFunc()
			if err != nil {
				t.Fatal(err)
			}
			if skip {
				log.Printf("[WARN] Skipping step %d/%d", i+1, len(c.Steps))
				continue
			}
		}

		if step.ImportState {
			err := testStepNewImportState(t, c, helper, wd, step, appliedCfg)
			if step.ExpectError != nil {
				if err == nil {
					t.Fatalf("Step %d/%d error running import: expected an error but got none", i+1, len(c.Steps))
				}
				if !step.ExpectError.MatchString(err.Error()) {
					t.Fatalf("Step %d/%d error running import, expected an error with pattern (%s), no match on: %s", i+1, len(c.Steps), step.ExpectError.String(), err)
				}
			} else {
				if err != nil {
					t.Fatalf("Step %d/%d error running import: %s", i+1, len(c.Steps), err)
				}
			}
			continue
		}

		if step.Config != "" {
			err := testStepNewConfig(t, c, wd, step)
			if step.ExpectError != nil {
				if err == nil {
					t.Fatalf("Step %d/%d, expected an error but got none", i+1, len(c.Steps))
				}
				if !step.ExpectError.MatchString(err.Error()) {
					t.Fatalf("Step %d/%d, expected an error with pattern, no match on: %s", i+1, len(c.Steps), err)
				}
			} else {
				if err != nil {
					t.Fatalf("Step %d/%d error: %s", i+1, len(c.Steps), err)
				}
			}
			appliedCfg = step.Config
			continue
		}

		t.Fatal("Unsupported test mode")
	}
}

func getState(t testing.T, wd *plugintest.WorkingDir) (*terraform.State, error) {
	t.Helper()

	jsonState, err := wd.State()
	if err != nil {
		return nil, err
	}
	state, err := shimStateFromJson(jsonState)
	if err != nil {
		t.Fatal(err)
	}
	return state, nil
}

func stateIsEmpty(state *terraform.State) bool {
	return state.Empty() || !state.HasResources()
}

func planIsEmpty(plan *tfjson.Plan) bool {
	for _, rc := range plan.ResourceChanges {
		for _, a := range rc.Change.Actions {
			if a != tfjson.ActionNoop {
				return false
			}
		}
	}
	return true
}

func testIDRefresh(c TestCase, t testing.T, wd *plugintest.WorkingDir, step TestStep, r *terraform.ResourceState) error {
	t.Helper()

	spewConf := spew.NewDefaultConfig()
	spewConf.SortKeys = true

	// Build the state. The state is just the resource with an ID. There
	// are no attributes. We only set what is needed to perform a refresh.
	state := terraform.NewState()
	state.RootModule().Resources = make(map[string]*terraform.ResourceState)
	state.RootModule().Resources[c.IDRefreshName] = &terraform.ResourceState{}

	// Temporarily set the config to a minimal provider config for the refresh
	// test. After the refresh we can reset it.
	cfg, err := testProviderConfig(c)
	if err != nil {
		return err
	}
	err = wd.SetConfig(cfg)
	if err != nil {
		t.Fatalf("Error setting import test config: %s", err)
	}
	defer func() {
		err = wd.SetConfig(step.Config)
		if err != nil {
			t.Fatalf("Error resetting test config: %s", err)
		}
	}()

	// Refresh!
	err = runProviderCommand(t, func() error {
		err = wd.Refresh()
		if err != nil {
			t.Fatalf("Error running terraform refresh: %s", err)
		}
		state, err = getState(t, wd)
		if err != nil {
			return err
		}
		return nil
	}, wd, c.ProviderFactories)
	if err != nil {
		return err
	}

	// Verify attribute equivalence.
	actualR := state.RootModule().Resources[c.IDRefreshName]
	if actualR == nil {
		return fmt.Errorf("Resource gone!")
	}
	if actualR.Primary == nil {
		return fmt.Errorf("Resource has no primary instance")
	}
	actual := actualR.Primary.Attributes
	expected := r.Primary.Attributes
	// Remove fields we're ignoring
	for _, v := range c.IDRefreshIgnore {
		for k := range actual {
			if strings.HasPrefix(k, v) {
				delete(actual, k)
			}
		}
		for k := range expected {
			if strings.HasPrefix(k, v) {
				delete(expected, k)
			}
		}
	}

	if !reflect.DeepEqual(actual, expected) {
		// Determine only the different attributes
		for k, v := range expected {
			if av, ok := actual[k]; ok && v == av {
				delete(expected, k)
				delete(actual, k)
			}
		}

		spewConf := spew.NewDefaultConfig()
		spewConf.SortKeys = true
		return fmt.Errorf(
			"Attributes not equivalent. Difference is shown below. Top is actual, bottom is expected."+
				"\n\n%s\n\n%s",
			spewConf.Sdump(actual), spewConf.Sdump(expected))
	}

	return nil
}
<|endoftext|>


<commit_before>package resource

import (
	"fmt"
	"log"
	"reflect"
	"strings"

	"github.com/davecgh/go-spew/spew"
	tfjson "github.com/hashicorp/terraform-json"
	tftest "github.com/hashicorp/terraform-plugin-test"
	testing "github.com/mitchellh/go-testing-interface"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func runPostTestDestroy(t testing.T, c TestCase, wd *tftest.WorkingDir, providers map[string]*schema.Provider) error {
	runProviderCommand(func() error {
		wd.RequireDestroy(t)
		return nil
	}, wd, defaultPluginServeOpts(wd, providers))

	if c.CheckDestroy != nil {
		var statePostDestroy *terraform.State
		runProviderCommand(func() error {
			statePostDestroy = getState(t, wd)
			return nil
		}, wd, defaultPluginServeOpts(wd, providers))

		if err := c.CheckDestroy(statePostDestroy); err != nil {
			return err
		}
	}

	return nil
}

func runNewTest(t testing.T, c TestCase, providers map[string]*schema.Provider, helper *tftest.Helper) {
	spewConf := spew.NewDefaultConfig()
	spewConf.SortKeys = true
	wd := helper.RequireNewWorkingDir(t)

	defer func() {
		var statePreDestroy *terraform.State
		runProviderCommand(func() error {
			statePreDestroy = getState(t, wd)
			return nil
		}, wd, defaultPluginServeOpts(wd, providers))

		if !stateIsEmpty(statePreDestroy) {
			runPostTestDestroy(t, c, wd, providers)
		}

		wd.Close()
	}()

	providerCfg := testProviderConfig(c)

	wd.RequireSetConfig(t, providerCfg)
	runProviderCommand(func() error {
		wd.RequireInit(t)
		return nil
	}, wd, defaultPluginServeOpts(wd, providers))

	// use this to track last step succesfully applied
	// acts as default for import tests
	var appliedCfg string

	for i, step := range c.Steps {
		if step.PreConfig != nil {
			step.PreConfig()
		}

		if step.SkipFunc != nil {
			skip, err := step.SkipFunc()
			if err != nil {
				t.Fatal(err)
			}
			if skip {
				log.Printf("[WARN] Skipping step %d", i)
				continue
			}
		}
		step.providers = providers

		if step.ImportState {
			err := testStepNewImportState(t, c, helper, wd, step, appliedCfg)
			if err != nil {
				t.Fatal(err)
			}
			continue
		}

		if step.Config != "" {
			err := testStepNewConfig(t, c, wd, step)
			if step.ExpectError != nil {
				if err == nil {
					t.Fatal("Expected an error but got none")
				}
				if !step.ExpectError.MatchString(err.Error()) {
					t.Fatalf("Expected an error with pattern, no match on: %s", err)
				}
			} else {
				if err != nil {
					t.Fatal(err)
				}
			}
			appliedCfg = step.Config
			continue
		}

		t.Fatal("Unsupported test mode")
	}
}

func getState(t testing.T, wd *tftest.WorkingDir) *terraform.State {
	jsonState := wd.RequireState(t)
	state, err := shimStateFromJson(jsonState)
	if err != nil {
		t.Fatal(err)
	}
	return state
}

func stateIsEmpty(state *terraform.State) bool {
	return state.Empty() || !state.HasResources()
}

func planIsEmpty(plan *tfjson.Plan) bool {
	for _, rc := range plan.ResourceChanges {
		if rc.Mode == tfjson.DataResourceMode {
			// Skip data sources as the current implementation ignores
			// existing state and they are all re-read every time
			continue
		}

		for _, a := range rc.Change.Actions {
			if a != tfjson.ActionNoop {
				return false
			}
		}
	}
	return true
}

func testIDRefresh(c TestCase, t testing.T, wd *tftest.WorkingDir, step TestStep, r *terraform.ResourceState) error {
	spewConf := spew.NewDefaultConfig()
	spewConf.SortKeys = true

	// Build the state. The state is just the resource with an ID. There
	// are no attributes. We only set what is needed to perform a refresh.
	state := terraform.NewState()
	state.RootModule().Resources = make(map[string]*terraform.ResourceState)
	state.RootModule().Resources[c.IDRefreshName] = &terraform.ResourceState{}

	// Temporarily set the config to a minimal provider config for the refresh
	// test. After the refresh we can reset it.
	cfg := testProviderConfig(c)
	wd.RequireSetConfig(t, cfg)
	defer wd.RequireSetConfig(t, step.Config)

	// Refresh!
	runProviderCommand(func() error {
		wd.RequireRefresh(t)
		return nil
	}, wd, defaultPluginServeOpts(wd, step.providers))
	state = getState(t, wd)

	// Verify attribute equivalence.
	actualR := state.RootModule().Resources[c.IDRefreshName]
	if actualR == nil {
		return fmt.Errorf("Resource gone!")
	}
	if actualR.Primary == nil {
		return fmt.Errorf("Resource has no primary instance")
	}
	actual := actualR.Primary.Attributes
	expected := r.Primary.Attributes
	// Remove fields we're ignoring
	for _, v := range c.IDRefreshIgnore {
		for k := range actual {
			if strings.HasPrefix(k, v) {
				delete(actual, k)
			}
		}
		for k := range expected {
			if strings.HasPrefix(k, v) {
				delete(expected, k)
			}
		}
	}

	if !reflect.DeepEqual(actual, expected) {
		// Determine only the different attributes
		for k, v := range expected {
			if av, ok := actual[k]; ok && v == av {
				delete(expected, k)
				delete(actual, k)
			}
		}

		spewConf := spew.NewDefaultConfig()
		spewConf.SortKeys = true
		return fmt.Errorf(
			"Attributes not equivalent. Difference is shown below. Top is actual, bottom is expected."+
				"\n\n%s\n\n%s",
			spewConf.Sdump(actual), spewConf.Sdump(expected))
	}

	return nil
}
<commit_msg>Fix TestIDRefresh to not timeout.<commit_after>package resource

import (
	"fmt"
	"log"
	"reflect"
	"strings"

	"github.com/davecgh/go-spew/spew"
	tfjson "github.com/hashicorp/terraform-json"
	tftest "github.com/hashicorp/terraform-plugin-test"
	testing "github.com/mitchellh/go-testing-interface"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func runPostTestDestroy(t testing.T, c TestCase, wd *tftest.WorkingDir, providers map[string]*schema.Provider) error {
	runProviderCommand(func() error {
		wd.RequireDestroy(t)
		return nil
	}, wd, defaultPluginServeOpts(wd, providers))

	if c.CheckDestroy != nil {
		var statePostDestroy *terraform.State
		runProviderCommand(func() error {
			statePostDestroy = getState(t, wd)
			return nil
		}, wd, defaultPluginServeOpts(wd, providers))

		if err := c.CheckDestroy(statePostDestroy); err != nil {
			return err
		}
	}

	return nil
}

func runNewTest(t testing.T, c TestCase, providers map[string]*schema.Provider, helper *tftest.Helper) {
	spewConf := spew.NewDefaultConfig()
	spewConf.SortKeys = true
	wd := helper.RequireNewWorkingDir(t)

	defer func() {
		var statePreDestroy *terraform.State
		runProviderCommand(func() error {
			statePreDestroy = getState(t, wd)
			return nil
		}, wd, defaultPluginServeOpts(wd, providers))

		if !stateIsEmpty(statePreDestroy) {
			runPostTestDestroy(t, c, wd, providers)
		}

		wd.Close()
	}()

	providerCfg := testProviderConfig(c)

	wd.RequireSetConfig(t, providerCfg)
	runProviderCommand(func() error {
		wd.RequireInit(t)
		return nil
	}, wd, defaultPluginServeOpts(wd, providers))

	// use this to track last step succesfully applied
	// acts as default for import tests
	var appliedCfg string

	for i, step := range c.Steps {
		if step.PreConfig != nil {
			step.PreConfig()
		}

		if step.SkipFunc != nil {
			skip, err := step.SkipFunc()
			if err != nil {
				t.Fatal(err)
			}
			if skip {
				log.Printf("[WARN] Skipping step %d", i)
				continue
			}
		}
		step.providers = providers

		if step.ImportState {
			err := testStepNewImportState(t, c, helper, wd, step, appliedCfg)
			if err != nil {
				t.Fatal(err)
			}
			continue
		}

		if step.Config != "" {
			err := testStepNewConfig(t, c, wd, step)
			if step.ExpectError != nil {
				if err == nil {
					t.Fatal("Expected an error but got none")
				}
				if !step.ExpectError.MatchString(err.Error()) {
					t.Fatalf("Expected an error with pattern, no match on: %s", err)
				}
			} else {
				if err != nil {
					t.Fatal(err)
				}
			}
			appliedCfg = step.Config
			continue
		}

		t.Fatal("Unsupported test mode")
	}
}

func getState(t testing.T, wd *tftest.WorkingDir) *terraform.State {
	jsonState := wd.RequireState(t)
	state, err := shimStateFromJson(jsonState)
	if err != nil {
		t.Fatal(err)
	}
	return state
}

func stateIsEmpty(state *terraform.State) bool {
	return state.Empty() || !state.HasResources()
}

func planIsEmpty(plan *tfjson.Plan) bool {
	for _, rc := range plan.ResourceChanges {
		if rc.Mode == tfjson.DataResourceMode {
			// Skip data sources as the current implementation ignores
			// existing state and they are all re-read every time
			continue
		}

		for _, a := range rc.Change.Actions {
			if a != tfjson.ActionNoop {
				return false
			}
		}
	}
	return true
}

func testIDRefresh(c TestCase, t testing.T, wd *tftest.WorkingDir, step TestStep, r *terraform.ResourceState) error {
	spewConf := spew.NewDefaultConfig()
	spewConf.SortKeys = true

	// Build the state. The state is just the resource with an ID. There
	// are no attributes. We only set what is needed to perform a refresh.
	state := terraform.NewState()
	state.RootModule().Resources = make(map[string]*terraform.ResourceState)
	state.RootModule().Resources[c.IDRefreshName] = &terraform.ResourceState{}

	// Temporarily set the config to a minimal provider config for the refresh
	// test. After the refresh we can reset it.
	cfg := testProviderConfig(c)
	wd.RequireSetConfig(t, cfg)
	defer wd.RequireSetConfig(t, step.Config)

	// Refresh!
	runProviderCommand(func() error {
		wd.RequireRefresh(t)
		state = getState(t, wd)
		return nil
	}, wd, defaultPluginServeOpts(wd, step.providers))

	// Verify attribute equivalence.
	actualR := state.RootModule().Resources[c.IDRefreshName]
	if actualR == nil {
		return fmt.Errorf("Resource gone!")
	}
	if actualR.Primary == nil {
		return fmt.Errorf("Resource has no primary instance")
	}
	actual := actualR.Primary.Attributes
	expected := r.Primary.Attributes
	// Remove fields we're ignoring
	for _, v := range c.IDRefreshIgnore {
		for k := range actual {
			if strings.HasPrefix(k, v) {
				delete(actual, k)
			}
		}
		for k := range expected {
			if strings.HasPrefix(k, v) {
				delete(expected, k)
			}
		}
	}

	if !reflect.DeepEqual(actual, expected) {
		// Determine only the different attributes
		for k, v := range expected {
			if av, ok := actual[k]; ok && v == av {
				delete(expected, k)
				delete(actual, k)
			}
		}

		spewConf := spew.NewDefaultConfig()
		spewConf.SortKeys = true
		return fmt.Errorf(
			"Attributes not equivalent. Difference is shown below. Top is actual, bottom is expected."+
				"\n\n%s\n\n%s",
			spewConf.Sdump(actual), spewConf.Sdump(expected))
	}

	return nil
}
<|endoftext|>


<commit_before>package helpoptimal

// import (
// 	"fmt"
// 	"unsafe"
// 	"sync/atomic"
// )

type key struct {
	value float64
	minValue0 float64
	minValue1 float64
	maxValue0 float64
	maxValue1 float64
	maxValue2 float64
}

type node struct {
}
<commit_msg>Key API from Concurrent Set<commit_after>package helpoptimal

import (
	"math"
	"math/rand"
	// "fmt"
	// "unsafe"
	// "sync/atomic"
)

type key struct {
	value float64
	minValue0 float64
	minValue1 float64
	maxValue0 float64
	maxValue1 float64
	maxValue2 float64
}

type node struct {
}

func newKey() *key {
	k := new(key)
	k.value = 0
	k.minValue0 = -math.MaxFloat64
	k.minValue1 = -0.95*math.MaxFloat64
	k.maxValue0 = math.MaxFloat64
	k.maxValue1 = 0.95*math.MaxFloat64
	k.maxValue2 = 0.9*math.MaxFloat64
	return k
}
func (k *key) compareTo(o *key) bool {
	return k.value < o.value
}
func (k *key) equals(o *key) bool {
	return k.value == o.value
}
func (k *key) getValue() float64 {
	return k.value
}
func (k *key) simpleNew(b *key) *key {
	if k.value < b.value {
		return b
	} else {
		return k
	}
}
func (k *key) randPoint(b *key) *key {
	nk := new (key)
	if k.value < b.value {
		nk.value = (rand.Float64()*k.value) + b.value
	} else {
		nk.value = (rand.Float64()*b.value) + k.value
	}
	return nk
}
func (k *key) newPoint(b *key) *key {
	nk := new (key)
	nk.value = k.value*0.5 + b.value*0.5
	return nk
}

<|endoftext|>


<commit_before>package steam

// listbuilder.go - Functions for building the list of servers & their details
// in resposne to a retrieval of all servers from the Steam Master server
// or in response to a user's specific query from the API.

import (
	"net"
	"strconv"
	"strings"
	"time"

	"github.com/syncore/a2sapi/src/db"
	"github.com/syncore/a2sapi/src/logger"
	"github.com/syncore/a2sapi/src/models"
	"github.com/syncore/a2sapi/src/steam/filters"
)

func buildServerList(data a2sData, addtoServerDB bool) (*models.APIServerList,
	error) {
	// Cannot ignore all three requests
	for _, g := range data.HostsGames {
		if g.IgnoreInfo && g.IgnorePlayers && g.IgnoreRules {
			return nil, logger.LogAppErrorf("Cannot ignore all three A2S_ requests!")
		}
	}
	successcount := 0
	var success bool
	srvDBhosts := make(map[string]string, len(data.HostsGames))
	sl := &models.APIServerList{
		Servers:       make([]models.APIServer, 0),
		FailedServers: make([]string, 0),
	}

	for host, game := range data.HostsGames {
		info, iok := data.Info[host]
		players, pok := data.Players[host]
		if players == nil {
			// return empty array instead of nil pointers (null) in json
			players = make([]models.SteamPlayerInfo, 0)
		}
		rules, rok := data.Rules[host]
		success = iok && rok && pok

		if game.IgnoreInfo {
			success = pok && rok
		}
		if game.IgnorePlayers {
			success = iok && rok
		}
		if game.IgnoreRules {
			rules = make(map[string]string, 0)
			success = iok && pok
		}
		if game.IgnoreInfo && game.IgnorePlayers {
			success = rok
		}
		if game.IgnoreInfo && game.IgnoreRules {
			success = pok
		}
		if game.IgnorePlayers && game.IgnoreRules {
			success = iok
		}

		if success {
			srv := models.APIServer{
				Game:            game.Name,
				Players:         players,
				FilteredPlayers: removeBuggedPlayers(players),
				Rules:           rules,
				Info:            info,
			}
			// Gametype support: gametype can be found in rules, info, or not
			// at all depending on the game (currently just for QuakeLive & Reflex)
			srv.Info.GameTypeShort, srv.Info.GameTypeFull = getGameType(game, srv)

			ip, port, serr := net.SplitHostPort(host)
			if serr == nil {
				srv.IP = ip
				srv.Host = host
				p, perr := strconv.Atoi(port)
				if perr == nil {
					srv.Port = p
				}
				if !strings.EqualFold(game.Name, filters.GameUnspecified.String()) {
					srvDBhosts[host] = game.Name
				}
				loc := make(chan models.DbCountry, 1)
				go db.CountryDB.GetCountryInfo(loc, ip)
				srv.CountryInfo = <-loc
			}
			sl.Servers = append(sl.Servers, srv)
			successcount++
		} else {
			sl.FailedServers = append(sl.FailedServers, host)
		}
	}

	sl.RetrievedAt = time.Now().Format("Mon Jan 2 15:04:05 2006 EST")
	sl.RetrievedTimeStamp = time.Now().Unix()
	sl.ServerCount = len(sl.Servers)
	sl.FailedCount = len(sl.FailedServers)

	if len(srvDBhosts) != 0 {
		go db.ServerDB.AddServersToDB(srvDBhosts)
		sl = setServerIDForList(sl)
	}

	logger.LogAppInfo(
		"Successfully queried (%d/%d) servers. %d timed out or otherwise failed.",
		successcount, len(data.HostsGames), sl.FailedCount)
	logger.WriteDebug("Server Queries: Successful: (%d/%d) servers\tFailed: %d servers",
		successcount, len(data.HostsGames), sl.FailedCount)
	return sl, nil
}

// removeBuggedPlayers filters the players to remove "bugged" or stuck players
// from the player list in games like Quake Live where certain servers do not
// correctly send the Steam de-auth message, causing "ghost" or phantom players
// to exist on servers.
func removeBuggedPlayers(players []models.SteamPlayerInfo) models.FilteredPlayerInfo {
	rpi := models.FilteredPlayerInfo{
		FilteredPlayerCount: len(players),
		FilteredPlayers:     players,
	}
	var filtered []models.SteamPlayerInfo
	// 4 hour threshold with no score; also can leave bots intact in list
	for _, p := range players {
		if p.Score == 0 && int(p.TimeConnectedSecs) > (3600*4) {
			continue
		}
		filtered = append(filtered, p)
	}
	// Empty players (nil) displayed as empty array in JSON, not null
	if len(filtered) == 0 {
		rpi.FilteredPlayerCount = 0
		rpi.FilteredPlayers = make([]models.SteamPlayerInfo, 0)
	} else {
		rpi.FilteredPlayerCount = len(filtered)
		rpi.FilteredPlayers = filtered
	}
	return rpi
}

func setServerIDForList(sl *models.APIServerList) *models.APIServerList {
	toSet := make(map[string]string, len(sl.Servers))
	for _, s := range sl.Servers {
		toSet[s.Host] = s.Game
	}
	result := make(chan map[string]int64, 1)
	go db.ServerDB.GetIDsForServerList(result, toSet)
	m := <-result

	for _, s := range sl.Servers {
		if m[s.Host] != 0 {
			s.ID = m[s.Host]
		}
	}
	return sl
}
<commit_msg>Fix for serverID always displaying as "0" in JSON (will only show 0 on the first ever run of application and server hasn't been added to database)<commit_after>package steam

// listbuilder.go - Functions for building the list of servers & their details
// in resposne to a retrieval of all servers from the Steam Master server
// or in response to a user's specific query from the API.

import (
	"net"
	"strconv"
	"strings"
	"time"

	"github.com/syncore/a2sapi/src/db"
	"github.com/syncore/a2sapi/src/logger"
	"github.com/syncore/a2sapi/src/models"
	"github.com/syncore/a2sapi/src/steam/filters"
)

func buildServerList(data a2sData, addtoServerDB bool) (*models.APIServerList,
	error) {
	// Cannot ignore all three requests
	for _, g := range data.HostsGames {
		if g.IgnoreInfo && g.IgnorePlayers && g.IgnoreRules {
			return nil, logger.LogAppErrorf("Cannot ignore all three A2S_ requests!")
		}
	}
	successcount := 0
	var success bool
	srvDBhosts := make(map[string]string, len(data.HostsGames))
	sl := &models.APIServerList{
		Servers:       make([]models.APIServer, 0),
		FailedServers: make([]string, 0),
	}

	for host, game := range data.HostsGames {
		info, iok := data.Info[host]
		players, pok := data.Players[host]
		if players == nil {
			// return empty array instead of nil pointers (null) in json
			players = make([]models.SteamPlayerInfo, 0)
		}
		rules, rok := data.Rules[host]
		success = iok && rok && pok

		if game.IgnoreInfo {
			success = pok && rok
		}
		if game.IgnorePlayers {
			success = iok && rok
		}
		if game.IgnoreRules {
			rules = make(map[string]string, 0)
			success = iok && pok
		}
		if game.IgnoreInfo && game.IgnorePlayers {
			success = rok
		}
		if game.IgnoreInfo && game.IgnoreRules {
			success = pok
		}
		if game.IgnorePlayers && game.IgnoreRules {
			success = iok
		}

		if success {
			srv := models.APIServer{
				Game:            game.Name,
				Players:         players,
				FilteredPlayers: removeBuggedPlayers(players),
				Rules:           rules,
				Info:            info,
			}
			// Gametype support: gametype can be found in rules, info, or not
			// at all depending on the game (currently just for QuakeLive & Reflex)
			srv.Info.GameTypeShort, srv.Info.GameTypeFull = getGameType(game, srv)

			ip, port, serr := net.SplitHostPort(host)
			if serr == nil {
				srv.IP = ip
				srv.Host = host
				p, perr := strconv.Atoi(port)
				if perr == nil {
					srv.Port = p
				}
				if !strings.EqualFold(game.Name, filters.GameUnspecified.String()) {
					srvDBhosts[host] = game.Name
				}
				loc := make(chan models.DbCountry, 1)
				go db.CountryDB.GetCountryInfo(loc, ip)
				srv.CountryInfo = <-loc
			}
			sl.Servers = append(sl.Servers, srv)
			successcount++
		} else {
			sl.FailedServers = append(sl.FailedServers, host)
		}
	}

	sl.RetrievedAt = time.Now().Format("Mon Jan 2 15:04:05 2006 EST")
	sl.RetrievedTimeStamp = time.Now().Unix()
	sl.ServerCount = len(sl.Servers)
	sl.FailedCount = len(sl.FailedServers)

	if len(srvDBhosts) != 0 {
		go db.ServerDB.AddServersToDB(srvDBhosts)
		sl.Servers = setServerIDsForList(sl.Servers)
	}

	logger.LogAppInfo(
		"Successfully queried (%d/%d) servers. %d timed out or otherwise failed.",
		successcount, len(data.HostsGames), sl.FailedCount)
	logger.WriteDebug("Server Queries: Successful: (%d/%d) servers\tFailed: %d servers",
		successcount, len(data.HostsGames), sl.FailedCount)
	return sl, nil
}

// removeBuggedPlayers filters the players to remove "bugged" or stuck players
// from the player list in games like Quake Live where certain servers do not
// correctly send the Steam de-auth message, causing "ghost" or phantom players
// to exist on servers.
func removeBuggedPlayers(players []models.SteamPlayerInfo) models.FilteredPlayerInfo {
	rpi := models.FilteredPlayerInfo{
		FilteredPlayerCount: len(players),
		FilteredPlayers:     players,
	}
	var filtered []models.SteamPlayerInfo
	// 4 hour threshold with no score; also can leave bots intact in list
	for _, p := range players {
		if p.Score == 0 && int(p.TimeConnectedSecs) > (3600*4) {
			continue
		}
		filtered = append(filtered, p)
	}
	// Empty players (nil) displayed as empty array in JSON, not null
	if len(filtered) == 0 {
		rpi.FilteredPlayerCount = 0
		rpi.FilteredPlayers = make([]models.SteamPlayerInfo, 0)
	} else {
		rpi.FilteredPlayerCount = len(filtered)
		rpi.FilteredPlayers = filtered
	}
	return rpi
}

func setServerIDsForList(servers []models.APIServer) []models.APIServer {
	toSet := make(map[string]string, len(servers))
	for _, s := range servers {
		toSet[s.Host] = s.Game
	}
	result := make(chan map[string]int64, 1)
	go db.ServerDB.GetIDsForServerList(result, toSet)
	m := <-result
	var srvswithids []models.APIServer

	for _, s := range servers {
		if m[s.Host] != 0 {
			s.ID = m[s.Host]
		}
		srvswithids = append(srvswithids, s)
	}
	return srvswithids
}
<|endoftext|>


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

package hugolib

import (
	"flag"
	"fmt"
	"math/rand"
	"path/filepath"
	"strings"
	"testing"

	"github.com/spf13/afero"
)

type siteBuildingBenchmarkConfig struct {
	Frontmatter  string
	NumPages     int
	NumLangs     int
	RootSections int
	Render       bool
	Shortcodes   bool
	NumTags      int
	TagsPerPage  int
}

func (s siteBuildingBenchmarkConfig) String() string {
	// Make it comma separated with no spaces, so it is both Bash and regexp friendly.
	// To make it a short as possible, we only shows bools when enabled and ints when >= 0 (RootSections > 1)
	sep := ","
	id := s.Frontmatter + sep
	id += fmt.Sprintf("num_langs=%d%s", s.NumLangs, sep)

	if s.RootSections > 1 {
		id += fmt.Sprintf("num_root_sections=%d%s", s.RootSections, sep)
	}
	id += fmt.Sprintf("num_pages=%d%s", s.NumPages, sep)

	if s.NumTags > 0 {
		id += fmt.Sprintf("num_tags=%d%s", s.NumTags, sep)
	}

	if s.TagsPerPage > 0 {
		id += fmt.Sprintf("tags_per_page=%d%s", s.TagsPerPage, sep)
	}

	if s.Shortcodes {
		id += "shortcodes" + sep
	}

	if s.Render {
		id += "render" + sep
	}

	return strings.TrimSuffix(id, sep)
}

var someLangs = []string{"en", "fr", "nn"}

func BenchmarkSiteBuilding(b *testing.B) {
	var (
		// The below represents the full matrix of benchmarks. Big!
		allFrontmatters    = []string{"YAML", "TOML"}
		allNumRootSections = []int{1, 5}
		allNumTags         = []int{0, 1, 10, 20, 50, 100, 500, 1000, 5000}
		allTagsPerPage     = []int{0, 1, 5, 20, 50, 80}
		allNumPages        = []int{1, 10, 100, 500, 1000, 5000, 10000}
		allDoRender        = []bool{false, true}
		allDoShortCodes    = []bool{false, true}
		allNumLangs        = []int{1, 3}
	)

	var runDefault bool

	visitor := func(a *flag.Flag) {
		if a.Name == "test.bench" && len(a.Value.String()) < 40 {
			// The full suite is too big, so fall back to some smaller default if no
			// restriction is set.
			runDefault = true
		}
	}

	flag.Visit(visitor)

	if runDefault {
		allFrontmatters = allFrontmatters[1:]
		allNumRootSections = allNumRootSections[0:2]
		allNumTags = allNumTags[0:2]
		allTagsPerPage = allTagsPerPage[2:3]
		allNumPages = allNumPages[2:5]
		allDoRender = allDoRender[1:2]
		allDoShortCodes = allDoShortCodes[1:2]
	}

	var conf siteBuildingBenchmarkConfig
	for _, numLangs := range allNumLangs {
		conf.NumLangs = numLangs
		for _, frontmatter := range allFrontmatters {
			conf.Frontmatter = frontmatter
			for _, rootSections := range allNumRootSections {
				conf.RootSections = rootSections
				for _, numTags := range allNumTags {
					conf.NumTags = numTags
					for _, tagsPerPage := range allTagsPerPage {
						conf.TagsPerPage = tagsPerPage
						for _, numPages := range allNumPages {
							conf.NumPages = numPages
							for _, render := range allDoRender {
								conf.Render = render
								for _, shortcodes := range allDoShortCodes {
									conf.Shortcodes = shortcodes
									doBenchMarkSiteBuilding(conf, b)
								}
							}
						}
					}
				}
			}
		}
	}
}

func doBenchMarkSiteBuilding(conf siteBuildingBenchmarkConfig, b *testing.B) {
	b.Run(conf.String(), func(b *testing.B) {
		b.StopTimer()
		sites := createHugoBenchmarkSites(b, b.N, conf)
		b.StartTimer()
		for i := 0; i < b.N; i++ {
			h := sites[0]

			err := h.Build(BuildCfg{SkipRender: !conf.Render})
			if err != nil {
				b.Fatal(err)
			}

			// Try to help the GC
			sites[0] = nil
			sites = sites[1:]
		}
	})
}

func createHugoBenchmarkSites(b *testing.B, count int, cfg siteBuildingBenchmarkConfig) []*HugoSites {
	someMarkdown := `
An h1 header
============

Paragraphs are separated by a blank line.

2nd paragraph. *Italic* and **bold**. Itemized lists
look like:

  * this one
  * that one
  * the other one

Note that --- not considering the asterisk --- the actual text
content starts at 4-columns in :smile:.

> Block quotes are
> written like so.
>
> They can span multiple paragraphs,
> if you like.

Use 3 dashes for an em-dash. Use 2 dashes for ranges (ex., "it's all
in chapters 12--14"). Three dots ... will be converted to an ellipsis.
Unicode is supported. ☺
`

	someMarkdownWithShortCode := someMarkdown + `

{{< myShortcode >}}

`

	pageTemplateTOML := `+++
title = "%s"
tags = %s
+++
%s

`

	pageTemplateYAML := `---
title: "%s"
tags:
%s
---
%s

`

	siteConfig := `
baseURL = "http://example.com/blog"

paginate = 10
defaultContentLanguage = "en"
enableEmoji = true

[outputs]
home = [ "HTML" ]
section = [ "HTML" ]
taxonomy = [ "HTML" ]
taxonomyTerm = [ "HTML" ]
page = [ "HTML" ]

[languages]
%s

[Taxonomies]
tag = "tags"
category = "categories"
`

	langConfigTemplate := `
[languages.%s]
languageName = "Lang %s"
weight = %d
`

	langConfig := ""

	for i := 0; i < cfg.NumLangs; i++ {
		langCode := someLangs[i]
		langConfig += fmt.Sprintf(langConfigTemplate, langCode, langCode, i+1)
	}

	siteConfig = fmt.Sprintf(siteConfig, langConfig)

	numTags := cfg.NumTags

	if cfg.TagsPerPage > numTags {
		numTags = cfg.TagsPerPage
	}

	var (
		contentPagesContent [3]string
		tags                = make([]string, numTags)
		pageTemplate        string
	)

	for i := 0; i < numTags; i++ {
		tags[i] = fmt.Sprintf("Hugo %d", i+1)
	}

	var tagsStr string

	if cfg.Shortcodes {
		contentPagesContent = [3]string{
			someMarkdown,
			strings.Repeat(someMarkdownWithShortCode, 2),
			strings.Repeat(someMarkdownWithShortCode, 3),
		}
	} else {
		contentPagesContent = [3]string{
			someMarkdown,
			strings.Repeat(someMarkdown, 2),
			strings.Repeat(someMarkdown, 3),
		}
	}

	sites := make([]*HugoSites, count)
	for i := 0; i < count; i++ {
		// Maybe consider reusing the Source fs
		mf := afero.NewMemMapFs()
		th, h := newTestSitesFromConfig(b, mf, siteConfig,
			"layouts/_default/single.html", `Single HTML|{{ .Title }}|{{ .Content }}|{{ partial "myPartial" . }}`,
			"layouts/_default/list.html", `List HTML|{{ .Title }}|{{ .Content }}|GetPage: {{ with .Site.GetPage "page" "sect3/page3.md" }}{{ .Title }}{{ end }}`,
			"layouts/partials/myPartial.html", `Partial: {{ "Hello **world**!" | markdownify }}`,
			"layouts/shortcodes/myShortcode.html", `<p>MyShortcode</p>`)

		fs := th.Fs

		pagesPerSection := cfg.NumPages / cfg.RootSections / cfg.NumLangs
		for li := 0; li < cfg.NumLangs; li++ {
			fileLangCodeID := ""
			if li > 0 {
				fileLangCodeID = "." + someLangs[li] + "."
			}

			for i := 0; i < cfg.RootSections; i++ {
				for j := 0; j < pagesPerSection; j++ {
					var tagsSlice []string

					if numTags > 0 {
						tagsStart := rand.Intn(numTags) - cfg.TagsPerPage
						if tagsStart < 0 {
							tagsStart = 0
						}
						tagsSlice = tags[tagsStart : tagsStart+cfg.TagsPerPage]
					}

					if cfg.Frontmatter == "TOML" {
						pageTemplate = pageTemplateTOML
						tagsStr = "[]"
						if cfg.TagsPerPage > 0 {
							tagsStr = strings.Replace(fmt.Sprintf("%q", tagsSlice), " ", ", ", -1)
						}
					} else {
						// YAML
						pageTemplate = pageTemplateYAML
						for _, tag := range tagsSlice {
							tagsStr += "\n- " + tag
						}
					}

					content := fmt.Sprintf(pageTemplate, fmt.Sprintf("Title%d_%d", i, j), tagsStr, contentPagesContent[rand.Intn(3)])

					contentFilename := fmt.Sprintf("page%d%s.md", j, fileLangCodeID)

					writeSource(b, fs, filepath.Join("content", fmt.Sprintf("sect%d", i), contentFilename), content)
				}

				content := fmt.Sprintf(pageTemplate, fmt.Sprintf("Section %d", i), "[]", contentPagesContent[rand.Intn(3)])
				indexContentFilename := fmt.Sprintf("_index%s.md", fileLangCodeID)
				writeSource(b, fs, filepath.Join("content", fmt.Sprintf("sect%d", i), indexContentFilename), content)
			}
		}

		sites[i] = h
	}

	return sites
}
<commit_msg>hugolib: Fix benchmark for YAML front matter<commit_after>// Copyright 2017-present The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package hugolib

import (
	"flag"
	"fmt"
	"math/rand"
	"path/filepath"
	"strings"
	"testing"

	"github.com/spf13/afero"
)

type siteBuildingBenchmarkConfig struct {
	Frontmatter  string
	NumPages     int
	NumLangs     int
	RootSections int
	Render       bool
	Shortcodes   bool
	NumTags      int
	TagsPerPage  int
}

func (s siteBuildingBenchmarkConfig) String() string {
	// Make it comma separated with no spaces, so it is both Bash and regexp friendly.
	// To make it a short as possible, we only shows bools when enabled and ints when >= 0 (RootSections > 1)
	sep := ","
	id := s.Frontmatter + sep
	id += fmt.Sprintf("num_langs=%d%s", s.NumLangs, sep)

	if s.RootSections > 1 {
		id += fmt.Sprintf("num_root_sections=%d%s", s.RootSections, sep)
	}
	id += fmt.Sprintf("num_pages=%d%s", s.NumPages, sep)

	if s.NumTags > 0 {
		id += fmt.Sprintf("num_tags=%d%s", s.NumTags, sep)
	}

	if s.TagsPerPage > 0 {
		id += fmt.Sprintf("tags_per_page=%d%s", s.TagsPerPage, sep)
	}

	if s.Shortcodes {
		id += "shortcodes" + sep
	}

	if s.Render {
		id += "render" + sep
	}

	return strings.TrimSuffix(id, sep)
}

var someLangs = []string{"en", "fr", "nn"}

func BenchmarkSiteBuilding(b *testing.B) {
	var (
		// The below represents the full matrix of benchmarks. Big!
		allFrontmatters    = []string{"YAML", "TOML"}
		allNumRootSections = []int{1, 5}
		allNumTags         = []int{0, 1, 10, 20, 50, 100, 500, 1000, 5000}
		allTagsPerPage     = []int{0, 1, 5, 20, 50, 80}
		allNumPages        = []int{1, 10, 100, 500, 1000, 5000, 10000}
		allDoRender        = []bool{false, true}
		allDoShortCodes    = []bool{false, true}
		allNumLangs        = []int{1, 3}
	)

	var runDefault bool

	visitor := func(a *flag.Flag) {
		if a.Name == "test.bench" && len(a.Value.String()) < 40 {
			// The full suite is too big, so fall back to some smaller default if no
			// restriction is set.
			runDefault = true
		}
	}

	flag.Visit(visitor)

	if runDefault {
		allFrontmatters = allFrontmatters[1:]
		allNumRootSections = allNumRootSections[0:2]
		allNumTags = allNumTags[0:2]
		allTagsPerPage = allTagsPerPage[2:3]
		allNumPages = allNumPages[2:5]
		allDoRender = allDoRender[1:2]
		allDoShortCodes = allDoShortCodes[1:2]
	}

	var conf siteBuildingBenchmarkConfig
	for _, numLangs := range allNumLangs {
		conf.NumLangs = numLangs
		for _, frontmatter := range allFrontmatters {
			conf.Frontmatter = frontmatter
			for _, rootSections := range allNumRootSections {
				conf.RootSections = rootSections
				for _, numTags := range allNumTags {
					conf.NumTags = numTags
					for _, tagsPerPage := range allTagsPerPage {
						conf.TagsPerPage = tagsPerPage
						for _, numPages := range allNumPages {
							conf.NumPages = numPages
							for _, render := range allDoRender {
								conf.Render = render
								for _, shortcodes := range allDoShortCodes {
									conf.Shortcodes = shortcodes
									doBenchMarkSiteBuilding(conf, b)
								}
							}
						}
					}
				}
			}
		}
	}
}

func doBenchMarkSiteBuilding(conf siteBuildingBenchmarkConfig, b *testing.B) {
	b.Run(conf.String(), func(b *testing.B) {
		b.StopTimer()
		sites := createHugoBenchmarkSites(b, b.N, conf)
		b.StartTimer()
		for i := 0; i < b.N; i++ {
			h := sites[0]

			err := h.Build(BuildCfg{SkipRender: !conf.Render})
			if err != nil {
				b.Fatal(err)
			}

			// Try to help the GC
			sites[0] = nil
			sites = sites[1:]
		}
	})
}

func createHugoBenchmarkSites(b *testing.B, count int, cfg siteBuildingBenchmarkConfig) []*HugoSites {
	someMarkdown := `
An h1 header
============

Paragraphs are separated by a blank line.

2nd paragraph. *Italic* and **bold**. Itemized lists
look like:

  * this one
  * that one
  * the other one

Note that --- not considering the asterisk --- the actual text
content starts at 4-columns in :smile:.

> Block quotes are
> written like so.
>
> They can span multiple paragraphs,
> if you like.

Use 3 dashes for an em-dash. Use 2 dashes for ranges (ex., "it's all
in chapters 12--14"). Three dots ... will be converted to an ellipsis.
Unicode is supported. ☺
`

	someMarkdownWithShortCode := someMarkdown + `

{{< myShortcode >}}

`

	pageTemplateTOML := `+++
title = "%s"
tags = %s
+++
%s

`

	pageTemplateYAML := `---
title: "%s"
tags: %s
---
%s

`

	siteConfig := `
baseURL = "http://example.com/blog"

paginate = 10
defaultContentLanguage = "en"
enableEmoji = true

[outputs]
home = [ "HTML" ]
section = [ "HTML" ]
taxonomy = [ "HTML" ]
taxonomyTerm = [ "HTML" ]
page = [ "HTML" ]

[languages]
%s

[Taxonomies]
tag = "tags"
category = "categories"
`

	langConfigTemplate := `
[languages.%s]
languageName = "Lang %s"
weight = %d
`

	langConfig := ""

	for i := 0; i < cfg.NumLangs; i++ {
		langCode := someLangs[i]
		langConfig += fmt.Sprintf(langConfigTemplate, langCode, langCode, i+1)
	}

	siteConfig = fmt.Sprintf(siteConfig, langConfig)

	numTags := cfg.NumTags

	if cfg.TagsPerPage > numTags {
		numTags = cfg.TagsPerPage
	}

	var (
		contentPagesContent [3]string
		tags                = make([]string, numTags)
		pageTemplate        string
	)

	for i := 0; i < numTags; i++ {
		tags[i] = fmt.Sprintf("Hugo %d", i+1)
	}

	if cfg.Shortcodes {
		contentPagesContent = [3]string{
			someMarkdown,
			strings.Repeat(someMarkdownWithShortCode, 2),
			strings.Repeat(someMarkdownWithShortCode, 3),
		}
	} else {
		contentPagesContent = [3]string{
			someMarkdown,
			strings.Repeat(someMarkdown, 2),
			strings.Repeat(someMarkdown, 3),
		}
	}

	sites := make([]*HugoSites, count)
	for i := 0; i < count; i++ {
		// Maybe consider reusing the Source fs
		mf := afero.NewMemMapFs()
		th, h := newTestSitesFromConfig(b, mf, siteConfig,
			"layouts/_default/single.html", `Single HTML|{{ .Title }}|{{ .Content }}|{{ partial "myPartial" . }}`,
			"layouts/_default/list.html", `List HTML|{{ .Title }}|{{ .Content }}|GetPage: {{ with .Site.GetPage "page" "sect3/page3.md" }}{{ .Title }}{{ end }}`,
			"layouts/partials/myPartial.html", `Partial: {{ "Hello **world**!" | markdownify }}`,
			"layouts/shortcodes/myShortcode.html", `<p>MyShortcode</p>`)

		fs := th.Fs

		pagesPerSection := cfg.NumPages / cfg.RootSections / cfg.NumLangs
		for li := 0; li < cfg.NumLangs; li++ {
			fileLangCodeID := ""
			if li > 0 {
				fileLangCodeID = "." + someLangs[li] + "."
			}

			for i := 0; i < cfg.RootSections; i++ {
				for j := 0; j < pagesPerSection; j++ {
					var tagsSlice []string

					if numTags > 0 {
						tagsStart := rand.Intn(numTags) - cfg.TagsPerPage
						if tagsStart < 0 {
							tagsStart = 0
						}
						tagsSlice = tags[tagsStart : tagsStart+cfg.TagsPerPage]
					}

					var tagsStr string

					if cfg.Frontmatter == "TOML" {
						pageTemplate = pageTemplateTOML
						tagsStr = "[]"
						if cfg.TagsPerPage > 0 {
							tagsStr = strings.Replace(fmt.Sprintf("%q", tagsSlice), " ", ", ", -1)
						}
					} else {
						// YAML
						pageTemplate = pageTemplateYAML
						for _, tag := range tagsSlice {
							tagsStr += "\n- " + tag
						}
					}

					content := fmt.Sprintf(pageTemplate, fmt.Sprintf("Title%d_%d", i, j), tagsStr, contentPagesContent[rand.Intn(3)])

					contentFilename := fmt.Sprintf("page%d%s.md", j, fileLangCodeID)

					writeSource(b, fs, filepath.Join("content", fmt.Sprintf("sect%d", i), contentFilename), content)

				}

				content := fmt.Sprintf(pageTemplate, fmt.Sprintf("Section %d", i), "[]", contentPagesContent[rand.Intn(3)])

				indexContentFilename := fmt.Sprintf("_index%s.md", fileLangCodeID)
				writeSource(b, fs, filepath.Join("content", fmt.Sprintf("sect%d", i), indexContentFilename), content)
			}
		}

		sites[i] = h
	}

	return sites
}
<|endoftext|>


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

package wa

type FuncType struct {
	Params []Type
	Result Type
}

func (f1 FuncType) Equal(f2 FuncType) bool {
	if f1.Result != f2.Result {
		return false
	}

	if len(f1.Params) != len(f2.Params) {
		return false
	}

	for i := range f1.Params {
		if f1.Params[i] != f2.Params[i] {
			return false
		}
	}

	return true
}

func (f FuncType) String() (s string) {
	s = "("
	for i, t := range f.Params {
		if i > 0 {
			s += ", "
		}
		s += t.String()
	}
	s += ")"
	if f.Result != Void {
		s += " " + f.Result.String()
	}
	return
}
<commit_msg>wa: consistent receiver naming<commit_after>// Copyright (c) 2016 Timo Savola. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package wa

type FuncType struct {
	Params []Type
	Result Type
}

func (f FuncType) Equal(other FuncType) bool {
	if f.Result != other.Result {
		return false
	}

	if len(f.Params) != len(other.Params) {
		return false
	}

	for i := range f.Params {
		if f.Params[i] != other.Params[i] {
			return false
		}
	}

	return true
}

func (f FuncType) String() (s string) {
	s = "("
	for i, t := range f.Params {
		if i > 0 {
			s += ", "
		}
		s += t.String()
	}
	s += ")"
	if f.Result != Void {
		s += " " + f.Result.String()
	}
	return
}
<|endoftext|>


<commit_before>package ftp

import (
	"fmt"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestWalkReturnsCorrectlyPopulatedWalker(t *testing.T) {
	mock, err := newFtpMock(t, "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	defer mock.Close()

	c, cErr := Connect(mock.Addr())
	if cErr != nil {
		t.Fatal(err)
	}

	w := c.Walk("root")

	assert.Equal(t, "root/", w.root)
	assert.Equal(t, &c, &w.serverConn)
}

func TestFieldsReturnCorrectData(t *testing.T) {
	w := Walker{
		cur: &item{
			path: "/root/",
			err:  fmt.Errorf("this is an error"),
			entry: &Entry{
				Name: "root",
				Size: 123,
				Time: time.Now(),
				Type: EntryTypeFolder,
			},
		},
	}

	assert.Equal(t, "this is an error", w.Err().Error())
	assert.Equal(t, "/root/", w.Path())
	assert.Equal(t, EntryTypeFolder, w.Stat().Type)
}

func TestSkipDirIsCorrectlySet(t *testing.T) {
	w := Walker{}

	w.SkipDir()

	assert.Equal(t, false, w.descend)
}

func TestNoDescendDoesNotAddToStack(t *testing.T) {
	mock, err := newFtpMock(t, "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	defer mock.Close()

	c, cErr := Connect(mock.Addr())
	if cErr != nil {
		t.Fatal(err)
	}

	w := c.Walk("/root")
	w.cur = &item{
		path: "/root/",
		err:  nil,
		entry: &Entry{
			Name: "root",
			Size: 123,
			Time: time.Now(),
			Type: EntryTypeFolder,
		},
	}

	w.stack = []*item{
		&item{
			path: "file",
			err:  nil,
			entry: &Entry{
				Name: "file",
				Size: 123,
				Time: time.Now(),
				Type: EntryTypeFile,
			},
		},
	}

	w.SkipDir()

	result := w.Next()

	assert.Equal(t, true, result, "Result should return true")
	assert.Equal(t, 0, len(w.stack))
	assert.Equal(t, true, w.descend)
}

func TestEmptyStackReturnsFalse(t *testing.T) {
	mock, err := newFtpMock(t, "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	defer mock.Close()

	c, cErr := Connect(mock.Addr())
	if cErr != nil {
		t.Fatal(err)
	}

	w := c.Walk("/root")

	w.cur = &item{
		path: "/root/",
		err:  nil,
		entry: &Entry{
			Name: "root",
			Size: 123,
			Time: time.Now(),
			Type: EntryTypeFolder,
		},
	}

	w.stack = []*item{}

	w.SkipDir()

	result := w.Next()

	assert.Equal(t, false, result, "Result should return false")
}

func TestCurAndStackSetCorrectly(t *testing.T) {
	mock, err := newFtpMock(t, "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	defer mock.Close()

	c, cErr := Connect(mock.Addr())
	if cErr != nil {
		t.Fatal(err)
	}

	w := c.Walk("/root")
	w.cur = &item{
		path: "root/file1",
		err:  nil,
		entry: &Entry{
			Name: "file1",
			Size: 123,
			Time: time.Now(),
			Type: EntryTypeFile,
		},
	}

	w.stack = []*item{
		&item{
			path: "file",
			err:  nil,
			entry: &Entry{
				Name: "file",
				Size: 123,
				Time: time.Now(),
				Type: EntryTypeFile,
			},
		},
		&item{
			path: "root/file1",
			err:  nil,
			entry: &Entry{
				Name: "file1",
				Size: 123,
				Time: time.Now(),
				Type: EntryTypeFile,
			},
		},
	}

	result := w.Next()
	result = w.Next()

	assert.Equal(t, true, result, "Result should return true")
	assert.Equal(t, 0, len(w.stack))
	assert.Equal(t, "file", w.cur.entry.Name)
}
<commit_msg>try and improve coveralls<commit_after>package ftp

import (
	"fmt"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestWalkReturnsCorrectlyPopulatedWalker(t *testing.T) {
	mock, err := newFtpMock(t, "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	defer mock.Close()

	c, cErr := Connect(mock.Addr())
	if cErr != nil {
		t.Fatal(err)
	}

	w := c.Walk("root")

	assert.Equal(t, "root/", w.root)
	assert.Equal(t, &c, &w.serverConn)
}

func TestFieldsReturnCorrectData(t *testing.T) {
	w := Walker{
		cur: &item{
			path: "/root/",
			err:  fmt.Errorf("this is an error"),
			entry: &Entry{
				Name: "root",
				Size: 123,
				Time: time.Now(),
				Type: EntryTypeFolder,
			},
		},
	}

	assert.Equal(t, "this is an error", w.Err().Error())
	assert.Equal(t, "/root/", w.Path())
	assert.Equal(t, EntryTypeFolder, w.Stat().Type)
}

func TestSkipDirIsCorrectlySet(t *testing.T) {
	w := Walker{}

	w.SkipDir()

	assert.Equal(t, false, w.descend)
}

func TestNoDescendDoesNotAddToStack(t *testing.T) {
	mock, err := newFtpMock(t, "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	defer mock.Close()

	c, cErr := Connect(mock.Addr())
	if cErr != nil {
		t.Fatal(err)
	}

	w := c.Walk("/root")
	w.cur = &item{
		path: "/root/",
		err:  nil,
		entry: &Entry{
			Name: "root",
			Size: 123,
			Time: time.Now(),
			Type: EntryTypeFolder,
		},
	}

	w.stack = []*item{
		&item{
			path: "file",
			err:  nil,
			entry: &Entry{
				Name: "file",
				Size: 123,
				Time: time.Now(),
				Type: EntryTypeFile,
			},
		},
	}

	w.SkipDir()

	result := w.Next()

	assert.Equal(t, true, result, "Result should return true")
	assert.Equal(t, 0, len(w.stack))
	assert.Equal(t, true, w.descend)
}

func TestEmptyStackReturnsFalse(t *testing.T) {
	mock, err := newFtpMock(t, "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	defer mock.Close()

	c, cErr := Connect(mock.Addr())
	if cErr != nil {
		t.Fatal(err)
	}

	w := c.Walk("/root")

	w.cur = &item{
		path: "/root/",
		err:  nil,
		entry: &Entry{
			Name: "root",
			Size: 123,
			Time: time.Now(),
			Type: EntryTypeFolder,
		},
	}

	w.stack = []*item{}

	w.SkipDir()

	result := w.Next()

	assert.Equal(t, false, result, "Result should return false")
}

func TestCurAndStackSetCorrectly(t *testing.T) {
	mock, err := newFtpMock(t, "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	defer mock.Close()

	c, cErr := Connect(mock.Addr())
	if cErr != nil {
		t.Fatal(err)
	}

	w := c.Walk("/root")
	w.cur = &item{
		path: "root/file1",
		err:  nil,
		entry: &Entry{
			Name: "file1",
			Size: 123,
			Time: time.Now(),
			Type: EntryTypeFile,
		},
	}

	w.stack = []*item{
		&item{
			path: "file",
			err:  nil,
			entry: &Entry{
				Name: "file",
				Size: 123,
				Time: time.Now(),
				Type: EntryTypeFile,
			},
		},
		&item{
			path: "root/file1",
			err:  nil,
			entry: &Entry{
				Name: "file1",
				Size: 123,
				Time: time.Now(),
				Type: EntryTypeFile,
			},
		},
	}

	result := w.Next()
	result = w.Next()

	assert.Equal(t, true, result, "Result should return true")
	assert.Equal(t, 0, len(w.stack))
	assert.Equal(t, "file", w.cur.entry.Name)
}

func TestCurInit(t *testing.T) {
	mock, err := newFtpMock(t, "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	defer mock.Close()

	c, cErr := Connect(mock.Addr())
	if cErr != nil {
		t.Fatal(err)
	}

	w := c.Walk("/root")

	result := w.Next()

	// mock fs has one file 'lo'

	assert.Equal(t, true, result, "Result should return false")
	assert.Equal(t, 0, len(w.stack))
	assert.Equal(t, "/root/lo", w.Path())
}
<|endoftext|>