<commit_before>package mackerel

import (
	"encoding/json"
	"fmt"
	"net/http"
)

/*
`/dashboards` Response
Legacy
{
  "dashboards": [
    {
       "id": "2c5bLca8d",
       "title": "My Dashboard",
       "bodyMarkdown": "# A test dashboard",
       "urlPath": "2u4PP3TJqbu",
       "createdAt": 1439346145003,
       "updatedAt": 1439346145003,
       "isLegacy": true
    }
  ]
}

Current
{
  "dashboards": [
    {
      "id":        "2c5bLca8e",
      "title":     "My Custom Dashboard(Current)",
      "urlPath":   "2u4PP3TJqbv",
      "createdAt": 1552909732,
      "updatedAt": 1552992837,
      "memo":      "A test Current Dashboard"
    }
  ]
}
*/

/*
`/dashboards/${ID}` Response`
Legacy
{
  "id": "2c5bLca8d",
  "title": "My Dashboard",
  "bodyMarkdown": "# A test dashboard",
  "urlPath": "2u4PP3TJqbu",
  "createdAt": 1439346145003,
  "updatedAt": 1439346145003,
  "isLegacy": true
}
Current
{
  "id": "2c5bLca8e",
  "createdAt": 1552909732,
  "updatedAt": 1552992837,
  "title": "My Custom Dashboard(Current),
  "urlPath": "2u4PP3TJqbv",
  "memo": "A test Current Dashboard",
  "widgets": [
    {
      "type": "markdown",
      "title": "markdown",
      "markdown": "# body",
      "layout": {
        "x": 0,
        "y": 0,
        "width": 24,
        "height": 3
      }
    },
    {
      "type": "graph",
      "title": "graph",
      "graph": {
        "type": "host",
        "hostId": "2u4PP3TJqbw",
        "name": "loadavg.loadavg15"
      },
      "layout": {
        "x": 0,
        "y": 7,
        "width": 8,
        "height": 10
      }
    },
    {
      "type": "value",
      "title": "value",
      "metric": {
        "type": "expression",
        "expression": "alias(scale(\nsum(\n  group(\n    host(2u4PP3TJqbx,loadavg.*)\n  )\n),\n1\n), 'test')"
      },
      "layout": {
        "x": 0,
        "y": 17,
        "width": 8,
        "height": 5
      }
    }
  ]
}
*/

// Dashboard information
type Dashboard struct {
	// Common to legacy dashboard and current dashboard
	ID        string `json:"id,omitempty"`
	Title     string `json:"title,omitempty"`
	URLPath   string `json:"urlPath,omitempty"`
	CreatedAt int64  `json:"createdAt,omitempty"`
	UpdatedAt int64  `json:"updatedAt,omitempty"`

	// current dashboard
	Memo    string   `json:"memo,omitempty"`
	Widgets []Widget `json:"widgets,omitenpty"`

	// legacy dashboard
	IsLegacy     bool   `json:"isLegacy,omitempty"`
	BodyMarkDown string `json:"bodyMarkdown,omitempty"`
}

// Widget information
type Widget struct {
	Type     string `json:"type,omitempty"`
	Title    string `json:"title,omitempty"`
	Layout   Layout `json:"layout,omitempty"`
	Metric   Metric `json:"metric,omitempty"`
	Graph    Graph  `json:"graph,omitempty"`
	Range    Range  `json:"range,omitempty"`
	Markdown string `json:"markdown,omitempty"`
}

// Metric information
type Metric struct {
	Type        string `json:"type,omitempty"`
	Name        string `json:"name,omitempty"`
	HostID      string `json:"hostId,omitempty"`
	ServiceName string `json:"serviceName,omitempty"`
	Expression  string `json:"expression,omitempty"`
}

// Graph information
type Graph struct {
	Type         string `json:"type,omitempty"`
	Name         string `json:"name,omitempty"`
	HostID       string `json:"hostId,omitempty"`
	RoleFullName string `json:"roleFullname,omitempty"`
	IsStacked    bool   `json:"isStacked,omitempty"`
	ServiceName  string `json:"serviceName,omitempty"`
	Expression   string `json:"expression,omitempty"`
}

// Range information
type Range struct {
	Type   string `json:"type,omitempty"`
	Period int64  `json:"period,omitempty"`
	Offset int64  `json:"offset,omitempty"`
	Start  int64  `json:"start,omitempty"`
	End    int64  `json:"end,omitempty"`
}

// Layout information
type Layout struct {
	X      int64 `json:"x,omitempty"`
	Y      int64 `json:"y,omitempty"`
	Width  int64 `json:"width,omitempty"`
	Height int64 `json:"height,omitempty"`
}

// FindDashboards find dashboards
func (c *Client) FindDashboards() ([]*Dashboard, error) {
	req, err := http.NewRequest("GET", c.urlFor("/api/v0/dashboards").String(), nil)
	if err != nil {
		return nil, err
	}
	resp, err := c.Request(req)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data struct {
		Dashboards []*Dashboard `json:"dashboards"`
	}
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}

	return data.Dashboards, err
}

// FindDashboard find dashboard
func (c *Client) FindDashboard(dashboardID string) (*Dashboard, error) {
	req, err := http.NewRequest("GET", c.urlFor(fmt.Sprintf("/api/v0/dashboards/%s", dashboardID)).String(), nil)
	if err != nil {
		return nil, err
	}
	resp, err := c.Request(req)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data Dashboard
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return &data, err
}

// CreateDashboard creating dashboard
func (c *Client) CreateDashboard(param *Dashboard) (*Dashboard, error) {
	resp, err := c.PostJSON("/api/v0/dashboards", param)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data Dashboard
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return &data, nil
}

// UpdateDashboard update dashboard
func (c *Client) UpdateDashboard(dashboardID string, param *Dashboard) (*Dashboard, error) {
	resp, err := c.PutJSON(fmt.Sprintf("/api/v0/dashboards/%s", dashboardID), param)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data Dashboard
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return &data, nil
}

// DeleteDashboard delete dashboard
func (c *Client) DeleteDashboard(dashboardID string) (*Dashboard, error) {
	req, err := http.NewRequest(
		"DELETE",
		c.urlFor(fmt.Sprintf("/api/v0/dashboards/%s", dashboardID)).String(),
		nil,
	)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/json")

	resp, err := c.Request(req)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data Dashboard
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return &data, nil
}
<commit_msg>Fix typo<commit_after>package mackerel

import (
	"encoding/json"
	"fmt"
	"net/http"
)

/*
`/dashboards` Response
Legacy
{
  "dashboards": [
    {
       "id": "2c5bLca8d",
       "title": "My Dashboard",
       "bodyMarkdown": "# A test dashboard",
       "urlPath": "2u4PP3TJqbu",
       "createdAt": 1439346145003,
       "updatedAt": 1439346145003,
       "isLegacy": true
    }
  ]
}

Current
{
  "dashboards": [
    {
      "id":        "2c5bLca8e",
      "title":     "My Custom Dashboard(Current)",
      "urlPath":   "2u4PP3TJqbv",
      "createdAt": 1552909732,
      "updatedAt": 1552992837,
      "memo":      "A test Current Dashboard"
    }
  ]
}
*/

/*
`/dashboards/${ID}` Response`
Legacy
{
  "id": "2c5bLca8d",
  "title": "My Dashboard",
  "bodyMarkdown": "# A test dashboard",
  "urlPath": "2u4PP3TJqbu",
  "createdAt": 1439346145003,
  "updatedAt": 1439346145003,
  "isLegacy": true
}
Current
{
  "id": "2c5bLca8e",
  "createdAt": 1552909732,
  "updatedAt": 1552992837,
  "title": "My Custom Dashboard(Current),
  "urlPath": "2u4PP3TJqbv",
  "memo": "A test Current Dashboard",
  "widgets": [
    {
      "type": "markdown",
      "title": "markdown",
      "markdown": "# body",
      "layout": {
        "x": 0,
        "y": 0,
        "width": 24,
        "height": 3
      }
    },
    {
      "type": "graph",
      "title": "graph",
      "graph": {
        "type": "host",
        "hostId": "2u4PP3TJqbw",
        "name": "loadavg.loadavg15"
      },
      "layout": {
        "x": 0,
        "y": 7,
        "width": 8,
        "height": 10
      }
    },
    {
      "type": "value",
      "title": "value",
      "metric": {
        "type": "expression",
        "expression": "alias(scale(\nsum(\n  group(\n    host(2u4PP3TJqbx,loadavg.*)\n  )\n),\n1\n), 'test')"
      },
      "layout": {
        "x": 0,
        "y": 17,
        "width": 8,
        "height": 5
      }
    }
  ]
}
*/

// Dashboard information
type Dashboard struct {
	// Common to legacy dashboard and current dashboard
	ID        string `json:"id,omitempty"`
	Title     string `json:"title,omitempty"`
	URLPath   string `json:"urlPath,omitempty"`
	CreatedAt int64  `json:"createdAt,omitempty"`
	UpdatedAt int64  `json:"updatedAt,omitempty"`

	// current dashboard
	Memo    string   `json:"memo,omitempty"`
	Widgets []Widget `json:"widgets,omitempty"`

	// legacy dashboard
	IsLegacy     bool   `json:"isLegacy,omitempty"`
	BodyMarkDown string `json:"bodyMarkdown,omitempty"`
}

// Widget information
type Widget struct {
	Type     string `json:"type,omitempty"`
	Title    string `json:"title,omitempty"`
	Layout   Layout `json:"layout,omitempty"`
	Metric   Metric `json:"metric,omitempty"`
	Graph    Graph  `json:"graph,omitempty"`
	Range    Range  `json:"range,omitempty"`
	Markdown string `json:"markdown,omitempty"`
}

// Metric information
type Metric struct {
	Type        string `json:"type,omitempty"`
	Name        string `json:"name,omitempty"`
	HostID      string `json:"hostId,omitempty"`
	ServiceName string `json:"serviceName,omitempty"`
	Expression  string `json:"expression,omitempty"`
}

