<commit_before>package word_test

import (
	"testing"

	"zenithar.org/word"
)

func TestGoodWord(t *testing.T) {
	var goodWords = []string{
		"",
		"facebook",
		"google",
		"zenithar",
		"linkedin",
	}

	for _, w := range goodWords {
		if !word.IsWord(w) {
			t.Errorf("%s must be a recognized word.", w)
		}
	}
}

func TestBadWord(t *testing.T) {
	var badWords = []string{
		"okajwwpvwfxigcb",
		"bejqryeinqtvask",
		"vhjnivbojjkvkcf",
	}

	for _, w := range badWords {
		if word.IsWord(w) {
			t.Errorf("%s must not be a recognized word.", w)
		}
	}
}
<commit_msg>[APP] Update package name<commit_after>package word_test

import (
	"testing"

	"github.com/zenithar/word"
)

func TestGoodWord(t *testing.T) {
	var goodWords = []string{
		"",
		"facebook",
		"google",
		"zenithar",
		"linkedin",
	}

	for _, w := range goodWords {
		if !word.IsWord(w) {
			t.Errorf("%s must be a recognized word.", w)
		}
	}
}

func TestBadWord(t *testing.T) {
	var badWords = []string{
		"okajwwpvwfxigcb",
		"bejqryeinqtvask",
		"vhjnivbojjkvkcf",
	}

	for _, w := range badWords {
		if word.IsWord(w) {
			t.Errorf("%s must not be a recognized word.", w)
		}
	}
}
<|endoftext|>


<commit_before>package mailchimp

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
)

// CheckSubscription ...
func (c *Client) CheckSubscription(email string, listID string) (*MemberResponse, error) {
	// Hash email
	h := md5.New()
	io.WriteString(h, email)
	emailMD5 := fmt.Sprintf("%s", h.Sum(nil))
	// Make request
	resp, err := c.do(
		"GET",
		fmt.Sprintf("/lists/%s/members/%s", listID, emailMD5),
		nil,
	)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// Read the response body
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	// If the request failed
	if resp.StatusCode > 299 {
		errorResponse, err := extractError(data)
		if err != nil {
			return nil, err
		}
		return nil, errorResponse
	}

	// Unmarshal response into MemberResponse struct
	memberResponse := new(MemberResponse)
	if err := json.Unmarshal(data, memberResponse); err != nil {
		return nil, err
	}
	return memberResponse, nil
}
<commit_msg>Fixed a bug with md5 email hashing.<commit_after>package mailchimp

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io/ioutil"
)

// CheckSubscription ...
func (c *Client) CheckSubscription(email string, listID string) (*MemberResponse, error) {
	// Hash email
	emailMD5 := fmt.Sprintf("%x", md5.Sum([]byte(email)))
	// Make request
	resp, err := c.do(
		"GET",
		fmt.Sprintf("/lists/%s/members/%s", listID, emailMD5),
		nil,
	)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// Read the response body
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	// If the request failed
	if resp.StatusCode > 299 {
		errorResponse, err := extractError(data)
		if err != nil {
			return nil, err
		}
		return nil, errorResponse
	}

	// Unmarshal response into MemberResponse struct
	memberResponse := new(MemberResponse)
	if err := json.Unmarshal(data, memberResponse); err != nil {
		return nil, err
	}
	return memberResponse, nil
}
<|endoftext|>


<commit_before>package chug

import (
	"flag"
	"io"
	"os"
	"regexp"
	"time"

	"github.com/cloudfoundry-incubator/veritas/common"
	"github.com/cloudfoundry-incubator/veritas/say"
)

func baseFlagSet(command string, minTimeFlag, maxTimeFlag, matchFlag, excludeFlag *string) *flag.FlagSet {
	flagSet := flag.NewFlagSet(command, flag.ExitOnError)
	flagSet.StringVar(minTimeFlag, "min", "", "only include entries logged after this time: either a unix timestamp, a chug-formatted time, or a duration (relative to now)")
	flagSet.StringVar(maxTimeFlag, "max", "", "only include entries logged before this time: either a unix timestamp, a chug-formatted time, or a duration (relative to now)")
	flagSet.StringVar(matchFlag, "match", "", "only include entries that match this regular expression")
	flagSet.StringVar(excludeFlag, "exclude", "", "exclude entries that match this regular expression")

	return flagSet
}

func parseBaseFlags(minTimeFlag, maxTimeFlag, matchFlag, excludeFlag string) (time.Time, time.Time, *regexp.Regexp, *regexp.Regexp) {
	minTime, err := ParseTimeFlag(minTimeFlag)
	common.ExitIfError("Failed to parse -min", err)
	maxTime, err := ParseTimeFlag(maxTimeFlag)
	common.ExitIfError("Failed to parse -max", err)
	match, err := regexp.Compile(matchFlag)
	common.ExitIfError("Failed to parse -match", err)
	exclude, err := regexp.Compile(excludeFlag)
	common.ExitIfError("Failed to parse -match", err)
	return minTime, maxTime, match, exclude
}

func ChugCommand() common.Command {
	var (
		minTimeFlag string
		maxTimeFlag string
		matchFlag   string
		excludeFlag string

		rel          string
		data         string
		hideNonLager bool
	)

	flagSet := baseFlagSet("chug", &minTimeFlag, &maxTimeFlag, &matchFlag, &excludeFlag)
	flagSet.StringVar(&rel, "rel", "", "render timestamps as durations relative to: 'first', 'now', or a number interpreted as a unix timestamp")
	flagSet.StringVar(&data, "data", "short", "render data: 'none', 'short', 'long'")
	flagSet.BoolVar(&hideNonLager, "hide", false, "hide non-lager logs")

	return common.Command{
		Name:        "chug",
		Description: "[file] - Prettify lager logs",
		FlagSet:     flagSet,
		Run: func(args []string) {
			minTime, maxTime, match, exclude := parseBaseFlags(minTimeFlag, maxTimeFlag, matchFlag, excludeFlag)

			if len(args) == 0 {
				err := Prettify(rel, data, hideNonLager, minTime, maxTime, match, exclude, os.Stdin)
				common.ExitIfError("Failed to chug", err)
			} else {
				f, err := os.Open(args[0])
				common.ExitIfError("Could not open file", err)

				err = Prettify(rel, data, hideNonLager, minTime, maxTime, match, exclude, f)
				common.ExitIfError("Failed to chug", err)

				f.Close()
			}
		},
	}
}

func UnifyChugCommand() common.Command {
	var (
		minTimeFlag string
		maxTimeFlag string
		matchFlag   string
		excludeFlag string
	)

	flagSet := baseFlagSet("chug-unify", &minTimeFlag, &maxTimeFlag, &matchFlag, &excludeFlag)

	return common.Command{
		Name:        "chug-unify",
		Description: "file1, file2,... - Combine lager files in temporal order",
		FlagSet:     flagSet,
		Run: func(args []string) {
			minTime, maxTime, match, exclude := parseBaseFlags(minTimeFlag, maxTimeFlag, matchFlag, excludeFlag)

			if len(args) == 0 {
				say.Println(0, say.Red("You must pass chug-unify files to combine"))
				os.Exit(1)
			} else {
				files := []io.Reader{}
				for _, arg := range args {
					f, err := os.Open(arg)
					common.ExitIfError("Could not open file", err)
					files = append(files, f)
				}

				err := Unify(files, os.Stdout, minTime, maxTime, match, exclude)
				common.ExitIfError("Failed to chug-unify", err)
			}
		},
	}
}

func ServeChugCommand() common.Command {
	var (
		minTimeFlag string
		maxTimeFlag string
		matchFlag   string
		excludeFlag string
		addr        string
		dev         bool
	)

	flagSet := baseFlagSet("chug-serve", &minTimeFlag, &maxTimeFlag, &matchFlag, &excludeFlag)
	flagSet.StringVar(&addr, "addr", "127.0.0.1:0", "address to serve chug")
	flagSet.BoolVar(&dev, "dev", false, "dev mode")

	return common.Command{
		Name:        "chug-serve",
		Description: "[file] - Serve up pretty lager logs",
		FlagSet:     flagSet,
		Run: func(args []string) {
			minTime, maxTime, match, exclude := parseBaseFlags(minTimeFlag, maxTimeFlag, matchFlag, excludeFlag)

			if len(args) == 0 {
				err := ServeLogs(addr, dev, minTime, maxTime, match, exclude, os.Stdin)
				common.ExitIfError("Failed to serve chug", err)
			} else {
				f, err := os.Open(args[0])
				common.ExitIfError("Could not open file", err)

				err = ServeLogs(addr, dev, minTime, maxTime, match, exclude, f)
				common.ExitIfError("Failed to serve chug", err)

				f.Close()
			}
		},
	}
}
<commit_msg>empty filter flags should not filter<commit_after>package chug

import (
	"flag"
	"io"
	"os"
	"regexp"
	"time"

	"github.com/cloudfoundry-incubator/veritas/common"
	"github.com/cloudfoundry-incubator/veritas/say"
)

func baseFlagSet(command string, minTimeFlag, maxTimeFlag, matchFlag, excludeFlag *string) *flag.FlagSet {
	flagSet := flag.NewFlagSet(command, flag.ExitOnError)
	flagSet.StringVar(minTimeFlag, "min", "", "only include entries logged after this time: either a unix timestamp, a chug-formatted time, or a duration (relative to now)")
	flagSet.StringVar(maxTimeFlag, "max", "", "only include entries logged before this time: either a unix timestamp, a chug-formatted time, or a duration (relative to now)")
	flagSet.StringVar(matchFlag, "match", "", "only include entries that match this regular expression")
	flagSet.StringVar(excludeFlag, "exclude", "", "exclude entries that match this regular expression")

	return flagSet
}

func parseBaseFlags(minTimeFlag, maxTimeFlag, matchFlag, excludeFlag string) (time.Time, time.Time, *regexp.Regexp, *regexp.Regexp) {
	minTime, err := ParseTimeFlag(minTimeFlag)
	common.ExitIfError("Failed to parse -min", err)
	maxTime, err := ParseTimeFlag(maxTimeFlag)
	common.ExitIfError("Failed to parse -max", err)
	match, err := regexp.Compile(matchFlag)
	common.ExitIfError("Failed to parse -match", err)
	if matchFlag == "" {
		match = nil
	}
	exclude, err := regexp.Compile(excludeFlag)
	common.ExitIfError("Failed to parse -match", err)
	if excludeFlag == "" {
		exclude = nil
	}
	return minTime, maxTime, match, exclude
}

func ChugCommand() common.Command {
	var (
		minTimeFlag string
		maxTimeFlag string
		matchFlag   string
		excludeFlag string

		rel          string
		data         string
		hideNonLager bool
	)

	flagSet := baseFlagSet("chug", &minTimeFlag, &maxTimeFlag, &matchFlag, &excludeFlag)
	flagSet.StringVar(&rel, "rel", "", "render timestamps as durations relative to: 'first', 'now', or a number interpreted as a unix timestamp")
	flagSet.StringVar(&data, "data", "short", "render data: 'none', 'short', 'long'")
	flagSet.BoolVar(&hideNonLager, "hide", false, "hide non-lager logs")

	return common.Command{
		Name:        "chug",
		Description: "[file] - Prettify lager logs",
		FlagSet:     flagSet,
		Run: func(args []string) {
			minTime, maxTime, match, exclude := parseBaseFlags(minTimeFlag, maxTimeFlag, matchFlag, excludeFlag)

			if len(args) == 0 {
				err := Prettify(rel, data, hideNonLager, minTime, maxTime, match, exclude, os.Stdin)
				common.ExitIfError("Failed to chug", err)
			} else {
				f, err := os.Open(args[0])
				common.ExitIfError("Could not open file", err)

				err = Prettify(rel, data, hideNonLager, minTime, maxTime, match, exclude, f)
				common.ExitIfError("Failed to chug", err)

				f.Close()
			}
		},
	}
}

func UnifyChugCommand() common.Command {
	var (
		minTimeFlag string
		maxTimeFlag string
		matchFlag   string
		excludeFlag string
	)

	flagSet := baseFlagSet("chug-unify", &minTimeFlag, &maxTimeFlag, &matchFlag, &excludeFlag)

	return common.Command{
		Name:        "chug-unify",
		Description: "file1, file2,... - Combine lager files in temporal order",
		FlagSet:     flagSet,
		Run: func(args []string) {
			minTime, maxTime, match, exclude := parseBaseFlags(minTimeFlag, maxTimeFlag, matchFlag, excludeFlag)

			if len(args) == 0 {
				say.Println(0, say.Red("You must pass chug-unify files to combine"))
				os.Exit(1)
			} else {
				files := []io.Reader{}
				for _, arg := range args {
					f, err := os.Open(arg)
					common.ExitIfError("Could not open file", err)
					files = append(files, f)
				}

				err := Unify(files, os.Stdout, minTime, maxTime, match, exclude)
				common.ExitIfError("Failed to chug-unify", err)
			}
		},
	}
}

func ServeChugCommand() common.Command {
	var (
		minTimeFlag string
		maxTimeFlag string
		matchFlag   string
		excludeFlag string
		addr        string
		dev         bool
	)

	flagSet := baseFlagSet("chug-serve", &minTimeFlag, &maxTimeFlag, &matchFlag, &excludeFlag)
	flagSet.StringVar(&addr, "addr", "127.0.0.1:0", "address to serve chug")
	flagSet.BoolVar(&dev, "dev", false, "dev mode")

	return common.Command{
		Name:        "chug-serve",
		Description: "[file] - Serve up pretty lager logs",
		FlagSet:     flagSet,
		Run: func(args []string) {
			minTime, maxTime, match, exclude := parseBaseFlags(minTimeFlag, maxTimeFlag, matchFlag, excludeFlag)

			if len(args) == 0 {
				err := ServeLogs(addr, dev, minTime, maxTime, match, exclude, os.Stdin)
				common.ExitIfError("Failed to serve chug", err)
			} else {
				f, err := os.Open(args[0])
				common.ExitIfError("Could not open file", err)

				err = ServeLogs(addr, dev, minTime, maxTime, match, exclude, f)
				common.ExitIfError("Failed to serve chug", err)

				f.Close()
			}
		},
	}
}
<|endoftext|>


<commit_before>package sctp

import (
	"encoding/binary"
	"fmt"
)

/*
chunkPayloadData represents an SCTP Chunk of type DATA

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Type = 0    | Reserved|U|B|E|    Length                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                              TSN                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Stream Identifier S      |   Stream Sequence Number n    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                  Payload Protocol Identifier                  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                 User Data (seq n of Stream S)                 |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

An unfragmented user message shall have both the B and E bits set to
'1'.  Setting both B and E bits to '0' indicates a middle fragment of
a multi-fragment user message, as summarized in the following table:
   B E                  Description
============================================================
|  1 0 | First piece of a fragmented user message          |
+----------------------------------------------------------+
|  0 0 | Middle piece of a fragmented user message         |
+----------------------------------------------------------+
|  0 1 | Last piece of a fragmented user message           |
+----------------------------------------------------------+
|  1 1 | Unfragmented message                              |
============================================================
|             Table 1: Fragment Description Flags          |
============================================================
*/
type chunkPayloadData struct {
	chunkHeader

	unordered        bool
	beginingFragment bool
	endingFragment   bool
	immediateSack    bool

	tsn                  uint32
	streamIdentifier     uint16
	streamSequenceNumber uint16
	payloadType          PayloadProtocolIdentifier
	userData             []byte
}

const (
	payloadDataEndingFragmentBitmask   = 1
	payloadDataBeginingFragmentBitmask = 2
	payloadDataUnorderedBitmask        = 4
	payloadDataImmediateSACK           = 8

	payloadDataHeaderSize = 12
)

// PayloadProtocolIdentifier is an enum for DataChannel payload types
type PayloadProtocolIdentifier uint32

// PayloadProtocolIdentifier enums
const (
	PayloadTypeWebRTCDCEP        PayloadProtocolIdentifier = 50
	PayloadTypeWebRTCString      PayloadProtocolIdentifier = 51
	PayloadTypeWebRTCBinary      PayloadProtocolIdentifier = 52
	PayloadTypeWebRTCStringEmpty PayloadProtocolIdentifier = 56
	PayloadTypeWebRTCBinaryEmpty PayloadProtocolIdentifier = 57
)

func (p PayloadProtocolIdentifier) String() string {
	switch p {
	case PayloadTypeWebRTCDCEP:
		return "WebRTC DCEP"
	case PayloadTypeWebRTCString:
		return "WebRTC String"
	case PayloadTypeWebRTCBinary:
		return "WebRTC Binary"
	case PayloadTypeWebRTCStringEmpty:
		return "WebRTC String (Empty)"
	case PayloadTypeWebRTCBinaryEmpty:
		return "WebRTC Binary (Empty)"
	default:
		return fmt.Sprintf("Unknown Payload Protocol Identifier: %d", p)
	}
}

func (p *chunkPayloadData) unmarshal(raw []byte) error {
	if err := p.chunkHeader.unmarshal(raw); err != nil {
		return err
	}

	p.immediateSack = p.flags&payloadDataImmediateSACK != 0
	p.unordered = p.flags&payloadDataUnorderedBitmask != 0
	p.beginingFragment = p.flags&payloadDataBeginingFragmentBitmask != 0
	p.endingFragment = p.flags&payloadDataEndingFragmentBitmask != 0

	p.tsn = binary.BigEndian.Uint32(p.raw[0:])
	p.streamIdentifier = binary.BigEndian.Uint16(p.raw[4:])
	p.streamSequenceNumber = binary.BigEndian.Uint16(p.raw[6:])
	p.payloadType = PayloadProtocolIdentifier(binary.BigEndian.Uint32(p.raw[8:]))
	p.userData = p.raw[payloadDataHeaderSize:]

	return nil
}

func (p *chunkPayloadData) marshal() ([]byte, error) {

	payRaw := make([]byte, payloadDataHeaderSize+len(p.userData))

	binary.BigEndian.PutUint32(payRaw[0:], p.tsn)
	binary.BigEndian.PutUint16(payRaw[4:], p.streamIdentifier)
	binary.BigEndian.PutUint16(payRaw[6:], p.streamSequenceNumber)
	binary.BigEndian.PutUint32(payRaw[8:], uint32(p.payloadType))
	copy(payRaw[payloadDataHeaderSize:], p.userData)

	flags := uint8(0)
	if p.endingFragment {
		flags = 1
	}
	if p.beginingFragment {
		flags |= 1 << 1
	}
	if p.unordered {
		flags |= 1 << 2
	}
	if p.immediateSack {
		flags |= 1 << 3
	}

	p.chunkHeader.flags = flags
	p.chunkHeader.typ = PAYLOADDATA
	p.chunkHeader.raw = payRaw
	return p.chunkHeader.marshal()
}

func (p *chunkPayloadData) check() (abort bool, err error) {
	return false, nil
}
<commit_msg>Fix PayloadTypeWebRTCBinary value<commit_after>package sctp

import (
	"encoding/binary"
	"fmt"
)

/*
chunkPayloadData represents an SCTP Chunk of type DATA

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Type = 0    | Reserved|U|B|E|    Length                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                              TSN                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Stream Identifier S      |   Stream Sequence Number n    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                  Payload Protocol Identifier                  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                 User Data (seq n of Stream S)                 |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

An unfragmented user message shall have both the B and E bits set to
'1'.  Setting both B and E bits to '0' indicates a middle fragment of
a multi-fragment user message, as summarized in the following table:
   B E                  Description
============================================================
|  1 0 | First piece of a fragmented user message          |
+----------------------------------------------------------+
|  0 0 | Middle piece of a fragmented user message         |
+----------------------------------------------------------+
|  0 1 | Last piece of a fragmented user message           |
+----------------------------------------------------------+
|  1 1 | Unfragmented message                              |
============================================================
|             Table 1: Fragment Description Flags          |
============================================================
*/
type chunkPayloadData struct {
	chunkHeader

	unordered        bool
	beginingFragment bool
	endingFragment   bool
	immediateSack    bool

	tsn                  uint32
	streamIdentifier     uint16
	streamSequenceNumber uint16
	payloadType          PayloadProtocolIdentifier
	userData             []byte
}

const (
	payloadDataEndingFragmentBitmask   = 1
	payloadDataBeginingFragmentBitmask = 2
	payloadDataUnorderedBitmask        = 4
	payloadDataImmediateSACK           = 8

	payloadDataHeaderSize = 12
)

// PayloadProtocolIdentifier is an enum for DataChannel payload types
type PayloadProtocolIdentifier uint32

// PayloadProtocolIdentifier enums
const (
	PayloadTypeWebRTCDCEP        PayloadProtocolIdentifier = 50
	PayloadTypeWebRTCString      PayloadProtocolIdentifier = 51
	PayloadTypeWebRTCBinary      PayloadProtocolIdentifier = 53
	PayloadTypeWebRTCStringEmpty PayloadProtocolIdentifier = 56
	PayloadTypeWebRTCBinaryEmpty PayloadProtocolIdentifier = 57
)

func (p PayloadProtocolIdentifier) String() string {
	switch p {
	case PayloadTypeWebRTCDCEP:
		return "WebRTC DCEP"
	case PayloadTypeWebRTCString:
		return "WebRTC String"
	case PayloadTypeWebRTCBinary:
		return "WebRTC Binary"
	case PayloadTypeWebRTCStringEmpty:
		return "WebRTC String (Empty)"
	case PayloadTypeWebRTCBinaryEmpty:
		return "WebRTC Binary (Empty)"
	default:
		return fmt.Sprintf("Unknown Payload Protocol Identifier: %d", p)
	}
}

func (p *chunkPayloadData) unmarshal(raw []byte) error {
	if err := p.chunkHeader.unmarshal(raw); err != nil {
		return err
	}

	p.immediateSack = p.flags&payloadDataImmediateSACK != 0
	p.unordered = p.flags&payloadDataUnorderedBitmask != 0
	p.beginingFragment = p.flags&payloadDataBeginingFragmentBitmask != 0
	p.endingFragment = p.flags&payloadDataEndingFragmentBitmask != 0

	p.tsn = binary.BigEndian.Uint32(p.raw[0:])
	p.streamIdentifier = binary.BigEndian.Uint16(p.raw[4:])
	p.streamSequenceNumber = binary.BigEndian.Uint16(p.raw[6:])
	p.payloadType = PayloadProtocolIdentifier(binary.BigEndian.Uint32(p.raw[8:]))
	p.userData = p.raw[payloadDataHeaderSize:]

	return nil
}

func (p *chunkPayloadData) marshal() ([]byte, error) {

	payRaw := make([]byte, payloadDataHeaderSize+len(p.userData))

	binary.BigEndian.PutUint32(payRaw[0:], p.tsn)
	binary.BigEndian.PutUint16(payRaw[4:], p.streamIdentifier)
	binary.BigEndian.PutUint16(payRaw[6:], p.streamSequenceNumber)
	binary.BigEndian.PutUint32(payRaw[8:], uint32(p.payloadType))
	copy(payRaw[payloadDataHeaderSize:], p.userData)

	flags := uint8(0)
	if p.endingFragment {
		flags = 1
	}
	if p.beginingFragment {
		flags |= 1 << 1
	}
	if p.unordered {
		flags |= 1 << 2
	}
	if p.immediateSack {
		flags |= 1 << 3
	}

	p.chunkHeader.flags = flags
	p.chunkHeader.typ = PAYLOADDATA
	p.chunkHeader.raw = payRaw
	return p.chunkHeader.marshal()
}

func (p *chunkPayloadData) check() (abort bool, err error) {
	return false, nil
}
<|endoftext|>


<commit_before>package utils

import (
	"encoding/binary"
	"errors"
	"fmt"
	"net"
	"os/exec"
	"strings"

	"github.com/docker/distribution"
	"github.com/docker/distribution/manifest/schema2"
)

// GetHostName returns host name
func GetHostName() (string, error) {
	out, err := exec.Command("bash", "-c", "echo $HOSTNAME").Output()
	name := strings.Trim(string(out[:]), "\n")
	if err != nil {
		return "", err
	}
	return name, nil
}

// GetIP returns ip given hostname
func GetIP(host string) (net.IP, error) {
	ips, err := net.LookupIP(host)
	if err != nil {
		return nil, err
	}

	for _, ip := range ips {
		if ip == nil || ip.IsLoopback() {
			continue
		}
		return ip, nil
	}
	return nil, fmt.Errorf("Error getting ip for %s", host)
}

// CompareByteArray compares two bytes array
func CompareByteArray(d1 []byte, d2 []byte) bool {
	if len(d1) != len(d2) {
		return false
	}

	n := len(d1)
	for i := 0; i < n; i++ {
		if d1[i] != d2[i] {
			return false
		}
	}

	return true
}

// GetLocalIP returns the non loopback local IP of the host
func GetLocalIP() (string, error) {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return "", err
	}
	for _, address := range addrs {
		// check the address type and if it is not a loopback the display it
		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				return ipnet.IP.String(), nil
			}
		}
	}
	return "", errors.New("Could not found any IPv4 network interface")
}

// IPtoInt32 converts net.IP address to int32
func IPtoInt32(ip net.IP) int32 {
	if len(ip) == 16 {
		return int32(binary.BigEndian.Uint32(ip[12:16]))
	}
	return int32(binary.BigEndian.Uint32(ip))
}