// Graph information
type Graph struct {
	Type         string `json:"type,omitempty"`
	Name         string `json:"name,omitempty"`
	HostID       string `json:"hostId,omitempty"`
	RoleFullName string `json:"roleFullname,omitempty"`
	IsStacked    bool   `json:"isStacked,omitempty"`
	ServiceName  string `json:"serviceName,omitempty"`
	Expression   string `json:"expression,omitempty"`
}

// Range information
type Range struct {
	Type   string `json:"type,omitempty"`
	Period int64  `json:"period,omitempty"`
	Offset int64  `json:"offset,omitempty"`
	Start  int64  `json:"start,omitempty"`
	End    int64  `json:"end,omitempty"`
}

// Layout information
type Layout struct {
	X      int64 `json:"x,omitempty"`
	Y      int64 `json:"y,omitempty"`
	Width  int64 `json:"width,omitempty"`
	Height int64 `json:"height,omitempty"`
}

// FindDashboards find dashboards
func (c *Client) FindDashboards() ([]*Dashboard, error) {
	req, err := http.NewRequest("GET", c.urlFor("/api/v0/dashboards").String(), nil)
	if err != nil {
		return nil, err
	}
	resp, err := c.Request(req)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data struct {
		Dashboards []*Dashboard `json:"dashboards"`
	}
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}

	return data.Dashboards, err
}

// FindDashboard find dashboard
func (c *Client) FindDashboard(dashboardID string) (*Dashboard, error) {
	req, err := http.NewRequest("GET", c.urlFor(fmt.Sprintf("/api/v0/dashboards/%s", dashboardID)).String(), nil)
	if err != nil {
		return nil, err
	}
	resp, err := c.Request(req)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data Dashboard
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return &data, err
}

// CreateDashboard creating dashboard
func (c *Client) CreateDashboard(param *Dashboard) (*Dashboard, error) {
	resp, err := c.PostJSON("/api/v0/dashboards", param)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data Dashboard
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return &data, nil
}

// UpdateDashboard update dashboard
func (c *Client) UpdateDashboard(dashboardID string, param *Dashboard) (*Dashboard, error) {
	resp, err := c.PutJSON(fmt.Sprintf("/api/v0/dashboards/%s", dashboardID), param)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data Dashboard
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return &data, nil
}

// DeleteDashboard delete dashboard
func (c *Client) DeleteDashboard(dashboardID string) (*Dashboard, error) {
	req, err := http.NewRequest(
		"DELETE",
		c.urlFor(fmt.Sprintf("/api/v0/dashboards/%s", dashboardID)).String(),
		nil,
	)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/json")

	resp, err := c.Request(req)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data Dashboard
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return &data, nil
}
<|endoftext|>


<commit_before>package auth

import (
	"net/http"

	"github.com/mdlayher/wavepipe/data"
	"github.com/mdlayher/wavepipe/subsonic"
)

// SubsonicAuth represents the Subsonic authentication method, which is used ONLY for the Subsonic
// emulation layer
type SubsonicAuth struct{}

// Authenticate uses the Subsonic authentication method to log in to the API, returning
// only a pair of client/server errors
func (a SubsonicAuth) Authenticate(req *http.Request) (*data.User, *data.Session, error, error) {
	// Check for required credentials via querystring
	query := req.URL.Query()
	username := query.Get("u")
	password := query.Get("p")

	// Check if username or password is blank
	if username == "" || password == "" {
		return nil, nil, subsonic.ErrBadCredentials, nil
	}

	// Check for Subsonic version
	version := query.Get("v")
	if version == "" {
		return nil, nil, subsonic.ErrMissingParameter, nil
	}

	// TODO: add authentication logic here

	// No errors, return no user or session
	return nil, nil, nil, nil
}
<commit_msg>Add initial Subsonic authentication, done using wavepipe username and wavepipe session key as password<commit_after>package auth

import (
	"database/sql"
	"net/http"
	"time"

	"github.com/mdlayher/wavepipe/data"
	"github.com/mdlayher/wavepipe/subsonic"
)

// SubsonicAuth represents the Subsonic authentication method, which is used ONLY for the Subsonic
// emulation layer
type SubsonicAuth struct{}

// Authenticate uses the Subsonic authentication method to log in to the API, returning
// only a pair of client/server errors
func (a SubsonicAuth) Authenticate(req *http.Request) (*data.User, *data.Session, error, error) {
	// Check for required credentials via querystring
	query := req.URL.Query()
	username := query.Get("u")
	password := query.Get("p")

	// Check if username or password is blank
	if username == "" || password == "" {
		return nil, nil, subsonic.ErrBadCredentials, nil
	}

	// Check for Subsonic version
	version := query.Get("v")
	if version == "" {
		return nil, nil, subsonic.ErrMissingParameter, nil
	}

	// TODO: reevaluate this strategy in the future, but for now, we will use a user's wavepipe session
	// TODO: key as their Subsonic password.  This will mean that the username and session key are passed on
	// TODO: every request, but also means that no more database schema must be added for Subsonic authentication.

	// Attempt to load session by key passed via Subsonic password parameter
	session := new(data.Session)
	session.Key = password
	if err := session.Load(); err != nil {
		// Check for invalid user
		if err == sql.ErrNoRows {
			return nil, nil, subsonic.ErrBadCredentials, nil
		}

		// Server error
		return nil, nil, nil, err
	}

	// Attempt to load associated user by username from Subsonic username parameter
	user := new(data.User)
	user.Username = username
	if err := user.Load(); err != nil {
		// Server error
		return nil, nil, nil, err
	}

	// Update session expiration date by 1 week
	session.Expire = time.Now().Add(7 * 24 * time.Hour).Unix()
	if err := session.Update(); err != nil {
		return nil, nil, nil, err
	}

	// No errors, return no user or session because the emulated Subsonic API is read-only
	return nil, nil, nil, nil
}
<|endoftext|>


<commit_before>package mount

import (
	"os"
)

// Type represents the type of a mount.
type Type string

// Type constants
const (
	// TypeBind is the type for mounting host dir
	TypeBind Type = "bind"
	// TypeVolume is the type for remote storage volumes
	TypeVolume Type = "volume"
	// TypeTmpfs is the type for mounting tmpfs
	TypeTmpfs Type = "tmpfs"
)

// Mount represents a mount (volume).
type Mount struct {
	Type Type `json:",omitempty"`
	// Source specifies the name of the mount. Depending on mount type, this
	// may be a volume name or a host path, or even ignored.
	// Source is not supported for tmpfs (must be an empty value)
	Source   string `json:",omitempty"`
	Target   string `json:",omitempty"`
	ReadOnly bool   `json:",omitempty"`

	BindOptions   *BindOptions   `json:",omitempty"`
	VolumeOptions *VolumeOptions `json:",omitempty"`
	TmpfsOptions  *TmpfsOptions  `json:",omitempty"`
}

// Propagation represents the propagation of a mount.
type Propagation string

const (
	// PropagationRPrivate RPRIVATE
	PropagationRPrivate Propagation = "rprivate"
	// PropagationPrivate PRIVATE
	PropagationPrivate Propagation = "private"
	// PropagationRShared RSHARED
	PropagationRShared Propagation = "rshared"
	// PropagationShared SHARED
	PropagationShared Propagation = "shared"
	// PropagationRSlave RSLAVE
	PropagationRSlave Propagation = "rslave"
	// PropagationSlave SLAVE
	PropagationSlave Propagation = "slave"
)

// Propagations is the list of all valid mount propagations
var Propagations = []Propagation{
	PropagationRPrivate,
	PropagationPrivate,
	PropagationRShared,
	PropagationShared,
	PropagationRSlave,
	PropagationSlave,
}

// BindOptions defines options specific to mounts of type "bind".
type BindOptions struct {
	Propagation Propagation `json:",omitempty"`
}

// VolumeOptions represents the options for a mount of type volume.
type VolumeOptions struct {
	NoCopy       bool              `json:",omitempty"`
	Labels       map[string]string `json:",omitempty"`
	DriverConfig *Driver           `json:",omitempty"`
}

// Driver represents a volume driver.
type Driver struct {
	Name    string            `json:",omitempty"`
	Options map[string]string `json:",omitempty"`
}

// TmpfsOptions defines options specific to mounts of type "tmpfs".
type TmpfsOptions struct {
	// Size sets the size of the tmpfs, in bytes.
	//
	// This will be converted to an operating system specific value
	// depending on the host. For example, on linux, it will be convered to
	// use a 'k', 'm' or 'g' syntax. BSD, though not widely supported with
	// docker, uses a straight byte value.
	//
	// Percentages are not supported.
	SizeBytes int64 `json:",omitempty"`
	// Mode of the tmpfs upon creation
	Mode os.FileMode `json:",omitempty"`

	// TODO(stevvooe): There are several more tmpfs flags, specified in the
	// daemon, that are accepted. Only the most basic are added for now.
	//
	// From docker/docker/pkg/mount/flags.go:
	//
	// var validFlags = map[string]bool{
	// 	"":          true,
	// 	"size":      true, X
	// 	"mode":      true, X
	// 	"uid":       true,
	// 	"gid":       true,
	// 	"nr_inodes": true,
	// 	"nr_blocks": true,
	// 	"mpol":      true,
	// }
	//
	// Some of these may be straightforward to add, but others, such as
	// uid/gid have implications in a clustered system.
}
<commit_msg>fix typo in mount.go<commit_after>package mount

import (
	"os"
)

// Type represents the type of a mount.
type Type string

// Type constants
const (
	// TypeBind is the type for mounting host dir
	TypeBind Type = "bind"
	// TypeVolume is the type for remote storage volumes
	TypeVolume Type = "volume"
	// TypeTmpfs is the type for mounting tmpfs
	TypeTmpfs Type = "tmpfs"
)

// Mount represents a mount (volume).
type Mount struct {
	Type Type `json:",omitempty"`
	// Source specifies the name of the mount. Depending on mount type, this
	// may be a volume name or a host path, or even ignored.
	// Source is not supported for tmpfs (must be an empty value)
	Source   string `json:",omitempty"`
	Target   string `json:",omitempty"`
	ReadOnly bool   `json:",omitempty"`

	BindOptions   *BindOptions   `json:",omitempty"`
	VolumeOptions *VolumeOptions `json:",omitempty"`
	TmpfsOptions  *TmpfsOptions  `json:",omitempty"`
}