// Int32toIP converts int32  to net.IP
func Int32toIP(i32 int32) net.IP {
	ip := make(net.IP, 4)
	binary.BigEndian.PutUint32(ip, uint32(i32))
	return ip
}

// ParseManifestV2 returns a parsed v2 manifest and its digest
func ParseManifestV2(data []byte) (distribution.Manifest, string, error) {
	manifest, descriptor, err := distribution.UnmarshalManifest(schema2.MediaTypeManifest, data)
	if err != nil {
		return nil, "", err
	}
	deserializedManifest, ok := manifest.(*schema2.DeserializedManifest)
	if !ok {
		return nil, "", fmt.Errorf("Unable to deserialize manifest")
	}
	version := deserializedManifest.Manifest.Versioned.SchemaVersion
	if version != 2 {
		return nil, "", fmt.Errorf("Unsupported manifest version: %d", version)
	}
	return manifest, descriptor.Digest.Hex(), nil
}
<commit_msg>Ignore all local interfaces for ip discovery<commit_after>package utils

import (
	"encoding/binary"
	"errors"
	"fmt"
	"net"
	"os/exec"
	"strings"

	"github.com/docker/distribution"
	"github.com/docker/distribution/manifest/schema2"
)

// GetHostName returns host name
func GetHostName() (string, error) {
	out, err := exec.Command("bash", "-c", "echo $HOSTNAME").Output()
	name := strings.Trim(string(out[:]), "\n")
	if err != nil {
		return "", err
	}
	return name, nil
}

// GetIP returns ip given hostname
func GetIP(host string) (net.IP, error) {
	ips, err := net.LookupIP(host)
	if err != nil {
		return nil, err
	}

	for _, ip := range ips {
		if ip == nil || ip.IsLoopback() {
			continue
		}
		return ip, nil
	}
	return nil, fmt.Errorf("Error getting ip for %s", host)
}

// CompareByteArray compares two bytes array
func CompareByteArray(d1 []byte, d2 []byte) bool {
	if len(d1) != len(d2) {
		return false
	}

	n := len(d1)
	for i := 0; i < n; i++ {
		if d1[i] != d2[i] {
			return false
		}
	}

	return true
}

// GetLocalIP returns the first non loopback intreface's IP
func GetLocalIP() (string, error) {
	ifis, err := net.Interfaces()
	if err != nil {
		return "", err
	}
	for _, ifi := range ifis {
		// TODO: Extend for Running and UP maybe? (@igor)
		if ifi.Flags&net.FlagLoopback != 0 {
			continue
		}
		addrs, err := ifi.Addrs()
		if err != nil {
			return "", err
		}

		if len(addrs) > 0 {
			ipnet, _ := addrs[0].(*net.IPNet)
			if ipnet.IP.To4() != nil {
				return ipnet.IP.String(), nil
			}
		}
	}
	return "", errors.New("Could not found any IPv4 network interface")
}

// IPtoInt32 converts net.IP address to int32
func IPtoInt32(ip net.IP) int32 {
	if len(ip) == 16 {
		return int32(binary.BigEndian.Uint32(ip[12:16]))
	}
	return int32(binary.BigEndian.Uint32(ip))
}

// Int32toIP converts int32  to net.IP
func Int32toIP(i32 int32) net.IP {
	ip := make(net.IP, 4)
	binary.BigEndian.PutUint32(ip, uint32(i32))
	return ip
}

// ParseManifestV2 returns a parsed v2 manifest and its digest
func ParseManifestV2(data []byte) (distribution.Manifest, string, error) {
	manifest, descriptor, err := distribution.UnmarshalManifest(schema2.MediaTypeManifest, data)
	if err != nil {
		return nil, "", err
	}
	deserializedManifest, ok := manifest.(*schema2.DeserializedManifest)
	if !ok {
		return nil, "", fmt.Errorf("Unable to deserialize manifest")
	}
	version := deserializedManifest.Manifest.Versioned.SchemaVersion
	if version != 2 {
		return nil, "", fmt.Errorf("Unsupported manifest version: %d", version)
	}
	return manifest, descriptor.Digest.Hex(), nil
}
<|endoftext|>


<commit_before>package utils

import (
	"encoding/json"
	"errors"
	"fmt"
	"image"
	_ "image/jpeg"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/eirka/eirka-libs/amazon"
	"github.com/eirka/eirka-libs/config"

	local "github.com/eirka/eirka-post/config"
)

func (i *ImageType) SaveWebM() (err error) {

	// create unique filenames for image and thumbnail
	err = i.makeFilenames()
	if err != nil {
		return
	}

	// save the file
	err = i.saveFile()
	if err != nil {
		return
	}

	// check the webm info
	err = i.checkWebM()
	if err != nil {
		return
	}

	// create thumbnail from webm
	err = i.createWebMThumbnail()
	if err != nil {
		return
	}

	return

}

// check webm metadata to make sure its the correct type of video, size, etc
func (i *ImageType) checkWebM() (err error) {
	imagefile := filepath.Join(local.Settings.Directories.ImageDir, i.Filename)

	avprobeArgs := []string{
		"-v",
		"quiet",
		"-of",
		"json",
		"-show_format",
		"-show_streams",
		imagefile,
	}

	cmd, err := exec.Command("avprobe", avprobeArgs...).Output()
	if err != nil {
		return errors.New("problem decoding webm")
	}

	avprobe := avprobe{}

	err = json.Unmarshal(cmd, &avprobe)
	if err != nil {
		return errors.New("problem decoding webm")
	}

	// allowed codecs
	codecs := map[string]bool{
		"vp8": true,
		"vp9": true,
	}

	switch {
	case avprobe.Format.FormatName != "matroska,webm":
		return errors.New("file is not vp8 video")
	case !codecs[strings.ToLower(avprobe.Streams[0].CodecName)]:
		return errors.New("file is not allowed webm codec")
	}

	duration, err := strconv.ParseFloat(avprobe.Format.Duration, 64)
	if err != nil {
		return errors.New("problem decoding webm")
	}

	// set file duration
	i.duration = int(duration)

	orig_size, err := strconv.ParseFloat(avprobe.Format.Size, 64)
	if err != nil {
		return
	}

	i.OrigWidth = avprobe.Streams[0].Width
	i.OrigHeight = avprobe.Streams[0].Height

	// Check against maximum sizes
	switch {
	case i.OrigWidth > config.Settings.Limits.ImageMaxWidth:
		return errors.New("webm width too large")
	case i.OrigWidth < config.Settings.Limits.ImageMinWidth:
		return errors.New("webm width too small")
	case i.OrigHeight > config.Settings.Limits.ImageMaxHeight:
		return errors.New("webm height too large")
	case i.OrigHeight < config.Settings.Limits.ImageMinHeight:
		return errors.New("webm height too small")
	case int(orig_size) > config.Settings.Limits.ImageMaxSize:
		return errors.New("webm size too large")
	case i.duration > config.Settings.Limits.WebmMaxLength:
		return errors.New("webm too long")
	}

	return

}

// create a webm thumbnail from the first frames
func (i *ImageType) createWebMThumbnail() (err error) {
	imagefile := filepath.Join(local.Settings.Directories.ImageDir, i.Filename)
	thumbfile := filepath.Join(local.Settings.Directories.ThumbnailDir, i.Thumbnail)

	var timepoint string

	// set the time when the screenshot is taken depending on video duration
	if i.duration > 5 {
		timepoint = "00:00:05"
	} else {
		timepoint = "00:00:00"
	}

	avconvArgs := []string{
		"-i",
		imagefile,
		"-v",
		"quiet",
		"-ss",
		timepoint,
		"-an",
		"-vframes",
		"1",
		"-f",
		"mjpeg",
		thumbfile,
	}

	// Make an image of first frame with avconv
	_, err = exec.Command("avconv", avconvArgs...).Output()
	if err != nil {
		return errors.New("problem decoding webm")
	}

	orig_dimensions := fmt.Sprintf("%dx%d", i.OrigWidth, i.OrigHeight)
	thumb_dimensions := fmt.Sprintf("%dx%d>", config.Settings.Limits.ThumbnailMaxWidth, config.Settings.Limits.ThumbnailMaxHeight)
	imagef := fmt.Sprintf("%s[0]", thumbfile)

	args := []string{
		"-background",
		"white",
		"-flatten",
		"-size",
		orig_dimensions,
		"-resize",
		thumb_dimensions,
		"-quality",
		"90",
		imagef,
		thumbfile,
	}

	_, err = exec.Command("convert", args...).Output()
	if err != nil {
		return errors.New("problem making thumbnail")
	}

	thumb, err := os.Open(thumbfile)
	if err != nil {
		return errors.New("problem making thumbnail")
	}
	defer thumb.Close()

	img, _, err := image.DecodeConfig(thumb)
	if err != nil {
		return errors.New("problem decoding thumbnail")
	}

	i.ThumbWidth = img.Width
	i.ThumbHeight = img.Height

	s3 := amazon.New()

	err = s3.Save(thumbfile, fmt.Sprintf("thumb/%s", i.Thumbnail), "video/webm")
	if err != nil {
		return
	}

	return

}

// avprobe json format
type avprobe struct {
	Format struct {
		Filename       string `json:"filename"`
		NbStreams      int    `json:"nb_streams"`
		FormatName     string `json:"format_name"`
		FormatLongName string `json:"format_long_name"`
		StartTime      string `json:"start_time"`
		Duration       string `json:"duration"`
		Size           string `json:"size"`
		BitRate        string `json:"bit_rate"`
	} `json:"format"`
	Streams []struct {
		Index              int    `json:"index"`
		CodecName          string `json:"codec_name"`
		CodecLongName      string `json:"codec_long_name"`
		CodecType          string `json:"codec_type"`
		CodecTimeBase      string `json:"codec_time_base"`
		CodecTagString     string `json:"codec_tag_string"`
		CodecTag           string `json:"codec_tag"`
		Width              int    `json:"width"`
		Height             int    `json:"height"`
		HasBFrames         int    `json:"has_b_frames"`
		SampleAspectRatio  string `json:"sample_aspect_ratio"`
		DisplayAspectRatio string `json:"display_aspect_ratio"`
		PixFmt             string `json:"pix_fmt"`
		Level              int    `json:"level"`
		AvgFrameRate       string `json:"avg_frame_rate"`
		TimeBase           string `json:"time_base"`
		StartTime          string `json:"start_time"`
		Duration           string `json:"duration"`
	} `json:"streams"`
}
<commit_msg>fix webm thumbnail mime type<commit_after>package utils

import (
	"encoding/json"
	"errors"
	"fmt"
	"image"
	_ "image/jpeg"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/eirka/eirka-libs/amazon"
	"github.com/eirka/eirka-libs/config"

	local "github.com/eirka/eirka-post/config"
)

func (i *ImageType) SaveWebM() (err error) {

	// create unique filenames for image and thumbnail
	err = i.makeFilenames()
	if err != nil {
		return
	}

	// save the file
	err = i.saveFile()
	if err != nil {
		return
	}

	// check the webm info
	err = i.checkWebM()
	if err != nil {
		return
	}

	// create thumbnail from webm
	err = i.createWebMThumbnail()
	if err != nil {
		return
	}

	return

}

// check webm metadata to make sure its the correct type of video, size, etc
func (i *ImageType) checkWebM() (err error) {
	imagefile := filepath.Join(local.Settings.Directories.ImageDir, i.Filename)

	avprobeArgs := []string{
		"-v",
		"quiet",
		"-of",
		"json",
		"-show_format",
		"-show_streams",
		imagefile,
	}

	cmd, err := exec.Command("avprobe", avprobeArgs...).Output()
	if err != nil {
		return errors.New("problem decoding webm")
	}

	avprobe := avprobe{}

	err = json.Unmarshal(cmd, &avprobe)
	if err != nil {
		return errors.New("problem decoding webm")
	}

	// allowed codecs
	codecs := map[string]bool{
		"vp8": true,
		"vp9": true,
	}

	switch {
	case avprobe.Format.FormatName != "matroska,webm":
		return errors.New("file is not vp8 video")
	case !codecs[strings.ToLower(avprobe.Streams[0].CodecName)]:
		return errors.New("file is not allowed webm codec")
	}

	duration, err := strconv.ParseFloat(avprobe.Format.Duration, 64)
	if err != nil {
		return errors.New("problem decoding webm")
	}

	// set file duration
	i.duration = int(duration)

	orig_size, err := strconv.ParseFloat(avprobe.Format.Size, 64)
	if err != nil {
		return
	}

	i.OrigWidth = avprobe.Streams[0].Width
	i.OrigHeight = avprobe.Streams[0].Height

	// Check against maximum sizes
	switch {
	case i.OrigWidth > config.Settings.Limits.ImageMaxWidth:
		return errors.New("webm width too large")
	case i.OrigWidth < config.Settings.Limits.ImageMinWidth:
		return errors.New("webm width too small")
	case i.OrigHeight > config.Settings.Limits.ImageMaxHeight:
		return errors.New("webm height too large")
	case i.OrigHeight < config.Settings.Limits.ImageMinHeight:
		return errors.New("webm height too small")
	case int(orig_size) > config.Settings.Limits.ImageMaxSize:
		return errors.New("webm size too large")
	case i.duration > config.Settings.Limits.WebmMaxLength:
		return errors.New("webm too long")
	}

	return

}

// create a webm thumbnail from the first frames
func (i *ImageType) createWebMThumbnail() (err error) {
	imagefile := filepath.Join(local.Settings.Directories.ImageDir, i.Filename)
	thumbfile := filepath.Join(local.Settings.Directories.ThumbnailDir, i.Thumbnail)

	var timepoint string

	// set the time when the screenshot is taken depending on video duration
	if i.duration > 5 {
		timepoint = "00:00:05"
	} else {
		timepoint = "00:00:00"
	}

	avconvArgs := []string{
		"-i",
		imagefile,
		"-v",
		"quiet",
		"-ss",
		timepoint,
		"-an",
		"-vframes",
		"1",
		"-f",
		"mjpeg",
		thumbfile,
	}

	// Make an image of first frame with avconv
	_, err = exec.Command("avconv", avconvArgs...).Output()
	if err != nil {
		return errors.New("problem decoding webm")
	}

	orig_dimensions := fmt.Sprintf("%dx%d", i.OrigWidth, i.OrigHeight)
	thumb_dimensions := fmt.Sprintf("%dx%d>", config.Settings.Limits.ThumbnailMaxWidth, config.Settings.Limits.ThumbnailMaxHeight)
	imagef := fmt.Sprintf("%s[0]", thumbfile)

	args := []string{
		"-background",
		"white",
		"-flatten",
		"-size",
		orig_dimensions,
		"-resize",
		thumb_dimensions,
		"-quality",
		"90",
		imagef,
		thumbfile,
	}

	_, err = exec.Command("convert", args...).Output()
	if err != nil {
		return errors.New("problem making thumbnail")
	}

	thumb, err := os.Open(thumbfile)
	if err != nil {
		return errors.New("problem making thumbnail")
	}
	defer thumb.Close()

	img, _, err := image.DecodeConfig(thumb)
	if err != nil {
		return errors.New("problem decoding thumbnail")
	}

	i.ThumbWidth = img.Width
	i.ThumbHeight = img.Height

	s3 := amazon.New()

	err = s3.Save(thumbfile, fmt.Sprintf("thumb/%s", i.Thumbnail), "image/jpeg")
	if err != nil {
		return
	}

	return

}

// avprobe json format
type avprobe struct {
	Format struct {
		Filename       string `json:"filename"`
		NbStreams      int    `json:"nb_streams"`
		FormatName     string `json:"format_name"`
		FormatLongName string `json:"format_long_name"`
		StartTime      string `json:"start_time"`
		Duration       string `json:"duration"`
		Size           string `json:"size"`
		BitRate        string `json:"bit_rate"`
	} `json:"format"`
	Streams []struct {
		Index              int    `json:"index"`
		CodecName          string `json:"codec_name"`
		CodecLongName      string `json:"codec_long_name"`
		CodecType          string `json:"codec_type"`
		CodecTimeBase      string `json:"codec_time_base"`
		CodecTagString     string `json:"codec_tag_string"`
		CodecTag           string `json:"codec_tag"`
		Width              int    `json:"width"`
		Height             int    `json:"height"`
		HasBFrames         int    `json:"has_b_frames"`
		SampleAspectRatio  string `json:"sample_aspect_ratio"`
		DisplayAspectRatio string `json:"display_aspect_ratio"`
		PixFmt             string `json:"pix_fmt"`
		Level              int    `json:"level"`
		AvgFrameRate       string `json:"avg_frame_rate"`
		TimeBase           string `json:"time_base"`
		StartTime          string `json:"start_time"`
		Duration           string `json:"duration"`
	} `json:"streams"`
}
<|endoftext|>


<commit_before>// 5 october 2014
package main

import (
	"net/url"
	"os"
	"path/filepath"

	"github.com/andlabs/ohv/internal/ui"
)

type HelpSource interface {
	Name() string
	Books() []Topic
	Orphans() []Topic
//	SharedAssets() []Asset
	Lookup(url *url.URL) Topic
}

type Topic interface {
	ui.TreeNode
	Name() string
	Prepare() (*Prepared, error)
	Parent() Topic
	Children() []Topic
	Source() HelpSource
	Less(t Topic) bool
}

type Prepared struct {
	Path			string
	CSSPath		string
	CSSBaseDir	string
}

type TopicSorter []Topic

func (t TopicSorter) Len() int { return len(t) }
func (t TopicSorter) Less(i, j int) bool { return t[i].Less(t[j]) }
func (t TopicSorter) Swap(i, j int) { t[i], t[j] = t[j], t[i] }

type LibraryModel struct {
	library	[]Topic
	model	*ui.TreeModel
}

var Library LibraryModel

func (l *LibraryModel) Append(topic Topic) {
	l.library = append(l.library, topic)
	if l.model != nil {
		l.model.RowInserted(topic, nil, len(l.library) - 1)
	}
}

func (l *LibraryModel) RootNodes() []ui.TreeNode {
	if len(l.library) == 0 {
		return nil
	}
	c := make([]ui.TreeNode, len(l.library))
	for i, n := range l.library {
		c[i] = n
	}
	return c
}

func (l *LibraryModel) MakeModel() {
	l.model = ui.NewTreeModel(l)
	for i, topic := range l.library {
		l.model.RowInserted(topic, nil, i)
	}
}

func (l *LibraryModel) Model() *ui.TreeModel {
	return l.model
}

func LoadMSHILibrary(dir string) {
	m, err := OpenMSHI(filepath.Join(dir, "mshi"))
	if err != nil {
		// TODO
		panic(err)
	}
	for _, b := range m.Books() {
		Library.Append(b)
	}
}

func LoadAppleLibraries(dir string) {
	dir = filepath.Join(dir, "apple")
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		// TODO better check
		if path == dir {
			return nil
		}
		a, err := OpenApple(path)
		if err != nil {
			return err
		}
		for _, b := range a.Books() {
			Library.Append(b)
		}
		return filepath.SkipDir
	})
	if err != nil {
		// TODO
		panic(err)
	}
}

func LoadLibraries() {
	// all directories /must/ be absolute
	dir, err := filepath.Abs(os.Args[1])
	if err != nil {
		// TODO
		panic(err)
	}
	LoadMSHILibrary(dir)
	LoadAppleLibraries(dir)
}
<commit_msg>More TODOs.<commit_after>// 5 october 2014
package main

import (
	"net/url"
	"os"
	"path/filepath"

	"github.com/andlabs/ohv/internal/ui"
)

type HelpSource interface {
	Name() string
	Books() []Topic
	Orphans() []Topic
//	SharedAssets() []Asset
	Lookup(url *url.URL) Topic
}

type Topic interface {
	ui.TreeNode
	Name() string
	Prepare() (*Prepared, error)
	Parent() Topic
	Children() []Topic
	Source() HelpSource
	Less(t Topic) bool
}

type Prepared struct {
	Path			string
	CSSPath		string
	CSSBaseDir	string
}

type TopicSorter []Topic

func (t TopicSorter) Len() int { return len(t) }
func (t TopicSorter) Less(i, j int) bool { return t[i].Less(t[j]) }
func (t TopicSorter) Swap(i, j int) { t[i], t[j] = t[j], t[i] }

type LibraryModel struct {
	library	[]Topic
	model	*ui.TreeModel
}

var Library LibraryModel

func (l *LibraryModel) Append(topic Topic) {
	l.library = append(l.library, topic)
	if l.model != nil {
		l.model.RowInserted(topic, nil, len(l.library) - 1)
	}
}

func (l *LibraryModel) RootNodes() []ui.TreeNode {
	if len(l.library) == 0 {
		return nil
	}
	c := make([]ui.TreeNode, len(l.library))
	for i, n := range l.library {
		c[i] = n
	}
	return c
}

func (l *LibraryModel) MakeModel() {
	l.model = ui.NewTreeModel(l)
	for i, topic := range l.library {
		l.model.RowInserted(topic, nil, i)
	}
}

func (l *LibraryModel) Model() *ui.TreeModel {
	return l.model
}

func LoadMSHILibrary(dir string) {
	m, err := OpenMSHI(filepath.Join(dir, "mshi"))
	if err != nil {
		// TODO
		panic(err)
	}
	for _, b := range m.Books() {
		Library.Append(b)
	}
}

func LoadAppleLibraries(dir string) {
	dir = filepath.Join(dir, "apple")
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		// TODO better check
		if path == dir {
			return nil
		}
		a, err := OpenApple(path)
		if err != nil {
			return err
		}
		for _, b := range a.Books() {
			Library.Append(b)
		}
		return filepath.SkipDir
	})
	if err != nil {
		// TODO
		panic(err)
	}
}

func LoadLibraries() {
	// all directories /must/ be absolute
	dir, err := filepath.Abs(os.Args[1])
	if err != nil {
		// TODO
		panic(err)
	}
	LoadMSHILibrary(dir)
	// TODO load from system installation path
	LoadAppleLibraries(dir)
}
<|endoftext|>


<commit_before>package cliedit

import (
	"github.com/elves/elvish/cli"
	"github.com/elves/elvish/cli/addons/completion"
	"github.com/elves/elvish/cliedit/complete"
	"github.com/elves/elvish/eval"
	"github.com/elves/elvish/parse"
)

//elvdoc:var completion:binding
//
// Keybinding for the completion mode.

//elvdoc:fn completion:start
//
// Start the completion mode

func initCompletion(app *cli.App, ev *eval.Evaler, ns eval.Ns) {
	bindingVar := newBindingVar(emptyBindingMap)
	binding := newMapBinding(app, ev, bindingVar)
	ns.AddNs("completion",
		eval.Ns{
			"binding": bindingVar,
		}.AddGoFn("<edit:completion", "start", func() {
			buf := app.CodeArea.CopyState().CodeBuffer
			name, items, err := complete.Complete(
				complete.CodeBuffer{Content: buf.Content, Dot: buf.Dot},
				complete.Config{PureEvaler: pureEvaler{ev}})
			if err != nil {
				app.Notify(err.Error())
				return
			}
			completion.Start(app,
				completion.Config{Binding: binding, Type: name, Items: items})
		}))
}

type pureEvaler struct{ ev *eval.Evaler }

func (pureEvaler) EachExternal(f func(string)) { eval.EachExternal(f) }

func (pureEvaler) EachSpecial(f func(string)) {
	for name := range eval.IsBuiltinSpecial {
		f(name)
	}
}

func (pe pureEvaler) EachNs(f func(string)) { pe.ev.EachNsInTop(f) }

func (pe pureEvaler) EachVariableInNs(ns string, f func(string)) {
	pe.ev.EachVariableInTop(ns, f)
}

func (pe pureEvaler) PurelyEvalPrimary(pn *parse.Primary) interface{} {
	return pe.ev.PurelyEvalPrimary(pn)
}

func (pe pureEvaler) PurelyEvalCompound(cn *parse.Compound) (string, error) {
	return pe.ev.PurelyEvalCompound(cn)
}

func (pe pureEvaler) PurelyEvalPartialCompound(cn *parse.Compound, in *parse.Indexing) (string, error) {
	return pe.ev.PurelyEvalPartialCompound(cn, in)
}
<commit_msg>cliedit: Use prefix filtering for completion.<commit_after>package cliedit

import (
	"github.com/elves/elvish/cli"
	"github.com/elves/elvish/cli/addons/completion"
	"github.com/elves/elvish/cliedit/complete"
	"github.com/elves/elvish/eval"
	"github.com/elves/elvish/parse"
)

//elvdoc:var completion:binding
//
// Keybinding for the completion mode.

//elvdoc:fn completion:start
//
// Start the completion mode

func initCompletion(app *cli.App, ev *eval.Evaler, ns eval.Ns) {
	bindingVar := newBindingVar(emptyBindingMap)
	binding := newMapBinding(app, ev, bindingVar)
	ns.AddNs("completion",
		eval.Ns{
			"binding": bindingVar,
		}.AddGoFn("<edit:completion", "start", func() {
			buf := app.CodeArea.CopyState().CodeBuffer
			name, items, err := complete.Complete(
				complete.CodeBuffer{Content: buf.Content, Dot: buf.Dot},
				complete.Config{
					Filter:     complete.PrefixFilter,
					PureEvaler: pureEvaler{ev},
				})
			if err != nil {
				app.Notify(err.Error())
				return
			}
			completion.Start(app,
				completion.Config{Binding: binding, Type: name, Items: items})
		}))
}