// Propagation represents the propagation of a mount.
type Propagation string

const (
	// PropagationRPrivate RPRIVATE
	PropagationRPrivate Propagation = "rprivate"
	// PropagationPrivate PRIVATE
	PropagationPrivate Propagation = "private"
	// PropagationRShared RSHARED
	PropagationRShared Propagation = "rshared"
	// PropagationShared SHARED
	PropagationShared Propagation = "shared"
	// PropagationRSlave RSLAVE
	PropagationRSlave Propagation = "rslave"
	// PropagationSlave SLAVE
	PropagationSlave Propagation = "slave"
)

// Propagations is the list of all valid mount propagations
var Propagations = []Propagation{
	PropagationRPrivate,
	PropagationPrivate,
	PropagationRShared,
	PropagationShared,
	PropagationRSlave,
	PropagationSlave,
}

// BindOptions defines options specific to mounts of type "bind".
type BindOptions struct {
	Propagation Propagation `json:",omitempty"`
}

// VolumeOptions represents the options for a mount of type volume.
type VolumeOptions struct {
	NoCopy       bool              `json:",omitempty"`
	Labels       map[string]string `json:",omitempty"`
	DriverConfig *Driver           `json:",omitempty"`
}

// Driver represents a volume driver.
type Driver struct {
	Name    string            `json:",omitempty"`
	Options map[string]string `json:",omitempty"`
}

// TmpfsOptions defines options specific to mounts of type "tmpfs".
type TmpfsOptions struct {
	// Size sets the size of the tmpfs, in bytes.
	//
	// This will be converted to an operating system specific value
	// depending on the host. For example, on linux, it will be converted to
	// use a 'k', 'm' or 'g' syntax. BSD, though not widely supported with
	// docker, uses a straight byte value.
	//
	// Percentages are not supported.
	SizeBytes int64 `json:",omitempty"`
	// Mode of the tmpfs upon creation
	Mode os.FileMode `json:",omitempty"`

	// TODO(stevvooe): There are several more tmpfs flags, specified in the
	// daemon, that are accepted. Only the most basic are added for now.
	//
	// From docker/docker/pkg/mount/flags.go:
	//
	// var validFlags = map[string]bool{
	// 	"":          true,
	// 	"size":      true, X
	// 	"mode":      true, X
	// 	"uid":       true,
	// 	"gid":       true,
	// 	"nr_inodes": true,
	// 	"nr_blocks": true,
	// 	"mpol":      true,
	// }
	//
	// Some of these may be straightforward to add, but others, such as
	// uid/gid have implications in a clustered system.
}
<|endoftext|>


<commit_before>package client

import (
	"errors"
	"io"
	"net/url"
	"os"

	flag "github.com/docker/docker/pkg/mflag"
)