type pureEvaler struct{ ev *eval.Evaler }

func (pureEvaler) EachExternal(f func(string)) { eval.EachExternal(f) }

func (pureEvaler) EachSpecial(f func(string)) {
	for name := range eval.IsBuiltinSpecial {
		f(name)
	}
}

func (pe pureEvaler) EachNs(f func(string)) { pe.ev.EachNsInTop(f) }

func (pe pureEvaler) EachVariableInNs(ns string, f func(string)) {
	pe.ev.EachVariableInTop(ns, f)
}

func (pe pureEvaler) PurelyEvalPrimary(pn *parse.Primary) interface{} {
	return pe.ev.PurelyEvalPrimary(pn)
}

func (pe pureEvaler) PurelyEvalCompound(cn *parse.Compound) (string, error) {
	return pe.ev.PurelyEvalCompound(cn)
}

func (pe pureEvaler) PurelyEvalPartialCompound(cn *parse.Compound, in *parse.Indexing) (string, error) {
	return pe.ev.PurelyEvalPartialCompound(cn, in)
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"net"
	"net/mail"
	"net/url"
	"reflect"
)

var (
	errNil       = fmt.Errorf("the value is nil")
	errStrEmtpy  = fmt.Errorf("the string is empty")
	errStrType   = fmt.Errorf("the value is not string type")
	errIntType   = fmt.Errorf("the value is not an integer type")
	errFloatType = fmt.Errorf("the value is not an float type")
)

func toString(v interface{}) (string, error) {
	if v == nil {
		return "", errNil
	}
	if s, ok := v.(string); ok {
		return s, nil
	}
	return "", errStrType
}

func toInt64(v interface{}) (int64, error) {
	if v == nil {
		return 0, errNil
	}

	switch v.(type) {
	case int, int8, int16, int32, int64:
		return reflect.ValueOf(v).Int(), nil
	case uint, uint8, uint16, uint32, uint64:
		return int64(reflect.ValueOf(v).Uint()), nil
	default:
		return 0, errIntType
	}
}

func toFloat64(v interface{}) (float64, error) {
	if v == nil {
		return 0, errNil
	}

	switch v.(type) {
	case float32, float64:
		return reflect.ValueOf(v).Float(), nil
	default:
		return 0, errFloatType
	}
}

type strLenValidator struct {
	min int
	max int
}

// NewStrLenValidator returns a validator to validate that the length of the
// string must be between min and max.
func NewStrLenValidator(min, max int) Validator {
	return strLenValidator{min: min, max: max}
}

func (sv strLenValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}

	_len := len(s)
	if _len > sv.max || _len < sv.min {
		return fmt.Errorf("the length of %s is %d, not between %d and %d",
			s, _len, sv.min, sv.max)
	}
	return nil
}

type notEmptyStrValidator struct{}

func (e notEmptyStrValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}

	if len(s) == 0 {
		return errStrEmtpy
	}
	return nil
}

var strNotEmptyV = notEmptyStrValidator{}

// NewStrNotEmptyValidator returns a validator to validate that the value must
// not be an empty string.
func NewStrNotEmptyValidator() Validator {
	return strNotEmptyV
}

type urlValidator struct{}

func (u urlValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}
	_, err = url.Parse(s)
	return err
}

var urlV = urlValidator{}

// NewURLValidator returns a validator to validate whether a url is valid.
func NewURLValidator() Validator {
	return urlV
}

type ipValidator struct{}

func (i ipValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}
	if net.ParseIP(s) == nil {
		return fmt.Errorf("the value is not a valid ip")
	}
	return nil
}

var ipV = ipValidator{}

// NewIPValidator returns a validator to validate whether an ip is valid.
func NewIPValidator() Validator {
	return ipV
}

type integerRangeValidator struct {
	min int64
	max int64
}

func (r integerRangeValidator) Validate(v interface{}) error {
	i, err := toInt64(v)
	if err != nil {
		return err
	}
	if r.min > i || i > r.max {
		return fmt.Errorf("the value %d is not between %d and %d",
			i, r.min, r.max)
	}
	return nil
}

// NewIntegerRangeValidator returns a validator to validate whether the integer
// value is between the min and the max.
func NewIntegerRangeValidator(min, max int64) Validator {
	return integerRangeValidator{min: min, max: max}
}

type floatRangeValidator struct {
	min float64
	max float64
}

func (r floatRangeValidator) Validate(v interface{}) error {
	f, err := toFloat64(v)
	if err != nil {
		return err
	}
	if r.min > f || f > r.max {
		return fmt.Errorf("the value %f is not between %f and %f",
			f, r.min, r.max)
	}
	return nil
}

// NewFloatRangeValidator returns a validator to validate whether the float
// value is between the min and the max.
func NewFloatRangeValidator(min, max float64) Validator {
	return floatRangeValidator{min: min, max: max}
}

var portValidator = NewIntegerRangeValidator(0, 65535)

// NewPortValidator returns a validator to validate whether a port is between
// 0 and 65535.
func NewPortValidator() Validator {
	return portValidator
}

type emailValidator struct{}

func (e emailValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}
	_, err = mail.ParseAddress(s)
	return err
}

var emailV = emailValidator{}

// NewEmailValidator returns a validator to validate whether an email is valid.
func NewEmailValidator() Validator {
	return emailV
}
<commit_msg>Add the address validator.<commit_after>package config

import (
	"fmt"
	"net"
	"net/mail"
	"net/url"
	"reflect"
)

var (
	errNil       = fmt.Errorf("the value is nil")
	errStrEmtpy  = fmt.Errorf("the string is empty")
	errStrType   = fmt.Errorf("the value is not string type")
	errIntType   = fmt.Errorf("the value is not an integer type")
	errFloatType = fmt.Errorf("the value is not an float type")
)

func toString(v interface{}) (string, error) {
	if v == nil {
		return "", errNil
	}
	if s, ok := v.(string); ok {
		return s, nil
	}
	return "", errStrType
}

func toInt64(v interface{}) (int64, error) {
	if v == nil {
		return 0, errNil
	}

	switch v.(type) {
	case int, int8, int16, int32, int64:
		return reflect.ValueOf(v).Int(), nil
	case uint, uint8, uint16, uint32, uint64:
		return int64(reflect.ValueOf(v).Uint()), nil
	default:
		return 0, errIntType
	}
}

func toFloat64(v interface{}) (float64, error) {
	if v == nil {
		return 0, errNil
	}

	switch v.(type) {
	case float32, float64:
		return reflect.ValueOf(v).Float(), nil
	default:
		return 0, errFloatType
	}
}

type strLenValidator struct {
	min int
	max int
}

// NewStrLenValidator returns a validator to validate that the length of the
// string must be between min and max.
func NewStrLenValidator(min, max int) Validator {
	return strLenValidator{min: min, max: max}
}

func (sv strLenValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}

	_len := len(s)
	if _len > sv.max || _len < sv.min {
		return fmt.Errorf("the length of %s is %d, not between %d and %d",
			s, _len, sv.min, sv.max)
	}
	return nil
}

type notEmptyStrValidator struct{}

func (e notEmptyStrValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}

	if len(s) == 0 {
		return errStrEmtpy
	}
	return nil
}

var strNotEmptyV = notEmptyStrValidator{}

// NewStrNotEmptyValidator returns a validator to validate that the value must
// not be an empty string.
func NewStrNotEmptyValidator() Validator {
	return strNotEmptyV
}

type urlValidator struct{}

func (u urlValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}
	_, err = url.Parse(s)
	return err
}

var urlV = urlValidator{}

// NewURLValidator returns a validator to validate whether a url is valid.
func NewURLValidator() Validator {
	return urlV
}

type ipValidator struct{}

func (i ipValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}
	if net.ParseIP(s) == nil {
		return fmt.Errorf("the value is not a valid ip")
	}
	return nil
}

var ipV = ipValidator{}

// NewIPValidator returns a validator to validate whether an ip is valid.
func NewIPValidator() Validator {
	return ipV
}

type integerRangeValidator struct {
	min int64
	max int64
}

func (r integerRangeValidator) Validate(v interface{}) error {
	i, err := toInt64(v)
	if err != nil {
		return err
	}
	if r.min > i || i > r.max {
		return fmt.Errorf("the value %d is not between %d and %d",
			i, r.min, r.max)
	}
	return nil
}

// NewIntegerRangeValidator returns a validator to validate whether the integer
// value is between the min and the max.
func NewIntegerRangeValidator(min, max int64) Validator {
	return integerRangeValidator{min: min, max: max}
}

type floatRangeValidator struct {
	min float64
	max float64
}

func (r floatRangeValidator) Validate(v interface{}) error {
	f, err := toFloat64(v)
	if err != nil {
		return err
	}
	if r.min > f || f > r.max {
		return fmt.Errorf("the value %f is not between %f and %f",
			f, r.min, r.max)
	}
	return nil
}

// NewFloatRangeValidator returns a validator to validate whether the float
// value is between the min and the max.
func NewFloatRangeValidator(min, max float64) Validator {
	return floatRangeValidator{min: min, max: max}
}

var portValidator = NewIntegerRangeValidator(0, 65535)

// NewPortValidator returns a validator to validate whether a port is between
// 0 and 65535.
func NewPortValidator() Validator {
	return portValidator
}

type emailValidator struct{}

func (e emailValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}
	_, err = mail.ParseAddress(s)
	return err
}

var emailV = emailValidator{}

// NewEmailValidator returns a validator to validate whether an email is valid.
func NewEmailValidator() Validator {
	return emailV
}

type addressValidator struct{}

func (a addressValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}
	_, _, err = net.SplitHostPort(s)
	return err
}

var addressV = addressValidator{}

// NewAddressValidator returns a validator to validate whether an address is
// like "host:port", "host%zone:port", "[host]:port" or "[host%zone]:port".
//
// This validator uses net.SplitHostPort() to validate it.
func NewAddressValidator() Validator {
	return addressV
}
<|endoftext|>


<commit_before>package client_test

import (
	"path/filepath"
	"testing"

	"github.com/lkingland/faas/client"
	"github.com/lkingland/faas/client/mock"
)

// TestInvalidDomain ensures that creating from a directory strucutre
// where the domain can not be derived while simultaneously failing to provide
// an explicit name fails.
func TestInvalidDomain(t *testing.T) {
	_, err := client.New(
		// Ensure no domain is found even if we are actually running within a path
		// from which a domain could be derived.
		client.WithDomainSearchLimit(0),
	)
	if err == nil {
		t.Fatal("no error generated for unspecified and underivable name")
	}
}

// TestCreate ensures that instantiation completes without error when provided with a
// language.  A single client instance services a single Service Function instance
// and as such requires the desired effective DNS for the function.  This is an optional
// parameter, as it is intended to be derived from directory path.
func TestCreate(t *testing.T) {
	client, err := client.New(client.WithName("my.example.com"))
	if err != nil {
		t.Fatal(err)
	}
	// missing language shold error
	if err := client.Create(""); err == nil {
		t.Fatal("missing language did not generate error")
	}
	// Any language provided works by default, with the concrete implementation
	// of the initializer being the decider if the language provided is supported.
	if err := client.Create("go"); err != nil {
		t.Fatal(err)
	}
}

// TestCreateInitializes ensures that a call to Create invokes the Service
// Function Initializer with correct parameters.
func TestCreateInitializes(t *testing.T) {
	initializer := mock.NewInitializer()
	client, err := client.New(
		client.WithRoot("./testdata/example.com/admin"), // set function root
		client.WithInitializer(initializer),             // will receive the final value
	)
	if err != nil {
		t.Fatal(err)
	}
	initializer.InitializeFn = func(name, language, path string) error {
		if name != "admin.example.com" {
			t.Fatalf("initializer expected name 'admin.example.com', got '%v'", name)
		}
		if language != "go" {
			t.Fatalf("initializer expected language 'go', got '%v'", language)
		}
		expectedPath, err := filepath.Abs("./testdata/example.com/admin")
		if err != nil {
			t.Fatal(err)
		}
		if path != expectedPath {
			t.Fatalf("initializer expected path '%v', got '%v'", expectedPath, path)
		}
		return nil
	}
	if err := client.Create("go"); err != nil {
		t.Fatal(err)
	}
	if !initializer.InitializeInvoked {
		t.Fatal("initializer was not invoked")
	}
}

// TestDeploy ensures that a call to Deploy invokes the Sevice Function
// Deployer with the correct parameters.
func TestDeploy(t *testing.T) {
	deployer := mock.NewDeployer()
	client, err := client.New(
		client.WithRoot("./testdata/example.com/admin"), // set function root
		client.WithDeployer(deployer),                   // will receive the final value
	)
	if err != nil {
		t.Fatal(err)
	}
	deployer.DeployFn = func(name, path string) (address string, err error) {
		if name != "admin.example.com" {
			t.Fatalf("deployer expected name 'admin.example.com', got '%v'", name)
		}
		expectedPath, err := filepath.Abs("./testdata/example.com/admin")
		if err != nil {
			t.Fatal(err)
		}
		if path != expectedPath {
			t.Fatalf("deployer expected path '%v', got '%v'", expectedPath, path)
		}
		return
	}
	if err := client.Deploy(); err != nil {
		t.Fatal(err)
	}
	if !deployer.DeployInvoked {
		t.Fatal("deployer was not invoked")
	}
}

// TestDeployDomain ensures that the effective domain is dervied from
// directory structure.  See the unit tests for pathToDomain for details.
func TestDeployDomain(t *testing.T) {
	// the mock dns provider does nothing but receive the caluclated
	// domain name via it's Provide(domain) method, which is the value
	// being tested here.
	dnsProvider := mock.NewDNSProvider()

	client, err := client.New(
		client.WithRoot("./testdata/example.com"), // set function root
		client.WithDomainSearchLimit(1),           // Limit recursion to one level
		client.WithDNSProvider(dnsProvider),       // will receive the final value
	)
	if err != nil {
		t.Fatal(err)
	}

	if err := client.Deploy(); err != nil {
		t.Fatal(err)
	}
	if !dnsProvider.ProvideInvoked {
		t.Fatal("dns provider was not invoked")
	}
	if dnsProvider.NameRequested != "example.com" {
		t.Fatalf("expected 'example.com', got '%v'", dnsProvider.NameRequested)
	}
}

// TestDeploySubdomain ensures that a subdirectory is interpreted as a subdomain
// when calculating final domain.  See the unit tests for pathToDomain for the
// details and edge cases of this caluclation.
func TestDeploySubdomain(t *testing.T) {
	dnsProvider := mock.NewDNSProvider()
	client, err := client.New(
		client.WithRoot("./testdata/example.com/admin"),
		client.WithDomainSearchLimit(2),
		client.WithDNSProvider(dnsProvider),
	)
	if err != nil {
		t.Fatal(err)
	}
	if err := client.Deploy(); err != nil {
		t.Fatal(err)
	}
	if !dnsProvider.ProvideInvoked {
		t.Fatal("dns provider was not invoked")
	}
	if dnsProvider.NameRequested != "admin.example.com" {
		t.Fatalf("expected 'admin.example.com', got '%v'", dnsProvider.NameRequested)
	}
}

// TestRun ensures that the runner is invoked with the absolute path requested.
func TestRun(t *testing.T) {
	root := "./testdata/example.com/admin"
	runner := mock.NewRunner()
	client, err := client.New(
		client.WithRoot(root),
		client.WithRunner(runner),
	)
	if err != nil {
		t.Fatal(err)
	}
	if err := client.Run(); err != nil {
		t.Fatal(err)
	}
	if !runner.RunInvoked {
		t.Fatal("run did not invoke the runner")
	}
	absRoot, err := filepath.Abs(root)
	if err != nil {
		t.Fatal(err)
	}
	if runner.RootRequested != absRoot {
		t.Fatalf("expected path '%v', got '%v'", absRoot, runner.RootRequested)
	}

}
<commit_msg>tests restructuring and expansion<commit_after>package client_test

import (
	"path/filepath"
	"testing"

	"github.com/lkingland/faas/client"
	"github.com/lkingland/faas/client/mock"
)

// TestNew ensures that instantiation succeeds when invoked normally
// and fails if not given a deriveable domain.
func TestNew(t *testing.T) {
	// Instantiation with optional explicit service name should succeed.
	_, err := client.New(
		client.WithName("my.example.com"), // be explicity rather than path-derive
	)
	if err != nil {
		t.Fatal(err)
	}

	// Instantiation with optional verbosity should succeed.
	_, err = client.New(
		client.WithName("my.example.com"),
		client.WithVerbose(true),
	)
	if err != nil {
		t.Fatal(err)
	}

	// Instantiation without an explicit service name, and no derivable service
	// name (because of limiting path recursion for deriviation) should fail.
	_, err = client.New(
		client.WithDomainSearchLimit(0), // limit ability to derive from path.
	)
	if err == nil {
		t.Fatal("no error generated for unspecified and underivable name")
	}
}

// TestCreate ensures that instantiation completes without error when provided with a
// valid language.  A single client instance services a single Service Function instance
// and as such requires the desired effective DNS for the function.  This is an optional
// parameter, as it is derived from path by default.
func TestCreate(t *testing.T) {
	client, err := client.New(
		client.WithName("my.example.com"), // be explicity rather than path-derive
		client.WithVerbose(true),          // enable verbose logging
	)
	if err != nil {
		t.Fatal(err)
	}
	// missing language should error
	if err := client.Create(""); err == nil {
		t.Fatal("missing language did not generate error")
	}
	// Any language provided works by default, with the concrete implementation
	// of the initializer being the decider if the language provided is supported.
	if err := client.Create("go"); err != nil {
		t.Fatal(err)
	}
}

// TestCreateDelegeates ensures that a call to Create invokes the Service Function
// Initializer, Builder, Pusher and Deployer with expected parameters.
func TestCreateDelegates(t *testing.T) {
	var (
		path        = "testdata/example.com/admin"
		name        = "admin.example.com"
		image       = "example.registry/user/datestamp-hash"
		route       = "https://admin.example.com/"
		initializer = mock.NewInitializer()
		builder     = mock.NewBuilder()
		pusher      = mock.NewPusher()
		deployer    = mock.NewDeployer()
	)

	client, err := client.New(
		client.WithRoot(path),               // set function root
		client.WithInitializer(initializer), // will receive the final value
		client.WithBuilder(builder),         // builds an image
		client.WithPusher(pusher),           // pushes images to a registry
		client.WithDeployer(deployer),       // deploys images as a running service
	)
	if err != nil {
		t.Fatal(err)
	}

	//  The initializer should receive the name expected from the path,
	// the passed language, and an absolute path to the funciton soruce.
	initializer.InitializeFn = func(name, language, path string) error {
		if name != "admin.example.com" {
			t.Fatalf("initializer expected name 'admin.example.com', got '%v'", name)
		}
		if language != "go" {
			t.Fatalf("initializer expected language 'go', got '%v'", language)
		}
		expectedPath, err := filepath.Abs("./testdata/example.com/admin")
		if err != nil {
			t.Fatal(err)
		}
		if path != expectedPath {
			t.Fatalf("initializer expected path '%v', got '%v'", expectedPath, path)
		}
		return nil
	}

	// The builder should be invoked with a service name and path to its source
	// function code.  For this test, it is a name derived from the test path.
	// An example image name is returned.
	builder.BuildFn = func(name2, path2 string) (image2 string, err error) {
		if name != name {
			t.Fatalf("deployer expected name %v, got '%v'", name, name2)
		}
		expectedPath, err := filepath.Abs(path)
		if err != nil {
			t.Fatal(err)
		}
		if path2 != expectedPath {
			t.Fatalf("deployer expected path '%v', got '%v'", expectedPath, path)
		}
		// image name would be calculated from registry, user, time and git hash
		return image, nil
	}

	// The pusher should be invoked with the image name generated by the builder.
	pusher.PushFn = func(image2 string) error {
		if image2 != image {
			t.Fatalf("pusher expected image '%v', got '%v'", image, image2)
		}
		// image of given name wouold be pushed to the configured registry.
		return nil
	}

	// The deployer should be invoked with the service name and image, and return
	// the final accessible address.
	deployer.DeployFn = func(name2, image2 string) (address string, err error) {
		if name2 != name {
			t.Fatalf("deployer expected name '%v', got '%v'", name, name2)
		}
		if image2 != image {
			t.Fatalf("deployer expected image '%v', got '%v'", image, image2)
		}
		// service of given name would be deployed using the given image and
		// allocated route returned.
		return route, nil
	}

	// Invoke the Creation task using a valid language.
	if err := client.Create("go"); err != nil {
		t.Fatal(err)
	}

	// Confirm that each delegate was invoked.
	if !initializer.InitializeInvoked {
		t.Fatal("initializer was not invoked")
	}
	if !builder.BuildInvoked {
		t.Fatal("builder was not invoked")
	}
	if !pusher.PushInvoked {
		t.Fatal("pusher was not invoked")
	}
	if !deployer.DeployInvoked {
		t.Fatal("deployer was not invoked")
	}
}

// TestCreateLocal ensures that when set to local-only mode, Create only invokes
// the initializer and builder.
func TestCreateLocal(t *testing.T) {
	var (
		path        = "testdata/example.com/admin"
		initializer = mock.NewInitializer()
		builder     = mock.NewBuilder()
		pusher      = mock.NewPusher()
		deployer    = mock.NewDeployer()
		dnsProvider = mock.NewDNSProvider()
	)

	client, err := client.New(
		client.WithRoot(path),               // set function root
		client.WithInitializer(initializer), // will receive the final value
		client.WithBuilder(builder),         // builds an image
		client.WithPusher(pusher),           // pushes images to a registry
		client.WithDeployer(deployer),       // deploys images as a running service
		client.WithDNSProvider(dnsProvider), // will receive the final value
	)
	if err != nil {
		t.Fatal(err)
	}
	// Set the client to local-only mode
	client.SetLocal(true)

	// Create a new Service Function
	if err := client.Create("go"); err != nil {
		t.Fatal(err)
	}
	// Ensure that none of the remote delegates were invoked
	if pusher.PushInvoked {
		t.Fatal("Push invoked in local mode.")
	}
	if deployer.DeployInvoked {
		t.Fatal("Deploy invoked in local mode.")
	}
	if dnsProvider.ProvideInvoked {
		t.Fatal("DNS provider invoked in local mode.")
	}

}

// TestCreateDomain ensures that the effective domain is dervied from
// directory structure.  See the unit tests for pathToDomain for details.
func TestCreateDomain(t *testing.T) {
	// the mock dns provider does nothing but receive the caluclated
	// domain name via it's Provide(domain) method, which is the value
	// being tested here.
	dnsProvider := mock.NewDNSProvider()

	client, err := client.New(
		client.WithRoot("./testdata/example.com"), // set function root
		client.WithDomainSearchLimit(1),           // Limit recursion to one level
		client.WithDNSProvider(dnsProvider),       // will receive the final value
	)
	if err != nil {
		t.Fatal(err)
	}

	if err := client.Create("go"); err != nil {
		t.Fatal(err)
	}
	if !dnsProvider.ProvideInvoked {
		t.Fatal("dns provider was not invoked")
	}
	if dnsProvider.NameRequested != "example.com" {
		t.Fatalf("expected 'example.com', got '%v'", dnsProvider.NameRequested)
	}
}

// TestCreateSubdomain ensures that a subdirectory is interpreted as a subdomain
// when calculating final domain.  See the unit tests for pathToDomain for the
// details and edge cases of this caluclation.
func TestCreateSubdomain(t *testing.T) {
	dnsProvider := mock.NewDNSProvider()
	client, err := client.New(
		client.WithRoot("./testdata/example.com/admin"),
		client.WithDomainSearchLimit(2),
		client.WithDNSProvider(dnsProvider),
	)
	if err != nil {
		t.Fatal(err)
	}
	if err := client.Create("go"); err != nil {
		t.Fatal(err)
	}
	if !dnsProvider.ProvideInvoked {
		t.Fatal("dns provider was not invoked")
	}
	if dnsProvider.NameRequested != "admin.example.com" {
		t.Fatalf("expected 'admin.example.com', got '%v'", dnsProvider.NameRequested)
	}
}

// TestRun ensures that the runner is invoked with the absolute path requested.
func TestRun(t *testing.T) {
	root := "./testdata/example.com/admin"
	runner := mock.NewRunner()
	client, err := client.New(
		client.WithRoot(root),
		client.WithRunner(runner),
	)
	if err != nil {
		t.Fatal(err)
	}
	if err := client.Run(); err != nil {
		t.Fatal(err)
	}
	if !runner.RunInvoked {
		t.Fatal("run did not invoke the runner")
	}
	absRoot, err := filepath.Abs(root)
	if err != nil {
		t.Fatal(err)
	}
	if runner.RootRequested != absRoot {
		t.Fatalf("expected path '%v', got '%v'", absRoot, runner.RootRequested)
	}
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"net"
	"net/url"
	"reflect"
)

var (
	errNil       = fmt.Errorf("the value is nil")
	errStrEmtpy  = fmt.Errorf("the string is empty")
	errStrType   = fmt.Errorf("the value is not string type")
	errIntType   = fmt.Errorf("the value is not an integer type")
	errFloatType = fmt.Errorf("the value is not an float type")
)