// CmdExport exports a filesystem as a tar archive.
//
// The tar archive is streamed to STDOUT by default or written to a file.
//
// Usage: docker export [OPTIONS] CONTAINER
func (cli *DockerCli) CmdExport(args ...string) error {
	cmd := cli.Subcmd("export", "CONTAINER", "Export a filesystem as a tar archive (streamed to STDOUT by default)", true)
	outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT")
	cmd.Require(flag.Exact, 1)

	cmd.ParseFlags(args, true)

	var (
		output io.Writer = cli.out
		err    error
	)
	if *outfile != "" {
		output, err = os.Create(*outfile)
		if err != nil {
			return err
		}
	} else if cli.isTerminalOut {
		return errors.New("Cowardly refusing to save to a terminal. Use the -o flag or redirect.")
	}

	if len(cmd.Args()) == 1 {
		image := cmd.Arg(0)
		if err := cli.stream("GET", "/containers/"+image+"/export", nil, output, nil); err != nil {
			return err
		}
	} else {
		v := url.Values{}
		for _, arg := range cmd.Args() {
			v.Add("names", arg)
		}
		if err := cli.stream("GET", "/containers/get?"+v.Encode(), nil, output, nil); err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>remove useless http call from export Signed-off-by: He Simei <hesimei@zju.edu.cn><commit_after>package client

import (
	"errors"
	"io"
	"os"

	flag "github.com/docker/docker/pkg/mflag"
)

// CmdExport exports a filesystem as a tar archive.
//
// The tar archive is streamed to STDOUT by default or written to a file.
//
// Usage: docker export [OPTIONS] CONTAINER
func (cli *DockerCli) CmdExport(args ...string) error {
	cmd := cli.Subcmd("export", "CONTAINER", "Export a filesystem as a tar archive (streamed to STDOUT by default)", true)
	outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT")
	cmd.Require(flag.Exact, 1)

	cmd.ParseFlags(args, true)

	var (
		output io.Writer = cli.out
		err    error
	)
	if *outfile != "" {
		output, err = os.Create(*outfile)
		if err != nil {
			return err
		}
	} else if cli.isTerminalOut {
		return errors.New("Cowardly refusing to save to a terminal. Use the -o flag or redirect.")
	}

	image := cmd.Arg(0)
	if err := cli.stream("GET", "/containers/"+image+"/export", nil, output, nil); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


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

package lsm

import (
	"github.com/golangsam/do/ats" // anything to string
)

// UserFriendly - interface exposed for go doc only
//
// I love to be easy - thus: I give You a simple API!
//  Create me with New, if You like - Note: No need, I'm friendly :-)
//  and Init me to use me afresh,
//  Assign any name (as key) to any value,
//  and Fetch a value by it's name,
//  Lookup a value as string by it's name (as key),
//  Delete a key, if You don't need it any more
//  as You please :-)
//
type UserFriendly interface {
	// Following may be chained:
	Init() *LazyStringerMap                              // (re)start afresh: no names, no content
	Assign(key string, val interface{}) *LazyStringerMap // assign a string "val" to name "key"
	Delete(key string) *LazyStringerMap                  // forget name "key" (and related content, if any)
	// Following may also be used in templates
	Fetch(key string) (interface{}, bool) // obtain content named "key", iff any
	Lookup(key string) string             // obtain content named "key" - as (eventually empty) string
	//
	Len() int // How many things do I contain right now?
}

// Init - Want my content reborn empty?
func (d *LazyStringerMap) Init() *LazyStringerMap {
	d.protectMe()       // protect me, and ...
	defer d.releaseMe() // release me, let me go ...
	d.init()
	return d
}

// Assign - You want to let my content named "key" to be the "val"-string?
func (d *LazyStringerMap) Assign(key string, val interface{}) *LazyStringerMap {
	d.protectMe()       // protect me, and ...
	defer d.releaseMe() // release me, let me go ...
	d.val[key] = val
	return d
}

// Lookup - You want my content named "key" - as (eventually empty) string
func (d *LazyStringerMap) Lookup(key string) string {
	d.lazyInit()        // non-nil me ...
	d.l.RLock()         // protect me, and ...
	defer d.l.RUnlock() // release me, let me go ...
	if c, ok := d.val[key]; ok {
		return ats.GetString(c)
	}

	return ""
}

// Fetch - You want my content named "key", iff any
func (d *LazyStringerMap) Fetch(key string) (interface{}, bool) {
	d.lazyInit()        // non-nil me ...
	d.l.RLock()         // protect me, and ...
	defer d.l.RUnlock() // release me, let me go ...
	if c, ok := d.val[key]; ok {
		return c, true
	}

	return nil, false
}

// Delete - You want me to forget about name "key" (and it's related content)?
func (d *LazyStringerMap) Delete(key string) *LazyStringerMap {
	d.protectMe()       // protect me, and ...
	defer d.releaseMe() // release me, let me go ...
	delete(d.val, key)
	return d
}

// Len - How many things do I contain right now?
func (d *LazyStringerMap) Len() int {
	d.lazyInit()        // non-nil me ...
	d.l.RLock()         // protect me, and ...
	defer d.l.RUnlock() // release me, let me go ...
	return len(d.val)
}
<commit_msg>new: Clone<commit_after>// Copyright 2016 Andreas Pannewitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package lsm

import (
	"github.com/golangsam/do/ats" // anything to string
)

// UserFriendly - interface exposed for go doc only
//
// I love to be easy - thus: I give You a simple API!
//  Create me with New, if You like - Note: No need, I'm friendly :-)
//  and Init me to use me afresh,
//  Assign any name (as key) to any value,
//  and Fetch a value by it's name,
//  Lookup a value as string by it's name (as key),
//  Delete a key, if You don't need it any more
//  as You please :-)
//
type UserFriendly interface {
	// Following may be chained:
	Init() *LazyStringerMap                              // (re)start afresh: no names, no content
	Assign(key string, val interface{}) *LazyStringerMap // assign a string "val" to name "key"
	Delete(key string) *LazyStringerMap                  // forget name "key" (and related content, if any)
	Clone() *LazyStringerMap                             // obtain a fresh Lazy String Map with a copy of original content

	// Following may also be used in templates:
	Fetch(key string) (interface{}, bool) // obtain content named "key", iff any
	Lookup(key string) string             // obtain content named "key" - as (eventually empty) string

	Len() int // How many things do I contain right now?
}

// Init - Want my content reborn empty?
func (d *LazyStringerMap) Init() *LazyStringerMap {
	d.protectMe()       // protect me, and ...
	defer d.releaseMe() // release me, let me go ...
	d.init()
	return d
}

// Assign - You want to let my content named "key" to be the "val"-string?
func (d *LazyStringerMap) Assign(key string, val interface{}) *LazyStringerMap {
	d.protectMe()       // protect me, and ...
	defer d.releaseMe() // release me, let me go ...
	d.val[key] = val
	return d
}

// Delete - You want me to forget about name "key" (and it's related content)?
func (d *LazyStringerMap) Delete(key string) *LazyStringerMap {
	d.protectMe()       // protect me, and ...
	defer d.releaseMe() // release me, let me go ...
	delete(d.val, key)
	return d
}

// Clone - a fresh Lazy String Map
// with a copy of original content
func (d *LazyStringerMap) Clone() *LazyStringerMap {
	n := New()
	n.val = d.val
	return n
}

// Lookup - You want my content named "key" - as (eventually empty) string
func (d *LazyStringerMap) Lookup(key string) string {
	d.lazyInit()        // non-nil me ...
	d.l.RLock()         // protect me, and ...
	defer d.l.RUnlock() // release me, let me go ...
	if c, ok := d.val[key]; ok {
		return ats.GetString(c)
	}

	return ""
}

// Fetch - You want my content named "key", iff any
func (d *LazyStringerMap) Fetch(key string) (interface{}, bool) {
	d.lazyInit()        // non-nil me ...
	d.l.RLock()         // protect me, and ...
	defer d.l.RUnlock() // release me, let me go ...
	if c, ok := d.val[key]; ok {
		return c, true
	}

	return nil, false
}

// Len - How many things do I contain right now?
func (d *LazyStringerMap) Len() int {
	d.lazyInit()        // non-nil me ...
	d.l.RLock()         // protect me, and ...
	defer d.l.RUnlock() // release me, let me go ...
	return len(d.val)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"testing"
	"time"
)

// Should cache first response and return it on second request without
// hitting origin again.
func TestCacheFirstResponse(t *testing.T) {
	testRequestsCachedIndefinite(t, nil)
}

// Should cache responses with default TTL if the response doesn't specify
// a period itself.
func TestCacheDefaultTTL(t *testing.T) {
	t.Error("Not implemented")
}

// Should cache responses for the period defined in a `Expires: n` response
// header.
func TestCacheExpires(t *testing.T) {
	t.Error("Not implemented")
}

// Should cache responses for the period defined in a `Cache-Control:
// max-age=n` response header.
func TestCacheCacheControlMaxAge(t *testing.T) {
	const cacheDuration = time.Duration(5 * time.Second)
	headerValue := fmt.Sprintf("max-age=%.0f", cacheDuration.Seconds())

	handler := func(w http.ResponseWriter) {
		w.Header().Set("Cache-Control", headerValue)
	}

	testRequestsCachedDuration(t, handler, cacheDuration)
}

// Should cache responses with a `Cache-Control: no-cache` header. Varnish
// doesn't respect this by default.
func TestCacheCacheControlNoCache(t *testing.T) {
	handler := func(w http.ResponseWriter) {
		w.Header().Set("Cache-Control", "no-cache")
	}

	testRequestsCachedIndefinite(t, handler)
}

// Should cache responses with a status code of 404. It's a common
// misconception that 404 responses shouldn't be cached; they should because
// they can be expensive to generate.
func TestCache404Response(t *testing.T) {
	handler := func(w http.ResponseWriter) {
		w.WriteHeader(http.StatusNotFound)
	}

	testRequestsCachedIndefinite(t, handler)
}
<commit_msg>Implement TestCacheExpires<commit_after>package main

import (
	"fmt"
	"net/http"
	"testing"
	"time"
)

// Should cache first response and return it on second request without
// hitting origin again.
func TestCacheFirstResponse(t *testing.T) {
	testRequestsCachedIndefinite(t, nil)
}

// Should cache responses with default TTL if the response doesn't specify
// a period itself.
func TestCacheDefaultTTL(t *testing.T) {
	t.Error("Not implemented")
}

// Should cache responses for the period defined in a `Expires: n` response
// header.
func TestCacheExpires(t *testing.T) {
	const cacheDuration = time.Duration(5 * time.Second)

	handler := func(w http.ResponseWriter) {
		headerValue := time.Now().UTC().Add(cacheDuration).Format(http.TimeFormat)
		w.Header().Set("Expires", headerValue)
	}

	testRequestsCachedDuration(t, handler, cacheDuration)
}

// Should cache responses for the period defined in a `Cache-Control:
// max-age=n` response header.
func TestCacheCacheControlMaxAge(t *testing.T) {
	const cacheDuration = time.Duration(5 * time.Second)
	headerValue := fmt.Sprintf("max-age=%.0f", cacheDuration.Seconds())

	handler := func(w http.ResponseWriter) {
		w.Header().Set("Cache-Control", headerValue)
	}

	testRequestsCachedDuration(t, handler, cacheDuration)
}

// Should cache responses with a `Cache-Control: no-cache` header. Varnish
// doesn't respect this by default.
func TestCacheCacheControlNoCache(t *testing.T) {
	handler := func(w http.ResponseWriter) {
		w.Header().Set("Cache-Control", "no-cache")
	}

	testRequestsCachedIndefinite(t, handler)
}

// Should cache responses with a status code of 404. It's a common
// misconception that 404 responses shouldn't be cached; they should because
// they can be expensive to generate.
func TestCache404Response(t *testing.T) {
	handler := func(w http.ResponseWriter) {
		w.WriteHeader(http.StatusNotFound)
	}

	testRequestsCachedIndefinite(t, handler)
}
<|endoftext|>


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

package gochimp

import (
	"encoding/json"
	"errors"
	"time"
)

// see https://mandrillapp.com/api/docs/messages.html
const messages_send_endpoint string = "/messages/send.json"                   // Send a new transactional message through Mandrill
const messages_send_template_endpoint string = "/messages/send-template.json" // Send a new transactional message through Mandrill using a template
const messages_search_endpoint string = "/messages/search.json"               // Search the content of recently sent messages and optionally narrow by date range, tags and senders
const messages_parse_endpoint string = "/messages/parse.json"                 // Parse the full MIME document for an email message, returning the content of the message broken into its constituent pieces
const messages_send_raw_endpoint string = "/messages/send-raw.json"           // Take a raw MIME document for a message, and send it exactly as if it were sent over the SMTP protocol

func (a *MandrillAPI) MessageSend(message Message, async bool) ([]SendResponse, error) {
	var response []SendResponse
	var params map[string]interface{} = make(map[string]interface{})
	params["message"] = message
	params["async"] = async
	err := parseMandrillJson(a, messages_send_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageSendTemplate(templateName string, templateContent []Var, message Message, async bool) ([]SendResponse, error) {
	var response []SendResponse
	if templateName == "" {
		return response, errors.New("templateName cannot be blank")
	}
	var params map[string]interface{} = make(map[string]interface{})
	params["message"] = message
	params["template_name"] = templateName
	params["async"] = async
	params["template_content"] = templateContent
	err := parseMandrillJson(a, messages_send_template_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageSearch(searchRequest SearchRequest) ([]SearchResponse, error) {
	var response []SearchResponse
	var params map[string]interface{} = make(map[string]interface{})
	//todo remove this hack
	params["query"] = searchRequest.Query
	params["date_from"] = searchRequest.DateFrom
	params["date_to"] = searchRequest.DateTo
	params["tags"] = searchRequest.Tags
	params["senders"] = searchRequest.Senders
	params["limit"] = searchRequest.Limit
	err := parseMandrillJson(a, messages_search_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageParse(rawMessage string, async bool) (Message, error) {
	var response Message
	if rawMessage == "" {
		return response, errors.New("rawMessage cannot be blank")
	}
	var params map[string]interface{} = make(map[string]interface{})
	params["raw_message"] = rawMessage
	err := parseMandrillJson(a, messages_parse_endpoint, params, &response)
	return response, err
}

// Can return oneof Invalid_Key, ValidationError or GeneralError
func (a *MandrillAPI) MessageSendRaw(rawMessage string, to []string, from Recipient, async bool) ([]SendResponse, error) {
	var response []SendResponse
	if rawMessage == "" {
		return response, errors.New("rawMessage cannot be blank")
	}
	if len(to) <= 0 {
		return response, errors.New("You need at least one recipient in the To array")
	}

	var params map[string]interface{} = make(map[string]interface{})
	params["raw_message"] = rawMessage
	params["from_email"] = from.Email
	params["from_name"] = from.Name
	params["to"] = to
	params["async"] = async
	err := parseMandrillJson(a, messages_send_raw_endpoint, params, &response)
	return response, err
}

type SearchResponse struct {
	Timestamp time.Duration       `json:"ts"`
	Id        string              `json:"_id"`
	Sender    string              `json:"sender"`
	Subject   string              `json:"subject"`
	Email     string              `json:"email"`
	Tags      []string            `json:"tags"`
	Opens     int                 `json:"opens"`
	Clicks    int                 `json:"clicks"`
	State     string              `json:"state"`
	Metadata  []map[string]string `json:"metadata"`
}

type SearchRequest struct {
	Query    string    `json:"query"`
	DateFrom time.Time `json:"date_from"`
	DateTo   time.Time `json:"date_to"`
	Tags     []string  `json:"tags"`
	Senders  []string  `json:"senders"`
	Limit    int       `json:"limit"`
}

type Message struct {
	Html                    string              `json:"html,omitempty"`
	Text                    string              `json:"text,omitempty"`
	Subject                 string              `json:"subject"`
	FromEmail               string              `json:"from_email"`
	FromName                string              `json:"from_name"`
	To                      []Recipient         `json:"to"`
	Headers                 map[string]string   `json:"headers,omitempty"`
	TrackOpens              bool                `json:"track_opens"`
	TrackClicks             bool                `json:"track_clicks"`
	ViewContentLink         bool                `json:"view_content_link,omitempty"`
	AutoText                bool                `json:"auto_text,omitempty"`
	AutoHtml                bool                `json:"auto_html,omitempty"`
	UrlStripQS              bool                `json:"url_strip_qs,omitempty"`
	InlineCss               bool                `json:"inline_css,omitempty"`
	PreserveRecipients      bool                `json:"preserve_recipients,omitempty"`
	Important               bool                `json:"important,omitempty"`
	BCCAddress              string              `json:"bcc_address,omitempty"`
	TrackingDomain          string              `json:"tracking_domain,omitempty"`
	SigningDomain           string              `json:"signing_domain,omitempty"`
	ReturnPathDomain        string              `json:"return_path_domain,omitempty"`
	Merge                   bool                `json:"merge,omitempty"`
	GlobalMergeVars         []Var               `json:"global_merge_vars,omitempty"`
	MergeVars               []MergeVars         `json:"merge_vars,omitempty"`
	Tags                    []string            `json:"tags,omitempty"`
	GoogleAnalyticsDomains  []string            `json:"google_analytics_domains,omitempty"`
	GoogleAnalyticsCampaign []string            `json:"google_analytics_campaign,omitempty"`
	Metadata                []map[string]string `json:"metadata,omitempty"`
	RecipientMetadata       []RecipientMetaData `json:"recipient_metadata,omitempty"`
	Attachments             []Attachment        `json:"attachments,omitempty"`
}

func (m *Message) String() string {
	b, _ := json.Marshal(m)
	return string(b)
}

func (m *Message) AddHeader(key, value string) {
	if m.Headers == nil {
		m.Headers = make(map[string]string)
	}
	m.Headers[key] = value
}

func (m *Message) AddRecipients(r ...Recipient) {
	m.To = append(m.To, r...)
}

func (m *Message) AddGlobalMergeVar(globalvars ...Var) {
	m.GlobalMergeVars = append(m.GlobalMergeVars, globalvars...)
}

func (m *Message) AddMergeVar(vars ...MergeVars) {
	m.MergeVars = append(m.MergeVars, vars...)
}

func (m *Message) AddTag(tags ...string) {
	m.Tags = append(m.Tags, tags...)
}

func (m *Message) AddGoogleAnalyticsDomains(domains ...string) {
	m.GoogleAnalyticsDomains = append(m.GoogleAnalyticsDomains, domains...)
}

func (m *Message) AddGoogleAnalyticsCampaign(campaigns ...string) {
	m.GoogleAnalyticsCampaign = append(m.GoogleAnalyticsCampaign, campaigns...)
}

func (m *Message) AddMetadata(metadata ...map[string]string) {
	m.Metadata = append(m.Metadata, metadata...)
}

func (m *Message) AddRecipientMetadata(metadata ...RecipientMetaData) {
	m.RecipientMetadata = append(m.RecipientMetadata, metadata...)
}

func (m *Message) AddAttachments(attachement ...Attachment) {
	m.Attachments = append(m.Attachments, attachement...)
}

type Attachment struct {
	Type    string `json:"type"`
	Name    string `json:"name"`
	Content string `json:"content"`
}
type RecipientMetaData struct {
	Recipient string            `json:"rcpt"`
	Vars      map[string]string `json:"values"`
}

type MergeVars struct {
	Recipient string `json:"rcpt"`
	Vars      []Var  `json:"vars"`
}

type Var struct {
	Name    string `json:"name"`
	Content string `json:"content"`
}

func NewVar(name string, content string) *Var {
	return &Var{Name: name, Content: content}
}

type Recipient struct {
	Email string `json:"email"`
	Name  string `json:"name"`
	Type  string `json:"type"`
}

type SendResponse struct {
	Email  string `json:"email"`
	Status string `json:"status"`
}
<commit_msg>Put id and rejected reason back in send message response<commit_after>// Copyright 2013 Matthew Baird
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//     http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gochimp

import (
	"encoding/json"
	"errors"
	"time"
)

// see https://mandrillapp.com/api/docs/messages.html
const messages_send_endpoint string = "/messages/send.json"                   // Send a new transactional message through Mandrill
const messages_send_template_endpoint string = "/messages/send-template.json" // Send a new transactional message through Mandrill using a template
const messages_search_endpoint string = "/messages/search.json"               // Search the content of recently sent messages and optionally narrow by date range, tags and senders
const messages_parse_endpoint string = "/messages/parse.json"                 // Parse the full MIME document for an email message, returning the content of the message broken into its constituent pieces
const messages_send_raw_endpoint string = "/messages/send-raw.json"           // Take a raw MIME document for a message, and send it exactly as if it were sent over the SMTP protocol

func (a *MandrillAPI) MessageSend(message Message, async bool) ([]SendResponse, error) {
	var response []SendResponse
	var params map[string]interface{} = make(map[string]interface{})
	params["message"] = message
	params["async"] = async
	err := parseMandrillJson(a, messages_send_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageSendTemplate(templateName string, templateContent []Var, message Message, async bool) ([]SendResponse, error) {
	var response []SendResponse
	if templateName == "" {
		return response, errors.New("templateName cannot be blank")
	}
	var params map[string]interface{} = make(map[string]interface{})
	params["message"] = message
	params["template_name"] = templateName
	params["async"] = async
	params["template_content"] = templateContent
	err := parseMandrillJson(a, messages_send_template_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageSearch(searchRequest SearchRequest) ([]SearchResponse, error) {
	var response []SearchResponse
	var params map[string]interface{} = make(map[string]interface{})
	//todo remove this hack
	params["query"] = searchRequest.Query
	params["date_from"] = searchRequest.DateFrom
	params["date_to"] = searchRequest.DateTo
	params["tags"] = searchRequest.Tags
	params["senders"] = searchRequest.Senders
	params["limit"] = searchRequest.Limit
	err := parseMandrillJson(a, messages_search_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageParse(rawMessage string, async bool) (Message, error) {
	var response Message
	if rawMessage == "" {
		return response, errors.New("rawMessage cannot be blank")
	}
	var params map[string]interface{} = make(map[string]interface{})
	params["raw_message"] = rawMessage
	err := parseMandrillJson(a, messages_parse_endpoint, params, &response)
	return response, err
}

// Can return oneof Invalid_Key, ValidationError or GeneralError
func (a *MandrillAPI) MessageSendRaw(rawMessage string, to []string, from Recipient, async bool) ([]SendResponse, error) {
	var response []SendResponse
	if rawMessage == "" {
		return response, errors.New("rawMessage cannot be blank")
	}
	if len(to) <= 0 {
		return response, errors.New("You need at least one recipient in the To array")
	}

	var params map[string]interface{} = make(map[string]interface{})
	params["raw_message"] = rawMessage
	params["from_email"] = from.Email
	params["from_name"] = from.Name
	params["to"] = to
	params["async"] = async
	err := parseMandrillJson(a, messages_send_raw_endpoint, params, &response)
	return response, err
}

type SearchResponse struct {
	Timestamp time.Duration       `json:"ts"`
	Id        string              `json:"_id"`
	Sender    string              `json:"sender"`
	Subject   string              `json:"subject"`
	Email     string              `json:"email"`
	Tags      []string            `json:"tags"`
	Opens     int                 `json:"opens"`
	Clicks    int                 `json:"clicks"`
	State     string              `json:"state"`
	Metadata  []map[string]string `json:"metadata"`
}

type SearchRequest struct {
	Query    string    `json:"query"`
	DateFrom time.Time `json:"date_from"`
	DateTo   time.Time `json:"date_to"`
	Tags     []string  `json:"tags"`
	Senders  []string  `json:"senders"`
	Limit    int       `json:"limit"`
}

type Message struct {
	Html                    string              `json:"html,omitempty"`
	Text                    string              `json:"text,omitempty"`
	Subject                 string              `json:"subject"`
	FromEmail               string              `json:"from_email"`
	FromName                string              `json:"from_name"`
	To                      []Recipient         `json:"to"`
	Headers                 map[string]string   `json:"headers,omitempty"`
	TrackOpens              bool                `json:"track_opens"`
	TrackClicks             bool                `json:"track_clicks"`
	ViewContentLink         bool                `json:"view_content_link,omitempty"`
	AutoText                bool                `json:"auto_text,omitempty"`
	AutoHtml                bool                `json:"auto_html,omitempty"`
	UrlStripQS              bool                `json:"url_strip_qs,omitempty"`
	InlineCss               bool                `json:"inline_css,omitempty"`
	PreserveRecipients      bool                `json:"preserve_recipients,omitempty"`
	Important               bool                `json:"important,omitempty"`
	BCCAddress              string              `json:"bcc_address,omitempty"`
	TrackingDomain          string              `json:"tracking_domain,omitempty"`
	SigningDomain           string              `json:"signing_domain,omitempty"`
	ReturnPathDomain        string              `json:"return_path_domain,omitempty"`
	Merge                   bool                `json:"merge,omitempty"`
	GlobalMergeVars         []Var               `json:"global_merge_vars,omitempty"`
	MergeVars               []MergeVars         `json:"merge_vars,omitempty"`
	Tags                    []string            `json:"tags,omitempty"`
	GoogleAnalyticsDomains  []string            `json:"google_analytics_domains,omitempty"`
	GoogleAnalyticsCampaign []string            `json:"google_analytics_campaign,omitempty"`
	Metadata                []map[string]string `json:"metadata,omitempty"`
	RecipientMetadata       []RecipientMetaData `json:"recipient_metadata,omitempty"`
	Attachments             []Attachment        `json:"attachments,omitempty"`
}

func (m *Message) String() string {
	b, _ := json.Marshal(m)
	return string(b)
}

func (m *Message) AddHeader(key, value string) {
	if m.Headers == nil {
		m.Headers = make(map[string]string)
	}
	m.Headers[key] = value
}

func (m *Message) AddRecipients(r ...Recipient) {
	m.To = append(m.To, r...)
}

func (m *Message) AddGlobalMergeVar(globalvars ...Var) {
	m.GlobalMergeVars = append(m.GlobalMergeVars, globalvars...)
}

func (m *Message) AddMergeVar(vars ...MergeVars) {
	m.MergeVars = append(m.MergeVars, vars...)
}

func (m *Message) AddTag(tags ...string) {
	m.Tags = append(m.Tags, tags...)
}

func (m *Message) AddGoogleAnalyticsDomains(domains ...string) {
	m.GoogleAnalyticsDomains = append(m.GoogleAnalyticsDomains, domains...)
}

func (m *Message) AddGoogleAnalyticsCampaign(campaigns ...string) {
	m.GoogleAnalyticsCampaign = append(m.GoogleAnalyticsCampaign, campaigns...)
}

func (m *Message) AddMetadata(metadata ...map[string]string) {
	m.Metadata = append(m.Metadata, metadata...)
}

func (m *Message) AddRecipientMetadata(metadata ...RecipientMetaData) {
	m.RecipientMetadata = append(m.RecipientMetadata, metadata...)
}

func (m *Message) AddAttachments(attachement ...Attachment) {
	m.Attachments = append(m.Attachments, attachement...)
}

type Attachment struct {
	Type    string `json:"type"`
	Name    string `json:"name"`
	Content string `json:"content"`
}
type RecipientMetaData struct {
	Recipient string            `json:"rcpt"`
	Vars      map[string]string `json:"values"`
}

type MergeVars struct {
	Recipient string `json:"rcpt"`
	Vars      []Var  `json:"vars"`
}

type Var struct {
	Name    string `json:"name"`
	Content string `json:"content"`
}

func NewVar(name string, content string) *Var {
	return &Var{Name: name, Content: content}
}

type Recipient struct {
	Email string `json:"email"`
	Name  string `json:"name"`
	Type  string `json:"type"`
}

type SendResponse struct {
	Email          string `json:"email"`
	Status         string `json:"status"`
	Id             string `json:"_id"`
	RejectedReason string `json:"rejected_reason"`
}
<|endoftext|>


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

package gochimp

import (
	"encoding/json"
	"errors"
	"time"
)

// see https://mandrillapp.com/api/docs/messages.html
const messages_send_endpoint string = "/messages/send.json"                   // Send a new transactional message through Mandrill
const messages_send_template_endpoint string = "/messages/send-template.json" // Send a new transactional message through Mandrill using a template
const messages_search_endpoint string = "/messages/search.json"               // Search the content of recently sent messages and optionally narrow by date range, tags and senders
const messages_parse_endpoint string = "/messages/parse.json"                 // Parse the full MIME document for an email message, returning the content of the message broken into its constituent pieces
const messages_send_raw_endpoint string = "/messages/send-raw.json"           // Take a raw MIME document for a message, and send it exactly as if it were sent over the SMTP protocol

func (a *MandrillAPI) MessageSend(message Message, async bool) ([]SendResponse, error) {
	var response []SendResponse
	var params map[string]interface{} = make(map[string]interface{})
	params["message"] = message
	params["async"] = async
	err := parseMandrillJson(a, messages_send_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageSendTemplate(templateName string, templateContent []Var, message Message, async bool) ([]SendResponse, error) {
	var response []SendResponse
	if templateName == "" {
		return response, errors.New("templateName cannot be blank")
	}
	var params map[string]interface{} = make(map[string]interface{})
	params["message"] = message
	params["template_name"] = templateName
	params["async"] = async
	params["template_content"] = templateContent
	err := parseMandrillJson(a, messages_send_template_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageSearch(searchRequest SearchRequest) ([]SearchResponse, error) {
	var response []SearchResponse
	var params map[string]interface{} = make(map[string]interface{})
	//todo remove this hack
	params["query"] = searchRequest.Query
	params["date_from"] = searchRequest.DateFrom
	params["date_to"] = searchRequest.DateTo
	params["tags"] = searchRequest.Tags
	params["senders"] = searchRequest.Senders
	params["limit"] = searchRequest.Limit
	err := parseMandrillJson(a, messages_search_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageParse(rawMessage string, async bool) (Message, error) {
	var response Message
	if rawMessage == "" {
		return response, errors.New("rawMessage cannot be blank")
	}
	var params map[string]interface{} = make(map[string]interface{})
	params["raw_message"] = rawMessage
	err := parseMandrillJson(a, messages_parse_endpoint, params, &response)
	return response, err
}

// Can return oneof Invalid_Key, ValidationError or GeneralError
func (a *MandrillAPI) MessageSendRaw(rawMessage string, to []string, from Recipient, async bool) ([]SendResponse, error) {
	var response []SendResponse
	if rawMessage == "" {
		return response, errors.New("rawMessage cannot be blank")
	}
	if len(to) <= 0 {
		return response, errors.New("You need at least one recipient in the To array")
	}

	var params map[string]interface{} = make(map[string]interface{})
	params["raw_message"] = rawMessage
	params["from_email"] = from.Email
	params["from_name"] = from.Name
	params["to"] = to
	params["async"] = async
	err := parseMandrillJson(a, messages_send_raw_endpoint, params, &response)
	return response, err
}

type SearchResponse struct {
	Timestamp time.Duration       `json:"ts"`
	Id        string              `json:"_id"`
	Sender    string              `json:"sender"`
	Subject   string              `json:"subject"`
	Email     string              `json:"email"`
	Tags      []string            `json:"tags"`
	Opens     int                 `json:"opens"`
	Clicks    int                 `json:"clicks"`
	State     string              `json:"state"`
	Metadata  []map[string]string `json:"metadata"`
}

type SearchRequest struct {
	Query    string    `json:"query"`
	DateFrom time.Time `json:"date_from"`
	DateTo   time.Time `json:"date_to"`
	Tags     []string  `json:"tags"`
	Senders  []string  `json:"senders"`
	Limit    int       `json:"limit"`
}

type Message struct {
	Html                    string              `json:"html,omitempty"`
	Text                    string              `json:"text,omitempty"`
	Subject                 string              `json:"subject"`
	FromEmail               string              `json:"from_email"`
	FromName                string              `json:"from_name"`
	To                      []Recipient         `json:"to"`
	Headers                 map[string]string   `json:"headers,omitempty"`
	TrackOpens              bool                `json:"track_opens"`
	TrackClicks             bool                `json:"track_clicks"`
	ViewContentLink         bool                `json:"view_content_link,omitempty"`
	AutoText                bool                `json:"auto_text,omitempty"`
	AutoHtml                bool                `json:"auto_html,omitempty"`
	UrlStripQS              bool                `json:"url_strip_qs,omitempty"`
	InlineCss               bool                `json:"inline_css,omitempty"`
	PreserveRecipients      bool                `json:"preserve_recipients,omitempty"`
	Important               bool                `json:"important,omitempty"`
	BCCAddress              string              `json:"bcc_address,omitempty"`
	TrackingDomain          string              `json:"tracking_domain,omitempty"`
	SigningDomain           string              `json:"signing_domain,omitempty"`
	ReturnPathDomain        string              `json:"return_path_domain,omitempty"`
	Merge                   bool                `json:"merge,omitempty"`
	GlobalMergeVars         []Var               `json:"global_merge_vars,omitempty"`
	MergeVars               []MergeVars         `json:"merge_vars,omitempty"`
	Tags                    []string            `json:"tags,omitempty"`
	Subaccount              string              `json:"subaccount,omitempty"`
	GoogleAnalyticsDomains  []string            `json:"google_analytics_domains,omitempty"`
	GoogleAnalyticsCampaign []string            `json:"google_analytics_campaign,omitempty"`
	Metadata                []map[string]string `json:"metadata,omitempty"`
	RecipientMetadata       []RecipientMetaData `json:"recipient_metadata,omitempty"`
	Attachments             []Attachment        `json:"attachments,omitempty"`
}

func (m *Message) String() string {
	b, _ := json.Marshal(m)
	return string(b)
}

func (m *Message) AddHeader(key, value string) {
	if m.Headers == nil {
		m.Headers = make(map[string]string)
	}
	m.Headers[key] = value
}

func (m *Message) AddRecipients(r ...Recipient) {
	m.To = append(m.To, r...)
}

func (m *Message) AddGlobalMergeVar(globalvars ...Var) {
	m.GlobalMergeVars = append(m.GlobalMergeVars, globalvars...)
}

func (m *Message) AddMergeVar(vars ...MergeVars) {
	m.MergeVars = append(m.MergeVars, vars...)
}

func (m *Message) AddTag(tags ...string) {
	m.Tags = append(m.Tags, tags...)
}

func (m *Message) AddGoogleAnalyticsDomains(domains ...string) {
	m.GoogleAnalyticsDomains = append(m.GoogleAnalyticsDomains, domains...)
}

func (m *Message) AddGoogleAnalyticsCampaign(campaigns ...string) {
	m.GoogleAnalyticsCampaign = append(m.GoogleAnalyticsCampaign, campaigns...)
}

func (m *Message) AddMetadata(metadata ...map[string]string) {
	m.Metadata = append(m.Metadata, metadata...)
}

func (m *Message) AddRecipientMetadata(metadata ...RecipientMetaData) {
	m.RecipientMetadata = append(m.RecipientMetadata, metadata...)
}

func (m *Message) AddAttachments(attachement ...Attachment) {
	m.Attachments = append(m.Attachments, attachement...)
}

type Attachment struct {
	Type    string `json:"type"`
	Name    string `json:"name"`
	Content string `json:"content"`
}
type RecipientMetaData struct {
	Recipient string            `json:"rcpt"`
	Vars      map[string]string `json:"values"`
}

type MergeVars struct {
	Recipient string `json:"rcpt"`
	Vars      []Var  `json:"vars"`
}

type Var struct {
	Name    string `json:"name"`
	Content string `json:"content"`
}

func NewVar(name string, content string) *Var {
	return &Var{Name: name, Content: content}
}

type Recipient struct {
	Email string `json:"email"`
	Name  string `json:"name"`
	Type  string `json:"type"`
}

type SendResponse struct {
	Email          string `json:"email"`
	Status         string `json:"status"`
	Id             string `json:"_id"`
	RejectedReason string `json:"rejected_reason"`
}
<commit_msg>Fixed message metadata<commit_after>// Copyright 2013 Matthew Baird
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//     http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gochimp

import (
	"encoding/json"
	"errors"
	"time"
)

// see https://mandrillapp.com/api/docs/messages.html
const messages_send_endpoint string = "/messages/send.json"                   // Send a new transactional message through Mandrill
const messages_send_template_endpoint string = "/messages/send-template.json" // Send a new transactional message through Mandrill using a template
const messages_search_endpoint string = "/messages/search.json"               // Search the content of recently sent messages and optionally narrow by date range, tags and senders
const messages_parse_endpoint string = "/messages/parse.json"                 // Parse the full MIME document for an email message, returning the content of the message broken into its constituent pieces
const messages_send_raw_endpoint string = "/messages/send-raw.json"           // Take a raw MIME document for a message, and send it exactly as if it were sent over the SMTP protocol

func (a *MandrillAPI) MessageSend(message Message, async bool) ([]SendResponse, error) {
	var response []SendResponse
	var params map[string]interface{} = make(map[string]interface{})
	params["message"] = message
	params["async"] = async
	err := parseMandrillJson(a, messages_send_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageSendTemplate(templateName string, templateContent []Var, message Message, async bool) ([]SendResponse, error) {
	var response []SendResponse
	if templateName == "" {
		return response, errors.New("templateName cannot be blank")
	}
	var params map[string]interface{} = make(map[string]interface{})
	params["message"] = message
	params["template_name"] = templateName
	params["async"] = async
	params["template_content"] = templateContent
	err := parseMandrillJson(a, messages_send_template_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageSearch(searchRequest SearchRequest) ([]SearchResponse, error) {
	var response []SearchResponse
	var params map[string]interface{} = make(map[string]interface{})
	//todo remove this hack
	params["query"] = searchRequest.Query
	params["date_from"] = searchRequest.DateFrom
	params["date_to"] = searchRequest.DateTo
	params["tags"] = searchRequest.Tags
	params["senders"] = searchRequest.Senders
	params["limit"] = searchRequest.Limit
	err := parseMandrillJson(a, messages_search_endpoint, params, &response)
	return response, err
}

func (a *MandrillAPI) MessageParse(rawMessage string, async bool) (Message, error) {
	var response Message
	if rawMessage == "" {
		return response, errors.New("rawMessage cannot be blank")
	}
	var params map[string]interface{} = make(map[string]interface{})
	params["raw_message"] = rawMessage
	err := parseMandrillJson(a, messages_parse_endpoint, params, &response)
	return response, err
}

// Can return oneof Invalid_Key, ValidationError or GeneralError
func (a *MandrillAPI) MessageSendRaw(rawMessage string, to []string, from Recipient, async bool) ([]SendResponse, error) {
	var response []SendResponse
	if rawMessage == "" {
		return response, errors.New("rawMessage cannot be blank")
	}
	if len(to) <= 0 {
		return response, errors.New("You need at least one recipient in the To array")
	}

	var params map[string]interface{} = make(map[string]interface{})
	params["raw_message"] = rawMessage
	params["from_email"] = from.Email
	params["from_name"] = from.Name
	params["to"] = to
	params["async"] = async
	err := parseMandrillJson(a, messages_send_raw_endpoint, params, &response)
	return response, err
}

type SearchResponse struct {
	Timestamp time.Duration       `json:"ts"`
	Id        string              `json:"_id"`
	Sender    string              `json:"sender"`
	Subject   string              `json:"subject"`
	Email     string              `json:"email"`
	Tags      []string            `json:"tags"`
	Opens     int                 `json:"opens"`
	Clicks    int                 `json:"clicks"`
	State     string              `json:"state"`
	Metadata  []map[string]string `json:"metadata"`
}

type SearchRequest struct {
	Query    string    `json:"query"`
	DateFrom time.Time `json:"date_from"`
	DateTo   time.Time `json:"date_to"`
	Tags     []string  `json:"tags"`
	Senders  []string  `json:"senders"`
	Limit    int       `json:"limit"`
}

type Message struct {
	Html                    string              `json:"html,omitempty"`
	Text                    string              `json:"text,omitempty"`
	Subject                 string              `json:"subject"`
	FromEmail               string              `json:"from_email"`
	FromName                string              `json:"from_name"`
	To                      []Recipient         `json:"to"`
	Headers                 map[string]string   `json:"headers,omitempty"`
	TrackOpens              bool                `json:"track_opens"`
	TrackClicks             bool                `json:"track_clicks"`
	ViewContentLink         bool                `json:"view_content_link,omitempty"`
	AutoText                bool                `json:"auto_text,omitempty"`
	AutoHtml                bool                `json:"auto_html,omitempty"`
	UrlStripQS              bool                `json:"url_strip_qs,omitempty"`
	InlineCss               bool                `json:"inline_css,omitempty"`
	PreserveRecipients      bool                `json:"preserve_recipients,omitempty"`
	Important               bool                `json:"important,omitempty"`
	BCCAddress              string              `json:"bcc_address,omitempty"`
	TrackingDomain          string              `json:"tracking_domain,omitempty"`
	SigningDomain           string              `json:"signing_domain,omitempty"`
	ReturnPathDomain        string              `json:"return_path_domain,omitempty"`
	Merge                   bool                `json:"merge,omitempty"`
	GlobalMergeVars         []Var               `json:"global_merge_vars,omitempty"`
	MergeVars               []MergeVars         `json:"merge_vars,omitempty"`
	Tags                    []string            `json:"tags,omitempty"`
	Subaccount              string              `json:"subaccount,omitempty"`
	GoogleAnalyticsDomains  []string            `json:"google_analytics_domains,omitempty"`
	GoogleAnalyticsCampaign []string            `json:"google_analytics_campaign,omitempty"`
	Metadata                map[string]string   `json:"metadata,omitempty"`
	RecipientMetadata       []RecipientMetaData `json:"recipient_metadata,omitempty"`
	Attachments             []Attachment        `json:"attachments,omitempty"`
}

func (m *Message) String() string {
	b, _ := json.Marshal(m)
	return string(b)
}

func (m *Message) AddHeader(key, value string) {
	if m.Headers == nil {
		m.Headers = make(map[string]string)
	}
	m.Headers[key] = value
}

func (m *Message) AddRecipients(r ...Recipient) {
	m.To = append(m.To, r...)
}

func (m *Message) AddGlobalMergeVar(globalvars ...Var) {
	m.GlobalMergeVars = append(m.GlobalMergeVars, globalvars...)
}

func (m *Message) AddMergeVar(vars ...MergeVars) {
	m.MergeVars = append(m.MergeVars, vars...)
}

func (m *Message) AddTag(tags ...string) {
	m.Tags = append(m.Tags, tags...)
}

func (m *Message) AddGoogleAnalyticsDomains(domains ...string) {
	m.GoogleAnalyticsDomains = append(m.GoogleAnalyticsDomains, domains...)
}

func (m *Message) AddGoogleAnalyticsCampaign(campaigns ...string) {
	m.GoogleAnalyticsCampaign = append(m.GoogleAnalyticsCampaign, campaigns...)
}

func (m *Message) AddMetadata(key, value string) {
	if m.Metadata == nil {
		m.Metadata = make(map[string]string)
	}
	m.Metadata[key] = value

func (m *Message) AddRecipientMetadata(metadata ...RecipientMetaData) {
	m.RecipientMetadata = append(m.RecipientMetadata, metadata...)
}

func (m *Message) AddAttachments(attachement ...Attachment) {
	m.Attachments = append(m.Attachments, attachement...)
}

type Attachment struct {
	Type    string `json:"type"`
	Name    string `json:"name"`
	Content string `json:"content"`
}
type RecipientMetaData struct {
	Recipient string            `json:"rcpt"`
	Vars      map[string]string `json:"values"`
}

type MergeVars struct {
	Recipient string `json:"rcpt"`
	Vars      []Var  `json:"vars"`
}

type Var struct {
	Name    string `json:"name"`
	Content string `json:"content"`
}

func NewVar(name string, content string) *Var {
	return &Var{Name: name, Content: content}
}

type Recipient struct {
	Email string `json:"email"`
	Name  string `json:"name"`
	Type  string `json:"type"`
}

type SendResponse struct {
	Email          string `json:"email"`
	Status         string `json:"status"`
	Id             string `json:"_id"`
	RejectedReason string `json:"rejected_reason"`
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"testing"

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

// These tests ensure that the code generator generates valid code that can be built
// in combination with Thrift's autogenerated code.

func TestAllThrift(t *testing.T) {
	files, err := ioutil.ReadDir("test_files")
	require.NoError(t, err, "Cannot read test_files directory: %v", err)

	for _, f := range files {
		fname := f.Name()
		if f.IsDir() || filepath.Ext(fname) != ".thrift" {
			continue
		}

		if err := runSingleFileTest(t, filepath.Join("test_files", fname)); err != nil {
			t.Errorf("Thrift file %v failed: %v", fname, err)
		}
	}
}

func TestIncludeThrift(t *testing.T) {
	dirs, err := ioutil.ReadDir("test_files/include_test")
	require.NoError(t, err, "Cannot read test_files/include_test directory: %v", err)

	for _, d := range dirs {
		dname := d.Name()
		if !d.IsDir() {
			continue
		}

		if err := runDirTest(t, filepath.Join("test_files/include_test/", dname)); err != nil {
			t.Errorf("Thrift test %v failed: %v", dname, err)
		}
	}
}

func TestMultipleFiles(t *testing.T) {
	if err := runSingleFileTest(t, filepath.Join("test_files", "multi_test", "file1.thrift")); err != nil {
		t.Errorf("Multiple file test failed: %v", err)
	}
}

func copyFile(src, dst string) error {
	f, err := os.Open(src)
	if err != nil {
		return err
	}
	defer f.Close()

	writeF, err := os.OpenFile(dst, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
	if err != nil {
		return err
	}
	defer writeF.Close()

	_, err = io.Copy(writeF, f)
	return err
}

// setupDirectory creates a temporary directory.
func setupDirectory(thriftFile string) (string, error) {
	tempDir, err := ioutil.TempDir("", "thrift-gen")
	if err != nil {
		return "", err
	}

	return tempDir, nil
}

func runSingleFileTest(t *testing.T, thriftFile string) error {
	tempDir, err := ioutil.TempDir("", "thrift-gen")
	if err != nil {
		return err
	}

	return runTest(t, tempDir, thriftFile)
}

func runDirTest(t *testing.T, thriftDir string) error {
	tempDir, err := ioutil.TempDir("", "thrift-gen")
	if err != nil {
		return err
	}

	// The entry point should a file with the same basename as the dir.
	thriftFile := filepath.Join(thriftDir, path.Base(thriftDir)+".thrift")
	return runTest(t, tempDir, thriftFile)
}

func runTest(t *testing.T, tempDir, thriftFile string) error {
	// Generate code from the Thrift file.
	*packagePrefix = "../"
	if err := processFile(true /* generateThrift */, thriftFile, tempDir); err != nil {
		return fmt.Errorf("processFile(%s) in %q failed: %v", thriftFile, tempDir, err)
	}

	// Run go build to ensure that the generated code builds.
	cmd := exec.Command("go", "build", "./...")
	cmd.Dir = filepath.Join(tempDir)
	if output, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("Build in %q failed.\nError: %v Output:\n%v\n", tempDir, err, string(output))
	}

	// Only delete the temp directory on success.
	os.RemoveAll(tempDir)
	return nil
}
<commit_msg>Simplify test<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"testing"

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

// These tests ensure that the code generator generates valid code that can be built
// in combination with Thrift's autogenerated code.

func TestAllThrift(t *testing.T) {
	files, err := ioutil.ReadDir("test_files")
	require.NoError(t, err, "Cannot read test_files directory: %v", err)

	for _, f := range files {
		fname := f.Name()
		if f.IsDir() || filepath.Ext(fname) != ".thrift" {
			continue
		}

		if err := runTest(t, filepath.Join("test_files", fname)); err != nil {
			t.Errorf("Thrift file %v failed: %v", fname, err)
		}
	}
}

func TestIncludeThrift(t *testing.T) {
	dirs, err := ioutil.ReadDir("test_files/include_test")
	require.NoError(t, err, "Cannot read test_files/include_test directory: %v", err)

	for _, d := range dirs {
		dname := d.Name()
		if !d.IsDir() {
			continue
		}

		thriftFile := filepath.Join(dname, path.Base(dname)+".thrift")
		if err := runTest(t, filepath.Join("test_files/include_test/", thriftFile)); err != nil {
			t.Errorf("Thrift test %v failed: %v", dname, err)
		}
	}
}

func TestMultipleFiles(t *testing.T) {
	if err := runTest(t, filepath.Join("test_files", "multi_test", "file1.thrift")); err != nil {
		t.Errorf("Multiple file test failed: %v", err)
	}
}

func copyFile(src, dst string) error {
	f, err := os.Open(src)
	if err != nil {
		return err
	}
	defer f.Close()

	writeF, err := os.OpenFile(dst, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
	if err != nil {
		return err
	}
	defer writeF.Close()

	_, err = io.Copy(writeF, f)
	return err
}

// setupDirectory creates a temporary directory.
func setupDirectory(thriftFile string) (string, error) {
	tempDir, err := ioutil.TempDir("", "thrift-gen")
	if err != nil {
		return "", err
	}

	return tempDir, nil
}

func runTest(t *testing.T, thriftFile string) error {
	tempDir, err := ioutil.TempDir("", "thrift-gen")
	if err != nil {
		return err
	}

	// Generate code from the Thrift file.
	*packagePrefix = "../"
	if err := processFile(true /* generateThrift */, thriftFile, tempDir); err != nil {
		return fmt.Errorf("processFile(%s) in %q failed: %v", thriftFile, tempDir, err)
	}

	// Run go build to ensure that the generated code builds.
	cmd := exec.Command("go", "build", "./...")
	cmd.Dir = filepath.Join(tempDir)
	if output, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("Build in %q failed.\nError: %v Output:\n%v\n", tempDir, err, string(output))
	}

	// Only delete the temp directory on success.
	os.RemoveAll(tempDir)
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors.

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

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

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

package authtls

import (
	"github.com/pkg/errors"
	extensions "k8s.io/api/extensions/v1beta1"

	"regexp"

	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
	ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
	"k8s.io/ingress-nginx/internal/ingress/resolver"
	"k8s.io/ingress-nginx/internal/k8s"
)

const (
	defaultAuthTLSDepth     = 1
	defaultAuthVerifyClient = "on"
)

var (
	authVerifyClientRegex = regexp.MustCompile(`on|off|optional|optional_no_ca`)
)

// Config contains the AuthSSLCert used for muthual autentication
// and the configured ValidationDepth
type Config struct {
	resolver.AuthSSLCert
	VerifyClient       string `json:"verify_client"`
	ValidationDepth    int    `json:"validationDepth"`
	ErrorPage          string `json:"errorPage"`
	PassCertToUpstream bool   `json:"passCertToUpstream"`
	AuthTLSError       string
}

// Equal tests for equality between two Config types
func (assl1 *Config) Equal(assl2 *Config) bool {
	if assl1 == assl2 {
		return true
	}
	if assl1 == nil || assl2 == nil {
		return false
	}
	if !(&assl1.AuthSSLCert).Equal(&assl2.AuthSSLCert) {
		return false
	}
	if assl1.VerifyClient != assl2.VerifyClient {
		return false
	}
	if assl1.ValidationDepth != assl2.ValidationDepth {
		return false
	}
	if assl1.ErrorPage != assl2.ErrorPage {
		return false
	}
	if assl1.PassCertToUpstream != assl2.PassCertToUpstream {
		return false
	}

	return true
}

// NewParser creates a new TLS authentication annotation parser
func NewParser(resolver resolver.Resolver) parser.IngressAnnotation {
	return authTLS{resolver}
}

type authTLS struct {
	r resolver.Resolver
}

// Parse parses the annotations contained in the ingress
// rule used to use a Certificate as authentication method
func (a authTLS) Parse(ing *extensions.Ingress) (interface{}, error) {

	tlsauthsecret, err := parser.GetStringAnnotation("auth-tls-secret", ing)
	if err != nil {
		return &Config{}, err
	}

	if tlsauthsecret == "" {
		return &Config{}, ing_errors.NewLocationDenied("an empty string is not a valid secret name")
	}

	_, _, err = k8s.ParseNameNS(tlsauthsecret)
	if err != nil {
		return &Config{}, ing_errors.NewLocationDenied(err.Error())
	}

	tlsVerifyClient, err := parser.GetStringAnnotation("auth-tls-verify-client", ing)
	if err != nil || !authVerifyClientRegex.MatchString(tlsVerifyClient) {
		tlsVerifyClient = defaultAuthVerifyClient
	}

	tlsdepth, err := parser.GetIntAnnotation("auth-tls-verify-depth", ing)
	if err != nil || tlsdepth == 0 {
		tlsdepth = defaultAuthTLSDepth
	}

	authCert, err := a.r.GetAuthCertificate(tlsauthsecret)
	if err != nil {
		e := errors.Wrap(err, "error obtaining certificate")
		return &Config{}, ing_errors.LocationDenied{Reason: e}
	}

	errorpage, err := parser.GetStringAnnotation("auth-tls-error-page", ing)
	if err != nil || errorpage == "" {
		errorpage = ""
	}

	passCert, err := parser.GetBoolAnnotation("auth-tls-pass-certificate-to-upstream", ing)
	if err != nil {
		passCert = false
	}

	return &Config{
		AuthSSLCert:        *authCert,
		VerifyClient:       tlsVerifyClient,
		ValidationDepth:    tlsdepth,
		ErrorPage:          errorpage,
		PassCertToUpstream: passCert,
	}, nil
}
<commit_msg>Typo fix: muthual autentication -> mutual authentication<commit_after>/*
Copyright 2015 The Kubernetes Authors.

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

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

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

package authtls

import (
	"github.com/pkg/errors"
	extensions "k8s.io/api/extensions/v1beta1"

	"regexp"

	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
	ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
	"k8s.io/ingress-nginx/internal/ingress/resolver"
	"k8s.io/ingress-nginx/internal/k8s"
)

const (
	defaultAuthTLSDepth     = 1
	defaultAuthVerifyClient = "on"
)

var (
	authVerifyClientRegex = regexp.MustCompile(`on|off|optional|optional_no_ca`)
)

// Config contains the AuthSSLCert used for mutual authentication
// and the configured ValidationDepth
type Config struct {
	resolver.AuthSSLCert
	VerifyClient       string `json:"verify_client"`
	ValidationDepth    int    `json:"validationDepth"`
	ErrorPage          string `json:"errorPage"`
	PassCertToUpstream bool   `json:"passCertToUpstream"`
	AuthTLSError       string
}

// Equal tests for equality between two Config types
func (assl1 *Config) Equal(assl2 *Config) bool {
	if assl1 == assl2 {
		return true
	}
	if assl1 == nil || assl2 == nil {
		return false
	}
	if !(&assl1.AuthSSLCert).Equal(&assl2.AuthSSLCert) {
		return false
	}
	if assl1.VerifyClient != assl2.VerifyClient {
		return false
	}
	if assl1.ValidationDepth != assl2.ValidationDepth {
		return false
	}
	if assl1.ErrorPage != assl2.ErrorPage {
		return false
	}
	if assl1.PassCertToUpstream != assl2.PassCertToUpstream {
		return false
	}

	return true
}

// NewParser creates a new TLS authentication annotation parser
func NewParser(resolver resolver.Resolver) parser.IngressAnnotation {
	return authTLS{resolver}
}

type authTLS struct {
	r resolver.Resolver
}

// Parse parses the annotations contained in the ingress
// rule used to use a Certificate as authentication method
func (a authTLS) Parse(ing *extensions.Ingress) (interface{}, error) {

	tlsauthsecret, err := parser.GetStringAnnotation("auth-tls-secret", ing)
	if err != nil {
		return &Config{}, err
	}

	if tlsauthsecret == "" {
		return &Config{}, ing_errors.NewLocationDenied("an empty string is not a valid secret name")
	}

	_, _, err = k8s.ParseNameNS(tlsauthsecret)
	if err != nil {
		return &Config{}, ing_errors.NewLocationDenied(err.Error())
	}

	tlsVerifyClient, err := parser.GetStringAnnotation("auth-tls-verify-client", ing)
	if err != nil || !authVerifyClientRegex.MatchString(tlsVerifyClient) {
		tlsVerifyClient = defaultAuthVerifyClient
	}

	tlsdepth, err := parser.GetIntAnnotation("auth-tls-verify-depth", ing)
	if err != nil || tlsdepth == 0 {
		tlsdepth = defaultAuthTLSDepth
	}

	authCert, err := a.r.GetAuthCertificate(tlsauthsecret)
	if err != nil {
		e := errors.Wrap(err, "error obtaining certificate")
		return &Config{}, ing_errors.LocationDenied{Reason: e}
	}

	errorpage, err := parser.GetStringAnnotation("auth-tls-error-page", ing)
	if err != nil || errorpage == "" {
		errorpage = ""
	}

	passCert, err := parser.GetBoolAnnotation("auth-tls-pass-certificate-to-upstream", ing)
	if err != nil {
		passCert = false
	}

	return &Config{
		AuthSSLCert:        *authCert,
		VerifyClient:       tlsVerifyClient,
		ValidationDepth:    tlsdepth,
		ErrorPage:          errorpage,
		PassCertToUpstream: passCert,
	}, nil
}
<|endoftext|>