func toString(v interface{}) (string, error) {
	if v == nil {
		return "", errNil
	}
	if s, ok := v.(string); ok {
		return s, nil
	}
	return "", errStrType
}

func toInt64(v interface{}) (int64, error) {
	if v == nil {
		return 0, errNil
	}

	switch v.(type) {
	case int, int8, int16, int32, int64:
		return reflect.ValueOf(v).Int(), nil
	case uint, uint8, uint16, uint32, uint64:
		return int64(reflect.ValueOf(v).Uint()), nil
	default:
		return 0, errIntType
	}
}

func toFloat64(v interface{}) (float64, error) {
	if v == nil {
		return 0, errNil
	}

	switch v.(type) {
	case float32, float64:
		return reflect.ValueOf(v).Float(), nil
	default:
		return 0, errFloatType
	}
}

type strLenValidator struct {
	min int
	max int
}

// NewStrLenValidator returns a validator to validate that the length of the
// string must be between min and max.
func NewStrLenValidator(min, max int) Validator {
	return strLenValidator{min: min, max: max}
}

func (sv strLenValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}

	_len := len(s)
	if _len > sv.max || _len < sv.min {
		return fmt.Errorf("the length of %s is %d, not between %d and %d",
			s, _len, sv.min, sv.max)
	}
	return nil
}

type notEmptyStrValidator struct{}

func (e notEmptyStrValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}

	if len(s) == 0 {
		return errStrEmtpy
	}
	return nil
}

// NewStrNotEmptyValidator returns a validator to validate that the value must
// not be an empty string.
func NewStrNotEmptyValidator() Validator {
	return notEmptyStrValidator{}
}

type urlValidator struct{}

func (u urlValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}
	_, err = url.Parse(s)
	return err
}

// NewURLValidator returns a validator to validate whether a url is valid.
func NewURLValidator() Validator {
	return urlValidator{}
}

type ipValidator struct{}

func (i ipValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}
	if net.ParseIP(s) == nil {
		return fmt.Errorf("the value is not a valid ip")
	}
	return nil
}

// NewIPValidator returns a validator to validate whether an ip is valid.
func NewIPValidator() Validator {
	return ipValidator{}
}

type integerRangeValidator struct {
	min int64
	max int64
}

func (r integerRangeValidator) Validate(v interface{}) error {
	i, err := toInt64(v)
	if err != nil {
		return err
	}
	if r.min > i || i > r.max {
		return fmt.Errorf("the value %d is not between %d and %d",
			i, r.min, r.max)
	}
	return nil
}

// NewIntegerRangeValidator returns a validator to validate whether the integer
// value is between the min and the max.
func NewIntegerRangeValidator(min, max int64) Validator {
	return integerRangeValidator{min: min, max: max}
}

type floatRangeValidator struct {
	min float64
	max float64
}

func (r floatRangeValidator) Validate(v interface{}) error {
	f, err := toFloat64(v)
	if err != nil {
		return err
	}
	if r.min > f || f > r.max {
		return fmt.Errorf("the value %f is not between %f and %f",
			f, r.min, r.max)
	}
	return nil
}

// NewFloatRangeValidator returns a validator to validate whether the float
// value is between the min and the max.
func NewFloatRangeValidator(min, max float64) Validator {
	return floatRangeValidator{min: min, max: max}
}

var portValidator = NewIntegerRangeValidator(0, 65535)

// NewPortValidator returns a validator to validate whether a port is between
// 0 and 65535.
func NewPortValidator() Validator {
	return portValidator
}
<commit_msg>Add the email validator.<commit_after>package config

import (
	"fmt"
	"net"
	"net/mail"
	"net/url"
	"reflect"
)

var (
	errNil       = fmt.Errorf("the value is nil")
	errStrEmtpy  = fmt.Errorf("the string is empty")
	errStrType   = fmt.Errorf("the value is not string type")
	errIntType   = fmt.Errorf("the value is not an integer type")
	errFloatType = fmt.Errorf("the value is not an float type")
)

func toString(v interface{}) (string, error) {
	if v == nil {
		return "", errNil
	}
	if s, ok := v.(string); ok {
		return s, nil
	}
	return "", errStrType
}

func toInt64(v interface{}) (int64, error) {
	if v == nil {
		return 0, errNil
	}

	switch v.(type) {
	case int, int8, int16, int32, int64:
		return reflect.ValueOf(v).Int(), nil
	case uint, uint8, uint16, uint32, uint64:
		return int64(reflect.ValueOf(v).Uint()), nil
	default:
		return 0, errIntType
	}
}

func toFloat64(v interface{}) (float64, error) {
	if v == nil {
		return 0, errNil
	}

	switch v.(type) {
	case float32, float64:
		return reflect.ValueOf(v).Float(), nil
	default:
		return 0, errFloatType
	}
}

type strLenValidator struct {
	min int
	max int
}

// NewStrLenValidator returns a validator to validate that the length of the
// string must be between min and max.
func NewStrLenValidator(min, max int) Validator {
	return strLenValidator{min: min, max: max}
}

func (sv strLenValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}

	_len := len(s)
	if _len > sv.max || _len < sv.min {
		return fmt.Errorf("the length of %s is %d, not between %d and %d",
			s, _len, sv.min, sv.max)
	}
	return nil
}

type notEmptyStrValidator struct{}

func (e notEmptyStrValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}

	if len(s) == 0 {
		return errStrEmtpy
	}
	return nil
}

// NewStrNotEmptyValidator returns a validator to validate that the value must
// not be an empty string.
func NewStrNotEmptyValidator() Validator {
	return notEmptyStrValidator{}
}

type urlValidator struct{}

func (u urlValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}
	_, err = url.Parse(s)
	return err
}

// NewURLValidator returns a validator to validate whether a url is valid.
func NewURLValidator() Validator {
	return urlValidator{}
}

type ipValidator struct{}

func (i ipValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}
	if net.ParseIP(s) == nil {
		return fmt.Errorf("the value is not a valid ip")
	}
	return nil
}

// NewIPValidator returns a validator to validate whether an ip is valid.
func NewIPValidator() Validator {
	return ipValidator{}
}

type integerRangeValidator struct {
	min int64
	max int64
}

func (r integerRangeValidator) Validate(v interface{}) error {
	i, err := toInt64(v)
	if err != nil {
		return err
	}
	if r.min > i || i > r.max {
		return fmt.Errorf("the value %d is not between %d and %d",
			i, r.min, r.max)
	}
	return nil
}

// NewIntegerRangeValidator returns a validator to validate whether the integer
// value is between the min and the max.
func NewIntegerRangeValidator(min, max int64) Validator {
	return integerRangeValidator{min: min, max: max}
}

type floatRangeValidator struct {
	min float64
	max float64
}

func (r floatRangeValidator) Validate(v interface{}) error {
	f, err := toFloat64(v)
	if err != nil {
		return err
	}
	if r.min > f || f > r.max {
		return fmt.Errorf("the value %f is not between %f and %f",
			f, r.min, r.max)
	}
	return nil
}

// NewFloatRangeValidator returns a validator to validate whether the float
// value is between the min and the max.
func NewFloatRangeValidator(min, max float64) Validator {
	return floatRangeValidator{min: min, max: max}
}

var portValidator = NewIntegerRangeValidator(0, 65535)

// NewPortValidator returns a validator to validate whether a port is between
// 0 and 65535.
func NewPortValidator() Validator {
	return portValidator
}

type emailValidator struct{}

func (e emailValidator) Validate(v interface{}) error {
	s, err := toString(v)
	if err != nil {
		return err
	}
	_, err = mail.ParseAddress(s)
	return err
}

var emailV = emailValidator{}

// NewEmailValidator returns a validator to validate whether an email is valid.
func NewEmailValidator() Validator {
	return emailV
}
<|endoftext|>


<commit_before>package client

import (
	consul "github.com/hashicorp/consul/api"
	"github.com/hashicorp/nomad/nomad/structs"
	"log"
	"os"
	"testing"
	"time"
)

type mockConsulApiClient struct {
	serviceRegisterCallCount   int
	checkRegisterCallCount     int
	checkDeregisterCallCount   int
	serviceDeregisterCallCount int
}

func (a *mockConsulApiClient) CheckRegister(check *consul.AgentCheckRegistration) error {
	a.checkRegisterCallCount += 1
	return nil
}

func (a *mockConsulApiClient) CheckDeregister(checkID string) error {
	a.checkDeregisterCallCount += 1
	return nil
}

func (a *mockConsulApiClient) ServiceRegister(service *consul.AgentServiceRegistration) error {
	a.serviceRegisterCallCount += 1
	return nil
}

func (a *mockConsulApiClient) ServiceDeregister(serviceId string) error {
	a.serviceDeregisterCallCount += 1
	return nil
}

func (a *mockConsulApiClient) Services() (map[string]*consul.AgentService, error) {
	return make(map[string]*consul.AgentService), nil
}

func (a *mockConsulApiClient) Checks() (map[string]*consul.AgentCheck, error) {
	return make(map[string]*consul.AgentCheck), nil
}

func newConsulService() *ConsulService {
	logger := log.New(os.Stdout, "logger: ", log.Lshortfile)
	c, _ := NewConsulService(logger, "", "", "", false, false, &structs.Node{})
	c.client = &mockConsulApiClient{}
	return c
}

func newTask() *structs.Task {
	var services []*structs.Service
	return &structs.Task{
		Name:     "redis",
		Services: services,
		Resources: &structs.Resources{
			Networks: []*structs.NetworkResource{
				{
					IP:           "10.10.0.1",
					DynamicPorts: []structs.Port{{"db", 20413}},
				},
			},
		},
	}
}

func TestConsul_MakeChecks(t *testing.T) {
	service := &structs.Service{
		Id:   "Foo",
		Name: "Bar",
		Checks: []*structs.ServiceCheck{
			{
				Type:     "http",
				Path:     "/foo/bar",
				Interval: 10 * time.Second,
				Timeout:  2 * time.Second,
			},
			{
				Type:     "http",
				Protocol: "https",
				Path:     "/foo/bar",
				Interval: 10 * time.Second,
				Timeout:  2 * time.Second,
			},
			{
				Type:     "tcp",
				Interval: 10 * time.Second,
				Timeout:  2 * time.Second,
			},
		},
	}

	c := newConsulService()

	check1 := c.makeCheck(service, service.Checks[0], "10.10.0.1", 8090)
	check2 := c.makeCheck(service, service.Checks[1], "10.10.0.1", 8090)
	check3 := c.makeCheck(service, service.Checks[2], "10.10.0.1", 8090)

	if check1.HTTP != "http://10.10.0.1:8090/foo/bar" {
		t.Fatalf("Invalid http url for check: %v", check1.HTTP)
	}

	if check2.HTTP != "https://10.10.0.1:8090/foo/bar" {
		t.Fatalf("Invalid http url for check: %v", check2.HTTP)
	}

	if check3.TCP != "10.10.0.1:8090" {
		t.Fatalf("Invalid tcp check: %v", check3.TCP)
	}
}

func TestConsul_InvalidPortLabelForService(t *testing.T) {
	task := &structs.Task{
		Name:   "foo",
		Driver: "docker",
		Resources: &structs.Resources{
			CPU:      500,
			MemoryMB: 1024,
			DiskMB:   1024,
			IOPS:     10,
			Networks: []*structs.NetworkResource{
				{
					Device: "eth0",
					CIDR:   "255.255.0.0/16",
					MBits:  10,
					ReservedPorts: []structs.Port{
						{
							Label: "http",
							Value: 8080,
						},
						{
							Label: "ssh",
							Value: 2026,
						},
					},
				},
			},
		},
	}
	service := &structs.Service{
		Id:        "service-id",
		Name:      "foo",
		Tags:      []string{"a", "b"},
		PortLabel: "https",
		Checks:    make([]*structs.ServiceCheck, 0),
	}

	c := newConsulService()
	if err := c.registerService(service, task, "allocid"); err == nil {
		t.Fatalf("Service should be invalid")
	}
}

func TestConsul_Services_Deleted_From_Task(t *testing.T) {
	c := newConsulService()
	task := structs.Task{
		Name: "redis",
		Services: []*structs.Service{
			&structs.Service{
				Name:      "example-cache-redis",
				Tags:      []string{"global"},
				PortLabel: "db",
			},
		},
		Resources: &structs.Resources{
			Networks: []*structs.NetworkResource{
				{
					IP:           "10.10.0.1",
					DynamicPorts: []structs.Port{{"db", 20413}},
				},
			},
		},
	}
	c.Register(&task, "1")
	if len(c.serviceStates) != 1 {
		t.Fatalf("Expected tracked services: %v, Actual: %v", 1, len(c.serviceStates))
	}
	task.Services = []*structs.Service{}

	c.performSync()
	if len(c.serviceStates) != 0 {
		t.Fatalf("Expected tracked services: %v, Actual: %v", 0, len(c.serviceStates))
	}
}

func TestConsul_Service_Should_Be_Re_Reregistered_On_Change(t *testing.T) {
	c := newConsulService()
	task := newTask()
	s1 := structs.Service{
		Id:        "1-example-cache-redis",
		Name:      "example-cache-redis",
		Tags:      []string{"global"},
		PortLabel: "db",
	}
	task.Services = append(task.Services, &s1)
	c.Register(task, "1")

	s1.Tags = []string{"frontcache"}

	c.performSync()

	if len(c.serviceStates) != 1 {
		t.Fatal("We should be tracking one service")
	}

	if c.serviceStates[s1.Id] != s1.Hash() {
		t.Fatalf("Hash is %v, expected %v", c.serviceStates[s1.Id], s1.Hash())
	}
}

func TestConsul_AddCheck_To_Service(t *testing.T) {
	apiClient := &mockConsulApiClient{}
	c := newConsulService()
	c.client = apiClient
	task := newTask()
	var checks []*structs.ServiceCheck
	s1 := structs.Service{
		Id:        "1-example-cache-redis",
		Name:      "example-cache-redis",
		Tags:      []string{"global"},
		PortLabel: "db",
		Checks:    checks,
	}
	task.Services = append(task.Services, &s1)
	c.Register(task, "1")

	check1 := structs.ServiceCheck{
		Name:     "alive",
		Type:     "tcp",
		Interval: 10 * time.Second,
		Timeout:  5 * time.Second,
	}

	s1.Checks = append(s1.Checks, &check1)

	c.performSync()
	if apiClient.checkRegisterCallCount != 1 {
		t.Fatalf("Expected number of check registrations: %v, Actual: %v", 1, apiClient.checkRegisterCallCount)
	}
}

func TestConsul_ModifyCheck(t *testing.T) {
	apiClient := &mockConsulApiClient{}
	c := newConsulService()
	c.client = apiClient
	task := newTask()
	var checks []*structs.ServiceCheck
	s1 := structs.Service{
		Id:        "1-example-cache-redis",
		Name:      "example-cache-redis",
		Tags:      []string{"global"},
		PortLabel: "db",
		Checks:    checks,
	}
	task.Services = append(task.Services, &s1)
	c.Register(task, "1")

	check1 := structs.ServiceCheck{
		Name:     "alive",
		Type:     "tcp",
		Interval: 10 * time.Second,
		Timeout:  5 * time.Second,
	}

	s1.Checks = append(s1.Checks, &check1)

	c.performSync()
	if apiClient.checkRegisterCallCount != 1 {
		t.Fatalf("Expected number of check registrations: %v, Actual: %v", 1, apiClient.checkRegisterCallCount)
	}

	check1.Timeout = 2 * time.Second
	c.performSync()
	if apiClient.checkRegisterCallCount != 2 {
		t.Fatalf("Expected number of check registrations: %v, Actual: %v", 2, apiClient.checkRegisterCallCount)
	}
}

func TestConsul_FilterNomadServicesAndChecks(t *testing.T) {
}
<commit_msg>Added a test for the filtering logic of service and clients<commit_after>package client

import (
	consul "github.com/hashicorp/consul/api"
	"github.com/hashicorp/nomad/nomad/structs"
	"log"
	"os"
	"testing"
	"time"
)

type mockConsulApiClient struct {
	serviceRegisterCallCount   int
	checkRegisterCallCount     int
	checkDeregisterCallCount   int
	serviceDeregisterCallCount int
}

func (a *mockConsulApiClient) CheckRegister(check *consul.AgentCheckRegistration) error {
	a.checkRegisterCallCount += 1
	return nil
}

func (a *mockConsulApiClient) CheckDeregister(checkID string) error {
	a.checkDeregisterCallCount += 1
	return nil
}

func (a *mockConsulApiClient) ServiceRegister(service *consul.AgentServiceRegistration) error {
	a.serviceRegisterCallCount += 1
	return nil
}

func (a *mockConsulApiClient) ServiceDeregister(serviceId string) error {
	a.serviceDeregisterCallCount += 1
	return nil
}

func (a *mockConsulApiClient) Services() (map[string]*consul.AgentService, error) {
	return make(map[string]*consul.AgentService), nil
}

func (a *mockConsulApiClient) Checks() (map[string]*consul.AgentCheck, error) {
	return make(map[string]*consul.AgentCheck), nil
}

func newConsulService() *ConsulService {
	logger := log.New(os.Stdout, "logger: ", log.Lshortfile)
	c, _ := NewConsulService(logger, "", "", "", false, false, &structs.Node{})
	c.client = &mockConsulApiClient{}
	return c
}

func newTask() *structs.Task {
	var services []*structs.Service
	return &structs.Task{
		Name:     "redis",
		Services: services,
		Resources: &structs.Resources{
			Networks: []*structs.NetworkResource{
				{
					IP:           "10.10.0.1",
					DynamicPorts: []structs.Port{{"db", 20413}},
				},
			},
		},
	}
}

func TestConsul_MakeChecks(t *testing.T) {
	service := &structs.Service{
		Id:   "Foo",
		Name: "Bar",
		Checks: []*structs.ServiceCheck{
			{
				Type:     "http",
				Path:     "/foo/bar",
				Interval: 10 * time.Second,
				Timeout:  2 * time.Second,
			},
			{
				Type:     "http",
				Protocol: "https",
				Path:     "/foo/bar",
				Interval: 10 * time.Second,
				Timeout:  2 * time.Second,
			},
			{
				Type:     "tcp",
				Interval: 10 * time.Second,
				Timeout:  2 * time.Second,
			},
		},
	}

	c := newConsulService()

	check1 := c.makeCheck(service, service.Checks[0], "10.10.0.1", 8090)
	check2 := c.makeCheck(service, service.Checks[1], "10.10.0.1", 8090)
	check3 := c.makeCheck(service, service.Checks[2], "10.10.0.1", 8090)

	if check1.HTTP != "http://10.10.0.1:8090/foo/bar" {
		t.Fatalf("Invalid http url for check: %v", check1.HTTP)
	}

	if check2.HTTP != "https://10.10.0.1:8090/foo/bar" {
		t.Fatalf("Invalid http url for check: %v", check2.HTTP)
	}

	if check3.TCP != "10.10.0.1:8090" {
		t.Fatalf("Invalid tcp check: %v", check3.TCP)
	}
}

func TestConsul_InvalidPortLabelForService(t *testing.T) {
	task := &structs.Task{
		Name:   "foo",
		Driver: "docker",
		Resources: &structs.Resources{
			CPU:      500,
			MemoryMB: 1024,
			DiskMB:   1024,
			IOPS:     10,
			Networks: []*structs.NetworkResource{
				{
					Device: "eth0",
					CIDR:   "255.255.0.0/16",
					MBits:  10,
					ReservedPorts: []structs.Port{
						{
							Label: "http",
							Value: 8080,
						},
						{
							Label: "ssh",
							Value: 2026,
						},
					},
				},
			},
		},
	}
	service := &structs.Service{
		Id:        "service-id",
		Name:      "foo",
		Tags:      []string{"a", "b"},
		PortLabel: "https",
		Checks:    make([]*structs.ServiceCheck, 0),
	}

	c := newConsulService()
	if err := c.registerService(service, task, "allocid"); err == nil {
		t.Fatalf("Service should be invalid")
	}
}

func TestConsul_Services_Deleted_From_Task(t *testing.T) {
	c := newConsulService()
	task := structs.Task{
		Name: "redis",
		Services: []*structs.Service{
			&structs.Service{
				Name:      "example-cache-redis",
				Tags:      []string{"global"},
				PortLabel: "db",
			},
		},
		Resources: &structs.Resources{
			Networks: []*structs.NetworkResource{
				{
					IP:           "10.10.0.1",
					DynamicPorts: []structs.Port{{"db", 20413}},
				},
			},
		},
	}
	c.Register(&task, "1")
	if len(c.serviceStates) != 1 {
		t.Fatalf("Expected tracked services: %v, Actual: %v", 1, len(c.serviceStates))
	}
	task.Services = []*structs.Service{}

	c.performSync()
	if len(c.serviceStates) != 0 {
		t.Fatalf("Expected tracked services: %v, Actual: %v", 0, len(c.serviceStates))
	}
}

func TestConsul_Service_Should_Be_Re_Reregistered_On_Change(t *testing.T) {
	c := newConsulService()
	task := newTask()
	s1 := structs.Service{
		Id:        "1-example-cache-redis",
		Name:      "example-cache-redis",
		Tags:      []string{"global"},
		PortLabel: "db",
	}
	task.Services = append(task.Services, &s1)
	c.Register(task, "1")

	s1.Tags = []string{"frontcache"}

	c.performSync()

	if len(c.serviceStates) != 1 {
		t.Fatal("We should be tracking one service")
	}

	if c.serviceStates[s1.Id] != s1.Hash() {
		t.Fatalf("Hash is %v, expected %v", c.serviceStates[s1.Id], s1.Hash())
	}
}

func TestConsul_AddCheck_To_Service(t *testing.T) {
	apiClient := &mockConsulApiClient{}
	c := newConsulService()
	c.client = apiClient
	task := newTask()
	var checks []*structs.ServiceCheck
	s1 := structs.Service{
		Id:        "1-example-cache-redis",
		Name:      "example-cache-redis",
		Tags:      []string{"global"},
		PortLabel: "db",
		Checks:    checks,
	}
	task.Services = append(task.Services, &s1)
	c.Register(task, "1")

	check1 := structs.ServiceCheck{
		Name:     "alive",
		Type:     "tcp",
		Interval: 10 * time.Second,
		Timeout:  5 * time.Second,
	}

	s1.Checks = append(s1.Checks, &check1)

	c.performSync()
	if apiClient.checkRegisterCallCount != 1 {
		t.Fatalf("Expected number of check registrations: %v, Actual: %v", 1, apiClient.checkRegisterCallCount)
	}
}

func TestConsul_ModifyCheck(t *testing.T) {
	apiClient := &mockConsulApiClient{}
	c := newConsulService()
	c.client = apiClient
	task := newTask()
	var checks []*structs.ServiceCheck
	s1 := structs.Service{
		Id:        "1-example-cache-redis",
		Name:      "example-cache-redis",
		Tags:      []string{"global"},
		PortLabel: "db",
		Checks:    checks,
	}
	task.Services = append(task.Services, &s1)
	c.Register(task, "1")

	check1 := structs.ServiceCheck{
		Name:     "alive",
		Type:     "tcp",
		Interval: 10 * time.Second,
		Timeout:  5 * time.Second,
	}

	s1.Checks = append(s1.Checks, &check1)

	c.performSync()
	if apiClient.checkRegisterCallCount != 1 {
		t.Fatalf("Expected number of check registrations: %v, Actual: %v", 1, apiClient.checkRegisterCallCount)
	}

	check1.Timeout = 2 * time.Second
	c.performSync()
	if apiClient.checkRegisterCallCount != 2 {
		t.Fatalf("Expected number of check registrations: %v, Actual: %v", 2, apiClient.checkRegisterCallCount)
	}
}

func TestConsul_FilterNomadServicesAndChecks(t *testing.T) {
	c := newConsulService()
	srvs := map[string]*consul.AgentService{
		"foo-bar": {
			ID:      "foo-bar",
			Service: "http-frontend",
			Tags:    []string{"global"},
			Port:    8080,
			Address: "10.10.1.11",
		},
		"nomad-2121212": {
			ID:      "nomad-2121212",
			Service: "identity-service",
			Tags:    []string{"global"},
			Port:    8080,
			Address: "10.10.1.11",
		},
	}

	nomadServices := c.filterConsulServices(srvs)

	if len(nomadServices) != 1 {
		t.Fatalf("Expected number of services: %v, Actual: %v", 1, len(nomadServices))
	}

	nomadServices = c.filterConsulServices(nil)
	if len(nomadServices) != 0 {
		t.Fatalf("Expected number of services: %v, Actual: %v", 0, len(nomadServices))
	}

	chks := map[string]*consul.AgentCheck{
		"foo-bar-chk": {
			CheckID:   "foo-bar-chk",
			ServiceID: "foo-bar",
			Name:      "alive",
		},
		"212121212": {
			CheckID:   "212121212",
			ServiceID: "nomad-2121212",
			Name:      "ping",
		},
	}

	nomadChecks := c.filterConsulChecks(chks)

	if len(nomadChecks) != 1 {
		t.Fatalf("Expected number of checks: %v, Actual: %v", 1, len(nomadChecks))
	}

	nomadChecks = c.filterConsulChecks(nil)
	if len(nomadChecks) != 0 {
		t.Fatalf("Expected number of checks: %v, Actual: %v", 0, len(nomadChecks))
	}

}
<|endoftext|>