<commit_before>package models

import (
	"fmt"
	"github.com/coopernurse/gorp"
	"github.com/revel/revel"
)

type Profile struct {
	ProfileId          int
	UserId             int
	Name               string
	Summary            string
	Description        string
	PhotoUrl           string
	AggregateFollowers int
	AggregateFollowing int

	// Transient
	User               *User
}

func (p *Profile) String() string {
	return fmt.Sprintf("Profile(%s)", p.Summary)
}

func (profile *Profile) Validate(v *revel.Validation) {
	ValidateProfileName(v, profile.Name)
	ValidateProfileSummary(v, profile.Summary)
	ValidateProfileDescription(v, profile.Description)
	ValidateProfilePhotoUrl(v, profile.PhotoUrl)
}

func ValidateProfileName(v *revel.Validation, name string) *revel.ValidationResult {
	result := v.Required(name).Message("Name required")
	if !result.Ok {
		return result
	}

	result = v.MinSize(name, 6).Message("Name must be at least 6 characters")
	if !result.Ok {
		return result
	}

	result = v.MaxSize(name, 100).Message("Name must be at most 100 characters")

	return result
}

func ValidateProfileSummary(v *revel.Validation, summary string) *revel.ValidationResult {
	result := v.Required(summary).Message("Profile summary is required")
	if !result.Ok {
		return result
	}

	result = v.MinSize(summary, 3).Message("Profile summary must exceed 2 characters")
	if !result.Ok {
		return result
	}

	result = v.MaxSize(summary, 140).Message("Profile summary cannot exceed 140 characters")

	return result
}

func ValidateProfileDescription(v *revel.Validation, description string) *revel.ValidationResult {
	result := v.MaxSize(description, 400).Message("Profile description cannot exceed 400 characters")

	return result
}

func ValidateProfilePhotoUrl(v *revel.Validation, photoUrl string) *revel.ValidationResult {
	result := v.MaxSize(photoUrl, 200).Message("Photo URL cannot exceed 200 characters")

	return result
}

func (p *Profile) PostGet(exe gorp.SqlExecutor) error {
	var (
		obj interface{}
		err error
	)

	obj, err = exe.Get(User{}, p.UserId)
	if err != nil {
		return fmt.Errorf("Error loading a profile's user (%d): %s", p.UserId, err)
	}
	p.User = obj.(*User)

	/*obj, err = exe.Get(Post{}, p.ProfileId)
	if err != nil {
		return fmt.Errorf("Error loading a profile's posts (%d): %s", p.ProfileId, err)
	}
	var posts []*Post
	for _, post := range obj {
		posts = append(posts, post.(*Post))
	}
	p.Posts = posts*/

	return nil
}
<commit_msg>Make Profile summary optional (since it is not mandatory when a user signs up either)<commit_after>package models

import (
	"fmt"
	"github.com/coopernurse/gorp"
	"github.com/revel/revel"
)

type Profile struct {
	ProfileId          int
	UserId             int
	Name               string
	Summary            string
	Description        string
	PhotoUrl           string
	AggregateFollowers int
	AggregateFollowing int

	// Transient
	User               *User
}

func (p *Profile) String() string {
	return fmt.Sprintf("Profile(%s)", p.Summary)
}

func (profile *Profile) Validate(v *revel.Validation) {
	ValidateProfileName(v, profile.Name)
	ValidateProfileSummary(v, profile.Summary)
	ValidateProfileDescription(v, profile.Description)
	ValidateProfilePhotoUrl(v, profile.PhotoUrl)
}

func ValidateProfileName(v *revel.Validation, name string) *revel.ValidationResult {
	result := v.Required(name).Message("Name required")
	if !result.Ok {
		return result
	}

	result = v.MinSize(name, 6).Message("Name must be at least 6 characters")
	if !result.Ok {
		return result
	}

	result = v.MaxSize(name, 100).Message("Name must be at most 100 characters")

	return result
}

func ValidateProfileSummary(v *revel.Validation, summary string) *revel.ValidationResult {
	result := v.MaxSize(summary, 140).Message("Profile summary cannot exceed 140 characters")

	return result
}

func ValidateProfileDescription(v *revel.Validation, description string) *revel.ValidationResult {
	result := v.MaxSize(description, 400).Message("Profile description cannot exceed 400 characters")

	return result
}

func ValidateProfilePhotoUrl(v *revel.Validation, photoUrl string) *revel.ValidationResult {
	result := v.MaxSize(photoUrl, 200).Message("Photo URL cannot exceed 200 characters")

	return result
}

func (p *Profile) PostGet(exe gorp.SqlExecutor) error {
	var (
		obj interface{}
		err error
	)

	obj, err = exe.Get(User{}, p.UserId)
	if err != nil {
		return fmt.Errorf("Error loading a profile's user (%d): %s", p.UserId, err)
	}
	p.User = obj.(*User)

	/*obj, err = exe.Get(Post{}, p.ProfileId)
	if err != nil {
		return fmt.Errorf("Error loading a profile's posts (%d): %s", p.ProfileId, err)
	}
	var posts []*Post
	for _, post := range obj {
		posts = append(posts, post.(*Post))
	}
	p.Posts = posts*/

	return nil
}
<|endoftext|>


<commit_before>package grafana

import (
	"encoding/json"
	"time"
)

type DashboardID uint64

type dashboardStyle string

const (
	dashboardDarkStyle  dashboardStyle = "dark"
	dashboardLightStyle dashboardStyle = "light"
)

type Dashboard struct {
	ID      DashboardID `json:"id"`
	Version uint64      `json:"version"`

	Editable      bool           `json:"editable"`
	GraphTooltip  uint8          `json:"graphTooltip"`
	HideControls  bool           `json:"hideControls"`
	Rows          []*Row         `json:"rows"`
	Style         dashboardStyle `json:"style"`
	Timezone      string         `json:"timezone"`
	Title         string         `json:"title"`
	tags          []string
	Meta          *DashboardMeta `json:"meta,omitempty"`
	SchemaVersion int            `json:"schemaVersion"`
}

// NewDashboard creates new Dashboard.
func NewDashboard(title string) *Dashboard {
	return &Dashboard{
		Title:         title,
		Editable:      true,
		SchemaVersion: 14,
		Style:         dashboardDarkStyle,
	}
}

func (d *Dashboard) String() string {
	return Stringify(d)
}

// Tags is a getter for Dashboard tags field
func (d *Dashboard) Tags() []string {
	return d.tags
}

// SetTags sets new tags to dashboard
func (d *Dashboard) SetTags(tags ...string) {
	newTags := []string{}
	uniqTags := make(map[string]bool)
	for _, tag := range tags {
		if _, ok := uniqTags[tag]; ok {
			continue
		}

		uniqTags[tag] = true
		newTags = append(newTags, tag)
	}

	d.tags = newTags
}

// AddTags adds given tags to dashboard. This method keeps uniqueness of tags.
func (d *Dashboard) AddTags(tags ...string) {
	tagFound := make(map[string]bool, len(d.tags))
	for _, tag := range d.tags {
		tagFound[tag] = true
	}

	for _, tag := range tags {
		if _, ok := tagFound[tag]; ok {
			continue
		}
		d.tags = append(d.tags, tag)
	}
}

// RemoveTags removes given tags from dashboard. Does nothing if tag is not found.
func (d *Dashboard) RemoveTags(tags ...string) {
	tagIndex := make(map[string]int, len(d.tags))
	for i, tag := range d.tags {
		tagIndex[tag] = i
	}

	for _, tag := range tags {
		if i, ok := tagIndex[tag]; ok {
			d.tags = append(d.tags[:i], d.tags[i+1:]...)
		}
	}
}

// UnmarshalJSON implements json.Unmarshaler interface
func (d *Dashboard) UnmarshalJSON(data []byte) error {
	type JSONDashboard Dashboard
	inDashboard := struct {
		*JSONDashboard
		Tags []string `json:"tags"`
	}{
		JSONDashboard: (*JSONDashboard)(d),
	}
	if err := json.Unmarshal(data, &inDashboard); err != nil {
		return err
	}

	d.tags = inDashboard.Tags

	return nil
}

// MarshalJSON implements json.Marshaler interface
func (d *Dashboard) MarshalJSON() ([]byte, error) {
	type JSONDashboard Dashboard
	dd := (*JSONDashboard)(d)
	dd.Meta = nil

	return json.Marshal(&struct {
		*JSONDashboard
		Tags []string       `json:"tags"`
		Meta *DashboardMeta `json:"-"`
	}{
		JSONDashboard: dd,
		Tags:          d.Tags(),
	})
}

type DashboardMeta struct {
	Slug    string `json:"slug"`
	Type    string `json:"type"`
	Version int    `json:"version"`

	CanEdit bool `json:"canEdit"`
	CanSave bool `json:"canSave"`
	CanStar bool `json:"canStar"`

	Created   time.Time `json:"created"`
	CreatedBy string    `json:"createdBy"`
	Expires   time.Time `json:"expires"`
	Updated   time.Time `json:"updated"`
	UpdatedBy string    `json:"updatedBy"`
}

func (dm *DashboardMeta) String() string {
	return Stringify(dm)
}

type Row struct {
	Collapsed bool         `json:"collapse"`
	Editable  bool         `json:"editable"`
	Height    string       `json:"height"`
	Panels    []*TextPanel `json:"panels"`
	RepeatFor string       `json:"repeat"` // repeat row for given variable
	ShowTitle bool         `json:"showTitle"`
	Title     string       `json:"title"`
	TitleSize string       `json:"titleSize"` // TODO: validation: h1-h6
}

// NewRow creates new Row with somw defaults.
func NewRow() *Row {
	return &Row{
		Editable: true,
	}
}

type TextPanelMode string

const (
	TextPanelHTMLMode     TextPanelMode = "html"
	TextPanelMarkdownMode TextPanelMode = "markdown"
	TextPanelTextMode     TextPanelMode = "text"
)

type TextPanel struct {
	Content string        `json:"content"`
	Mode    TextPanelMode `json:"mode"`

	// General options
	ID          int    `json:"id"` // Not sure if it's necessary
	Description string `json:"description"`
	Height      string `json:"height"`
	// Links       []*PanelLink `json:"links"`
	MinSpan     int    `json:"minSpan"`        // TODO: valid values: 1-12
	Span        int    `json:"span,omitempty"` // TODO: valid values: 1-12
	Title       string `json:"title"`
	Transparent bool   `json:"transparent"`
	Type        string `json:"type"` // required
}

// NewTextPanel creates new "Text" panel.
func NewTextPanel(mode TextPanelMode) *TextPanel {
	return &TextPanel{
		Mode:    mode,
		Type:    "text",
		MinSpan: 12,
	}
}

type PanelLink struct {
	IncludeVars  bool   `json:"includeVars"`
	KeepTime     bool   `json:"keepTime"`
	Params       string `json:"params"`
	OpenInNewTab bool   `json:"targetBlank"`
	Type         string `json:"type"` // TODO validation: absolute/dashboard

	// type=absolute
	Title string `json:"title,omitempty"`
	URL   string `json:"url,omitempty"`

	// type=dashboard
	DashboardURI string `json:"dashUri,omitempty"`   // TODO: validation. should be valid dashboard
	Dashboard    string `json:"dashboard,omitempty"` // actually it's title
}

// NewPanelLink creates new PanelLink
func NewPanelLink(panelType string) *PanelLink {
	return &PanelLink{
		Type: panelType, // TODO: validation
	}
}
<commit_msg>Panel must have an ID.<commit_after>package grafana

import (
	"encoding/json"
	"time"
)

type DashboardID uint64

type dashboardStyle string

const (
	dashboardDarkStyle  dashboardStyle = "dark"
	dashboardLightStyle dashboardStyle = "light"
)

type Dashboard struct {
	ID      DashboardID `json:"id"`
	Version uint64      `json:"version"`

	Editable      bool           `json:"editable"`
	GraphTooltip  uint8          `json:"graphTooltip"`
	HideControls  bool           `json:"hideControls"`
	Rows          []*Row         `json:"rows"`
	Style         dashboardStyle `json:"style"`
	Timezone      string         `json:"timezone"`
	Title         string         `json:"title"`
	tags          []string
	Meta          *DashboardMeta `json:"meta,omitempty"`
	SchemaVersion int            `json:"schemaVersion"`
}

// NewDashboard creates new Dashboard.
func NewDashboard(title string) *Dashboard {
	return &Dashboard{
		Title:         title,
		Editable:      true,
		SchemaVersion: 14,
		Style:         dashboardDarkStyle,
	}
}

func (d *Dashboard) String() string {
	return Stringify(d)
}

// Tags is a getter for Dashboard tags field
func (d *Dashboard) Tags() []string {
	return d.tags
}

// SetTags sets new tags to dashboard
func (d *Dashboard) SetTags(tags ...string) {
	newTags := []string{}
	uniqTags := make(map[string]bool)
	for _, tag := range tags {
		if _, ok := uniqTags[tag]; ok {
			continue
		}

		uniqTags[tag] = true
		newTags = append(newTags, tag)
	}

	d.tags = newTags
}

// AddTags adds given tags to dashboard. This method keeps uniqueness of tags.
func (d *Dashboard) AddTags(tags ...string) {
	tagFound := make(map[string]bool, len(d.tags))
	for _, tag := range d.tags {
		tagFound[tag] = true
	}

	for _, tag := range tags {
		if _, ok := tagFound[tag]; ok {
			continue
		}
		d.tags = append(d.tags, tag)
	}
}

// RemoveTags removes given tags from dashboard. Does nothing if tag is not found.
func (d *Dashboard) RemoveTags(tags ...string) {
	tagIndex := make(map[string]int, len(d.tags))
	for i, tag := range d.tags {
		tagIndex[tag] = i
	}

	for _, tag := range tags {
		if i, ok := tagIndex[tag]; ok {
			d.tags = append(d.tags[:i], d.tags[i+1:]...)
		}
	}
}

// UnmarshalJSON implements json.Unmarshaler interface
func (d *Dashboard) UnmarshalJSON(data []byte) error {
	type JSONDashboard Dashboard
	inDashboard := struct {
		*JSONDashboard
		Tags []string `json:"tags"`
	}{
		JSONDashboard: (*JSONDashboard)(d),
	}
	if err := json.Unmarshal(data, &inDashboard); err != nil {
		return err
	}

	d.tags = inDashboard.Tags

	return nil
}

// MarshalJSON implements json.Marshaler interface
func (d *Dashboard) MarshalJSON() ([]byte, error) {
	type JSONDashboard Dashboard
	dd := (*JSONDashboard)(d)
	dd.Meta = nil

	return json.Marshal(&struct {
		*JSONDashboard
		Tags []string       `json:"tags"`
		Meta *DashboardMeta `json:"-"`
	}{
		JSONDashboard: dd,
		Tags:          d.Tags(),
	})
}

type DashboardMeta struct {
	Slug    string `json:"slug"`
	Type    string `json:"type"`
	Version int    `json:"version"`

	CanEdit bool `json:"canEdit"`
	CanSave bool `json:"canSave"`
	CanStar bool `json:"canStar"`

	Created   time.Time `json:"created"`
	CreatedBy string    `json:"createdBy"`
	Expires   time.Time `json:"expires"`
	Updated   time.Time `json:"updated"`
	UpdatedBy string    `json:"updatedBy"`
}

func (dm *DashboardMeta) String() string {
	return Stringify(dm)
}

type Row struct {
	Collapsed bool         `json:"collapse"`
	Editable  bool         `json:"editable"`
	Height    string       `json:"height"`
	Panels    []*TextPanel `json:"panels"`
	RepeatFor string       `json:"repeat"` // repeat row for given variable
	ShowTitle bool         `json:"showTitle"`
	Title     string       `json:"title"`
	TitleSize string       `json:"titleSize"` // TODO: validation: h1-h6
}

// MarshalJSON implements encoding/json.Marshaler
func (r *Row) MarshalJSON() ([]byte, error) {
	for i, p := range r.Panels {
		p.id = uint(i + 1)
	}
	type JSONRow Row
	jr := (*JSONRow)(r)
	return json.Marshal(jr)
}

// NewRow creates new Row with somw defaults.
func NewRow() *Row {
	return &Row{
		Editable: true,
	}
}

type TextPanelMode string

const (
	TextPanelHTMLMode     TextPanelMode = "html"
	TextPanelMarkdownMode TextPanelMode = "markdown"
	TextPanelTextMode     TextPanelMode = "text"
)

type TextPanel struct {
	Content string        `json:"content"`
	Mode    TextPanelMode `json:"mode"`

	// General options
	id          uint
	Description string       `json:"description"`
	Height      string       `json:"height"`
	Links       []*PanelLink `json:"links"`
	MinSpan     int          `json:"minSpan"`        // TODO: valid values: 1-12
	Span        int          `json:"span,omitempty"` // TODO: valid values: 1-12
	Title       string       `json:"title"`
	Transparent bool         `json:"transparent"`
	Type        string       `json:"type"` // required
}

func (p *TextPanel) MarshalJSON() ([]byte, error) {
	type JSONPanel TextPanel
	jp := (*JSONPanel)(p)
	return json.Marshal(&struct {
		*JSONPanel
		ID uint `json:"id"`
	}{
		JSONPanel: jp,
		ID:        jp.id,
	})
}

// NewTextPanel creates new "Text" panel.
func NewTextPanel(mode TextPanelMode) *TextPanel {
	return &TextPanel{
		Mode:    mode,
		Type:    "text",
		MinSpan: 12,
	}
}

type PanelLink struct {
	IncludeVars  bool   `json:"includeVars"`
	KeepTime     bool   `json:"keepTime"`
	Params       string `json:"params"`
	OpenInNewTab bool   `json:"targetBlank"`
	Type         string `json:"type"` // TODO validation: absolute/dashboard

	// type=absolute
	Title string `json:"title,omitempty"`
	URL   string `json:"url,omitempty"`

	// type=dashboard
	DashboardURI string `json:"dashUri,omitempty"`   // TODO: validation. should be valid dashboard
	Dashboard    string `json:"dashboard,omitempty"` // actually it's title
}

// NewPanelLink creates new PanelLink
func NewPanelLink(panelType string) *PanelLink {
	return &PanelLink{
		Type: panelType, // TODO: validation
	}
}
<|endoftext|>


<commit_before>package iffy

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
	"text/template"
)

type Tester struct {
	t      *testing.T
	r      http.Handler
	Calls  []*Call
	values Values
	Fatal  bool
}

type Headers map[string]string

type Call struct {
	Name       string
	Method     string
	QueryStr   string
	Body       string
	headers    Headers
	respObject interface{}
	checkers   []Checker
}

func (c *Call) ResponseObject(respObject interface{}) *Call {
	c.respObject = respObject
	return c
}

func (c *Call) Headers(h Headers) *Call {
	c.headers = h
	return c
}

func (c *Call) Checkers(ch ...Checker) *Call {
	c.checkers = ch
	return c
}

type Checker func(r *http.Response, body string, respObject interface{}) error

// Tester

func NewTester(t *testing.T, r http.Handler, calls ...*Call) *Tester {
	return &Tester{
		t:      t,
		r:      r,
		values: make(Values),
	}
}

func (t *Tester) Reset() {
	t.Calls = []*Call{}
}

func (t *Tester) AddCall(name, method, querystr, body string) *Call {
	c := &Call{
		Name:     name,
		Method:   method,
		QueryStr: querystr,
		Body:     body,
	}
	t.Calls = append(t.Calls, c)
	return c
}

func (it *Tester) Run() {
	for _, c := range it.Calls {
		it.t.Run(c.Name, func(t *testing.T) {
			body := bytes.NewBufferString(it.applyTemplate(c.Body))
			requestURI := it.applyTemplate(c.QueryStr)

			req, err := http.NewRequest(c.Method, requestURI, body)
			if err != nil {
				t.Error(err)
				return
			}

			// Save unparsed url for http routers whi use it
			req.RequestURI = requestURI

			if c.Body != "" {
				req.Header.Set("content-type", "application/json")
			}
			if c.headers != nil {
				for k, v := range c.headers {
					req.Header.Set(it.applyTemplate(k), it.applyTemplate(v))
				}
			}
			w := httptest.NewRecorder()
			it.r.ServeHTTP(w, req)
			resp := w.Result()
			var respBody string
			if resp.Body != nil {
				rb, err := ioutil.ReadAll(resp.Body)
				if err != nil {
					t.Error(err)
				}
				respBody = string(rb)
				resp.Body.Close()
				if c.respObject != nil {
					err = json.Unmarshal(rb, c.respObject)
					if err != nil {
						t.Error(err)
					}
				}

				dec := json.NewDecoder(bytes.NewBuffer(rb))
				dec.UseNumber()

				var retJson interface{}
				err = dec.Decode(&retJson)
				if err == nil {
					it.values[c.Name] = retJson
				}
			}
			failed := false
			for _, checker := range c.checkers {
				err = checker(resp, respBody, c.respObject)
				if err != nil {
					t.Errorf("%s: %s", c.Name, err)
					failed = true
				}
			}
			if failed && it.Fatal {
				t.FailNow()
			}
		})
	}
}

func (t *Tester) applyTemplate(s string) string {
	b, err := t.values.Apply(s)
	if err != nil {
		t.t.Error(err)
		return ""
	}
	return string(b)
}

type Values map[string]interface{}

func (v Values) Apply(templateStr string) ([]byte, error) {

	var funcMap = template.FuncMap{
		"field": v.fieldTmpl,
		"json":  v.jsonFieldTmpl,
	}

	tmpl, err := template.New("tmpl").Funcs(funcMap).Parse(templateStr)
	if err != nil {
		return nil, err
	}

	b := new(bytes.Buffer)

	err = tmpl.Execute(b, v)
	if err != nil {
		return nil, err
	}

	return b.Bytes(), nil
}

// templating funcs

func (v Values) fieldTmpl(key ...string) (interface{}, error) {
	var i interface{}

	i = map[string]interface{}(v)
	var ok bool

	for _, k := range key {
		switch i.(type) {
		case map[string]interface{}:
			i, ok = i.(map[string]interface{})[k]
			if !ok {
				i = "<no value>"
			}
		case map[string]string:
			i, ok = i.(map[string]string)[k]
			if !ok {
				i = "<no value>"
			}
		default:
			return nil, fmt.Errorf("cannot dereference %T", i)
		}
	}
	return i, nil
}

func (v Values) jsonFieldTmpl(key ...string) (interface{}, error) {
	i, err := v.fieldTmpl(key...)
	if err != nil {
		return nil, err
	}
	marshalled, err := json.Marshal(i)
	if err != nil {
		return nil, err
	}
	return string(marshalled), nil
}

// BUILT IN CHECKERS

func ExpectStatus(st int) Checker {
	return func(r *http.Response, body string, respObject interface{}) error {
		if r.StatusCode != st {
			return fmt.Errorf("Bad status code: expected %d, got %d", st, r.StatusCode)
		}
		return nil
	}
}

func DumpResponse(t *testing.T) Checker {
	return func(r *http.Response, body string, respObject interface{}) error {
		t.Log(body)
		return nil
	}
}

func UnmarshalResponse(i interface{}) Checker {
	return func(r *http.Response, body string, respObject interface{}) error {
		return json.Unmarshal([]byte(body), i)
	}
}

func ExpectJSONFields(fields ...string) Checker {
	return func(r *http.Response, body string, respObject interface{}) error {
		m := map[string]interface{}{}
		err := json.Unmarshal([]byte(body), &m)
		if err != nil {
			return err
		}
		for _, f := range fields {
			if _, ok := m[f]; !ok {
				return fmt.Errorf("Missing expected field '%s'", f)
			}
		}
		return nil
	}
}

func ExpectListLength(length int) Checker {
	return func(r *http.Response, body string, respObject interface{}) error {
		l := []interface{}{}
		err := json.Unmarshal([]byte(body), &l)
		if err != nil {
			return err
		}
		if len(l) != length {
			return fmt.Errorf("Expected a list of length %d, got %d", length, len(l))
		}
		return nil
	}
}

func ExpectListNonEmpty(r *http.Response, body string, respObject interface{}) error {
	l := []interface{}{}
	err := json.Unmarshal([]byte(body), &l)
	if err != nil {
		return err
	}
	if len(l) == 0 {
		return errors.New("Expected a non empty list")
	}
	return nil
}

func ExpectJSONBranch(nodes ...string) Checker {
	return func(r *http.Response, body string, respObject interface{}) error {
		m := map[string]interface{}{}
		err := json.Unmarshal([]byte(body), &m)
		if err != nil {
			return err
		}
		for i, n := range nodes {
			v, ok := m[n]
			if !ok {
				return fmt.Errorf("Missing node '%s'", n)
			}
			if child, ok := v.(map[string]interface{}); ok {
				m = child
			} else if i == len(nodes)-2 {
				// last child is not an object anymore
				// and there's only one more node to check
				// test last child against last provided node
				lastNode := nodes[i+1]
				if fmt.Sprintf("%v", v) != lastNode {
					return fmt.Errorf("Wrong value: expected '%v', got '%v'", lastNode, v)
				}
				return nil
			}
		}
		return nil
	}
}
<commit_msg>iffy: Allow to customize Host field<commit_after>package iffy

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
	"text/template"
)

type Tester struct {
	t      *testing.T
	r      http.Handler
	Calls  []*Call
	values Values
	Fatal  bool
}

type Headers map[string]string

type Call struct {
	Name       string
	Method     string
	QueryStr   string
	Body       string
	headers    Headers
	host       string
	respObject interface{}
	checkers   []Checker
}

func (c *Call) ResponseObject(respObject interface{}) *Call {
	c.respObject = respObject
	return c
}

func (c *Call) Headers(h Headers) *Call {
	c.headers = h
	return c
}

func (c *Call) Host(h string) *Call {
	c.host = h
	return c
}

func (c *Call) Checkers(ch ...Checker) *Call {
	c.checkers = ch
	return c
}

type Checker func(r *http.Response, body string, respObject interface{}) error

// Tester

func NewTester(t *testing.T, r http.Handler, calls ...*Call) *Tester {
	return &Tester{
		t:      t,
		r:      r,
		values: make(Values),
	}
}

func (t *Tester) Reset() {
	t.Calls = []*Call{}
}

func (t *Tester) AddCall(name, method, querystr, body string) *Call {
	c := &Call{
		Name:     name,
		Method:   method,
		QueryStr: querystr,
		Body:     body,
	}
	t.Calls = append(t.Calls, c)
	return c
}

func (it *Tester) Run() {
	for _, c := range it.Calls {
		it.t.Run(c.Name, func(t *testing.T) {
			body := bytes.NewBufferString(it.applyTemplate(c.Body))
			requestURI := it.applyTemplate(c.QueryStr)

			req, err := http.NewRequest(c.Method, requestURI, body)
			if err != nil {
				t.Error(err)
				return
			}

			// Save unparsed url for http routers whi use it
			req.RequestURI = requestURI

			if c.Body != "" {
				req.Header.Set("content-type", "application/json")
			}
			if c.headers != nil {
				for k, v := range c.headers {
					req.Header.Set(it.applyTemplate(k), it.applyTemplate(v))
				}
			}
			if c.host != "" {
				req.Host = c.host
			}
			w := httptest.NewRecorder()
			it.r.ServeHTTP(w, req)
			resp := w.Result()
			var respBody string
			if resp.Body != nil {
				rb, err := ioutil.ReadAll(resp.Body)
				if err != nil {
					t.Error(err)
				}
				respBody = string(rb)
				resp.Body.Close()
				if c.respObject != nil {
					err = json.Unmarshal(rb, c.respObject)
					if err != nil {
						t.Error(err)
					}
				}

				dec := json.NewDecoder(bytes.NewBuffer(rb))
				dec.UseNumber()

				var retJson interface{}
				err = dec.Decode(&retJson)
				if err == nil {
					it.values[c.Name] = retJson
				}
			}
			failed := false
			for _, checker := range c.checkers {
				err = checker(resp, respBody, c.respObject)
				if err != nil {
					t.Errorf("%s: %s", c.Name, err)
					failed = true
				}
			}
			if failed && it.Fatal {
				t.FailNow()
			}
		})
	}
}

func (t *Tester) applyTemplate(s string) string {
	b, err := t.values.Apply(s)
	if err != nil {
		t.t.Error(err)
		return ""
	}
	return string(b)
}

type Values map[string]interface{}

func (v Values) Apply(templateStr string) ([]byte, error) {

	var funcMap = template.FuncMap{
		"field": v.fieldTmpl,
		"json":  v.jsonFieldTmpl,
	}

	tmpl, err := template.New("tmpl").Funcs(funcMap).Parse(templateStr)
	if err != nil {
		return nil, err
	}

	b := new(bytes.Buffer)

	err = tmpl.Execute(b, v)
	if err != nil {
		return nil, err
	}

	return b.Bytes(), nil
}

// templating funcs

func (v Values) fieldTmpl(key ...string) (interface{}, error) {
	var i interface{}

	i = map[string]interface{}(v)
	var ok bool

	for _, k := range key {
		switch i.(type) {
		case map[string]interface{}:
			i, ok = i.(map[string]interface{})[k]
			if !ok {
				i = "<no value>"
			}
		case map[string]string:
			i, ok = i.(map[string]string)[k]
			if !ok {
				i = "<no value>"
			}
		default:
			return nil, fmt.Errorf("cannot dereference %T", i)
		}
	}
	return i, nil
}

func (v Values) jsonFieldTmpl(key ...string) (interface{}, error) {
	i, err := v.fieldTmpl(key...)
	if err != nil {
		return nil, err
	}
	marshalled, err := json.Marshal(i)
	if err != nil {
		return nil, err
	}
	return string(marshalled), nil
}

// BUILT IN CHECKERS

func ExpectStatus(st int) Checker {
	return func(r *http.Response, body string, respObject interface{}) error {
		if r.StatusCode != st {
			return fmt.Errorf("Bad status code: expected %d, got %d", st, r.StatusCode)
		}
		return nil
	}
}

func DumpResponse(t *testing.T) Checker {
	return func(r *http.Response, body string, respObject interface{}) error {
		t.Log(body)
		return nil
	}
}

func UnmarshalResponse(i interface{}) Checker {
	return func(r *http.Response, body string, respObject interface{}) error {
		return json.Unmarshal([]byte(body), i)
	}
}

func ExpectJSONFields(fields ...string) Checker {
	return func(r *http.Response, body string, respObject interface{}) error {
		m := map[string]interface{}{}
		err := json.Unmarshal([]byte(body), &m)
		if err != nil {
			return err
		}
		for _, f := range fields {
			if _, ok := m[f]; !ok {
				return fmt.Errorf("Missing expected field '%s'", f)
			}
		}
		return nil
	}
}

func ExpectListLength(length int) Checker {
	return func(r *http.Response, body string, respObject interface{}) error {
		l := []interface{}{}
		err := json.Unmarshal([]byte(body), &l)
		if err != nil {
			return err
		}
		if len(l) != length {
			return fmt.Errorf("Expected a list of length %d, got %d", length, len(l))
		}
		return nil
	}
}

func ExpectListNonEmpty(r *http.Response, body string, respObject interface{}) error {
	l := []interface{}{}
	err := json.Unmarshal([]byte(body), &l)
	if err != nil {
		return err
	}
	if len(l) == 0 {
		return errors.New("Expected a non empty list")
	}
	return nil
}

func ExpectJSONBranch(nodes ...string) Checker {
	return func(r *http.Response, body string, respObject interface{}) error {
		m := map[string]interface{}{}
		err := json.Unmarshal([]byte(body), &m)
		if err != nil {
			return err
		}
		for i, n := range nodes {
			v, ok := m[n]
			if !ok {
				return fmt.Errorf("Missing node '%s'", n)
			}
			if child, ok := v.(map[string]interface{}); ok {
				m = child
			} else if i == len(nodes)-2 {
				// last child is not an object anymore
				// and there's only one more node to check
				// test last child against last provided node
				lastNode := nodes[i+1]
				if fmt.Sprintf("%v", v) != lastNode {
					return fmt.Errorf("Wrong value: expected '%v', got '%v'", lastNode, v)
				}
				return nil
			}
		}
		return nil
	}
}
<|endoftext|>


<commit_before>package bot

import (
	"fmt"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	discord "github.com/bwmarrin/discordgo"
	"github.com/patrickmn/go-cache"
)

type DiscordConfig struct {
	Token string "token"
}

var (
	dBotID      string
	dSession    *discord.Session
	dGuilds     = map[string]string{}
	dGuildChans = map[string]map[string]string{}
)

func dInit() {
	d, err := discord.New(fmt.Sprintf("Bot %s", conf.Discord.Token))
	dSession = d
	if err != nil {
		log.Fatalf("Failed to initialise Discord session: %s", err)
	}

	u, err := dSession.User("@me")
	if err != nil {
		log.Fatalf("Failed to get own Discord user: %s", err)
	}

	dBotID = u.ID

	guilds, err := dSession.UserGuilds()
	if err != nil {
		log.Fatalf("Failed to get guilds: %s", err)
	}

	for _, g := range guilds {
		chans, err := dSession.GuildChannels(g.ID)
		if err != nil {
			log.Fatalf("Failed to get channels for %s: %s", g.Name, err)
		}

		dGuilds[g.Name] = g.ID
		dGuildChans[g.Name] = map[string]string{}
		for _, c := range chans {
			if c.Type == "text" {
				dGuildChans[g.Name][c.Name] = c.ID
			}
		}
	}

	dSession.AddHandler(dMessageCreate)

	err = dSession.Open()
	if err != nil {
		log.Fatalf("Failed to connect to Discord: %s", err)
	}

	log.Infof("Connected to Discord")
}

var (
	guildCache = cache.New(5*time.Minute, 30*time.Second)
)

func dGuild(guildID string) *discord.Guild {
	cached, ok := guildCache.Get(guildID)
	if ok {
		return cached.(*discord.Guild)
	}

	guild, err := dSession.Guild(guildID)
	if err != nil {
		log.Errorf("Failed to get guild with ID %s: %s", guildID, err)
		return nil
	}

	guildCache.Set(guildID, guild, cache.DefaultExpiration)
	return guild
}

func dMessageCreate(s *discord.Session, m *discord.MessageCreate) {
	if m.Author.ID == dBotID {
		return
	}

	c, err := s.Channel(m.ChannelID)
	if err != nil {
		log.Errorf("Failed to get channel for incoming message with CID %s: %s", m.ChannelID, err)
		return
	}

	guildID := c.GuildID

	g := dGuild(guildID)
	if g == nil {
		return
	}

	message := m.Content

	// Channels
	for _, c := range g.Channels {
		if c.Type != "text" {
			continue
		}
		find := fmt.Sprintf("<#%s>", c.ID)
		replace := fmt.Sprintf("#%s", c.Name)
		message = strings.Replace(message, find, replace, -1)
	}

	// Users
	for _, u := range g.Members {
		find := fmt.Sprintf("<@%s>", u.User.ID)
		find2 := fmt.Sprintf("<@!%s>", u.User.ID)
		replace := fmt.Sprintf("@%s", u.User.Username)
		message = strings.Replace(message, find, replace, -1)
		message = strings.Replace(message, find2, replace, -1)
	}

	// Roles
	for _, r := range g.Roles {
		find := fmt.Sprintf("<@&%s>", r.ID)
		replace := fmt.Sprintf("@%s", r.Name)
		message = strings.Replace(message, find, replace, -1)
	}

	incomingDiscord(m.Author.Username, fmt.Sprintf("%s#%s", g.Name, c.Name), message)
}

func dOutgoing(nick, channel, message string) {
	chanParts := strings.Split(channel, "#")
	guildID := dGuilds[chanParts[0]]
	chanID := dGuildChans[chanParts[0]][chanParts[1]]

	g := dGuild(guildID)
	if g == nil {
		return
	}

	// Channels
	for _, c := range g.Channels {
		if c.Type != "text" {
			continue
		}
		find := fmt.Sprintf("#%s", c.Name)
		replace := fmt.Sprintf("<#%s>", c.ID)
		message = strings.Replace(message, find, replace, -1)
	}

	// Users
	for _, u := range g.Members {
		find := fmt.Sprintf("@%s", u.User.Username)
		replace := fmt.Sprintf("<@%s>", u.User.ID)
		message = strings.Replace(message, find, replace, -1)
	}

	// Roles
	for _, r := range g.Roles {
		find := fmt.Sprintf("@%s", r.Name)
		replace := fmt.Sprintf("<@&%s>", r.ID)
		message = strings.Replace(message, find, replace, -1)
	}

	dSession.ChannelMessageSend(chanID, fmt.Sprintf("**<%s>** %s", nick, message))
}
<commit_msg>Fix images in messages not showing<commit_after>package bot

import (
	"fmt"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	discord "github.com/bwmarrin/discordgo"
	"github.com/patrickmn/go-cache"
)

type DiscordConfig struct {
	Token string "token"
}

var (
	dBotID      string
	dSession    *discord.Session
	dGuilds     = map[string]string{}
	dGuildChans = map[string]map[string]string{}
)

func dInit() {
	d, err := discord.New(fmt.Sprintf("Bot %s", conf.Discord.Token))
	dSession = d
	if err != nil {
		log.Fatalf("Failed to initialise Discord session: %s", err)
	}

	u, err := dSession.User("@me")
	if err != nil {
		log.Fatalf("Failed to get own Discord user: %s", err)
	}

	dBotID = u.ID

	guilds, err := dSession.UserGuilds()
	if err != nil {
		log.Fatalf("Failed to get guilds: %s", err)
	}

	for _, g := range guilds {
		chans, err := dSession.GuildChannels(g.ID)
		if err != nil {
			log.Fatalf("Failed to get channels for %s: %s", g.Name, err)
		}

		dGuilds[g.Name] = g.ID
		dGuildChans[g.Name] = map[string]string{}
		for _, c := range chans {
			if c.Type == "text" {
				dGuildChans[g.Name][c.Name] = c.ID
			}
		}
	}

	dSession.AddHandler(dMessageCreate)

	err = dSession.Open()
	if err != nil {
		log.Fatalf("Failed to connect to Discord: %s", err)
	}

	log.Infof("Connected to Discord")
}

var (
	guildCache = cache.New(5*time.Minute, 30*time.Second)
)

func dGuild(guildID string) *discord.Guild {
	cached, ok := guildCache.Get(guildID)
	if ok {
		return cached.(*discord.Guild)
	}

	guild, err := dSession.Guild(guildID)
	if err != nil {
		log.Errorf("Failed to get guild with ID %s: %s", guildID, err)
		return nil
	}

	guildCache.Set(guildID, guild, cache.DefaultExpiration)
	return guild
}

func dMessageCreate(s *discord.Session, m *discord.MessageCreate) {
	if m.Author.ID == dBotID {
		return
	}

	c, err := s.Channel(m.ChannelID)
	if err != nil {
		log.Errorf("Failed to get channel for incoming message with CID %s: %s", m.ChannelID, err)
		return
	}

	guildID := c.GuildID

	g := dGuild(guildID)
	if g == nil {
		return
	}

	if m.Content != "" {
		message := m.Content

		// Channels
		for _, c := range g.Channels {
			if c.Type != "text" {
				continue
			}
			find := fmt.Sprintf("<#%s>", c.ID)
			replace := fmt.Sprintf("#%s", c.Name)
			message = strings.Replace(message, find, replace, -1)
		}

		// Users
		for _, u := range g.Members {
			find := fmt.Sprintf("<@%s>", u.User.ID)
			find2 := fmt.Sprintf("<@!%s>", u.User.ID)
			replace := fmt.Sprintf("@%s", u.User.Username)
			message = strings.Replace(message, find, replace, -1)
			message = strings.Replace(message, find2, replace, -1)
		}

		// Roles
		for _, r := range g.Roles {
			find := fmt.Sprintf("<@&%s>", r.ID)
			replace := fmt.Sprintf("@%s", r.Name)
			message = strings.Replace(message, find, replace, -1)
		}

		incomingDiscord(m.Author.Username, fmt.Sprintf("%s#%s", g.Name, c.Name), message)
	}
	for _, a := range m.Attachments {
		incomingDiscord(m.Author.Username, fmt.Sprintf("%s#%s", g.Name, c.Name), a.ProxyURL)
	}
}

func dOutgoing(nick, channel, message string) {
	chanParts := strings.Split(channel, "#")
	guildID := dGuilds[chanParts[0]]
	chanID := dGuildChans[chanParts[0]][chanParts[1]]

	g := dGuild(guildID)
	if g == nil {
		return
	}

	// Channels
	for _, c := range g.Channels {
		if c.Type != "text" {
			continue
		}
		find := fmt.Sprintf("#%s", c.Name)
		replace := fmt.Sprintf("<#%s>", c.ID)
		message = strings.Replace(message, find, replace, -1)
	}

	// Users
	for _, u := range g.Members {
		find := fmt.Sprintf("@%s", u.User.Username)
		replace := fmt.Sprintf("<@%s>", u.User.ID)
		message = strings.Replace(message, find, replace, -1)
	}

	// Roles
	for _, r := range g.Roles {
		find := fmt.Sprintf("@%s", r.Name)
		replace := fmt.Sprintf("<@&%s>", r.ID)
		message = strings.Replace(message, find, replace, -1)
	}

	dSession.ChannelMessageSend(chanID, fmt.Sprintf("**<%s>** %s", nick, message))
}
<|endoftext|>


<commit_before>package chat_test

import (
	"strings"
	"testing"

	"github.com/spring1843/chat-server/src/chat"
)

func TestHandleCommandInput(t *testing.T) {
	server := chat.NewServer()
	user1 := chat.NewUser("u1")

	server.AddUser(user1)

	go func(t *testing.T) {
		input := `/help`
		if _, err := user1.HandleNewInput(server, input); err != nil {
			t.Fatalf("Failed executing help command. Error %s", err)
		}
	}(t)

	incoming := user1.GetOutgoing()
	if !strings.Contains(incoming, "quit") {
		t.Errorf("Message was not read from the user, expected quit to be part of %s", incoming)
	}
}

func TestHandleBroadCastInput(t *testing.T) {
	server := chat.NewServer()
	user1, user2 := chat.NewUser("u1"), chat.NewUser("u2")

	channelName := "bar"
	server.AddChannel(channelName)
	channel, err := server.GetChannel(channelName)
	if err != nil {
		t.Fatalf("Error getting channel just added. %s", err)
	}

	server.AddUser(user1)
	server.AddUser(user2)

	channel.AddUser("u1")
	channel.AddUser("u2")

	user1.SetChannel(channelName)
	user2.SetChannel(channelName)

	go func(t *testing.T) {
		input := `foo`
		if _, err := user1.HandleNewInput(server, input); err != nil {
			t.Fatalf("Failed executing help command. Error %s", err)
		}
	}(t)

	incoming := user2.GetOutgoing()
	if !strings.Contains(incoming, "foo") {
		t.Errorf("Message was not read from the user, expected quit to be part of %s", incoming)
	}
}
<commit_msg>Check that the user can keep sending messages after a failure<commit_after>package chat_test

import (
	"strings"
	"testing"

	"github.com/spring1843/chat-server/src/chat"
)

func TestHandleCommandInput(t *testing.T) {
	server := chat.NewServer()
	user1 := chat.NewUser("u1")

	server.AddUser(user1)

	go func(t *testing.T) {
		input := `/help`
		if _, err := user1.HandleNewInput(server, input); err != nil {
			t.Fatalf("Failed executing help command. Error %s", err)
		}
	}(t)

	incoming := user1.GetOutgoing()
	if !strings.Contains(incoming, "quit") {
		t.Errorf("Message was not sent to the user, expected quit to be part of %s", incoming)
	}
}

func TestHandleCommandInputFailure(t *testing.T) {
	server := chat.NewServer()
	user1 := chat.NewUser("u1")

	server.AddUser(user1)

	go func(t *testing.T) {
		input := `/yelp`
		if _, err := user1.HandleNewInput(server, input); err == nil {
			t.Fatal("Did not fail executing invalid command", err)
		}
	}(t)

	incoming := user1.GetOutgoing()
	if !strings.Contains(incoming, "not found") {
		t.Errorf("Message was not read from the user, expected quit to be part of %s", incoming)
	}

	go func(t *testing.T) {
		input := `/help`
		if _, err := user1.HandleNewInput(server, input); err != nil {
			t.Fatalf("Failed executing help command. Error %s", err)
		}
	}(t)

	incoming = user1.GetOutgoing()
	if !strings.Contains(incoming, "quit") {
		t.Errorf("Message was not sent to the user, expected quit to be part of %s", incoming)
	}
}

func TestHandleBroadCastInput(t *testing.T) {
	server := chat.NewServer()
	user1, user2 := chat.NewUser("u1"), chat.NewUser("u2")

	channelName := "bar"
	server.AddChannel(channelName)
	channel, err := server.GetChannel(channelName)
	if err != nil {
		t.Fatalf("Error getting channel just added. %s", err)
	}

	server.AddUser(user1)
	server.AddUser(user2)

	channel.AddUser("u1")
	channel.AddUser("u2")

	user1.SetChannel(channelName)
	user2.SetChannel(channelName)

	go func(t *testing.T) {
		input := `foo`
		if _, err := user1.HandleNewInput(server, input); err != nil {
			t.Fatalf("Failed executing help command. Error %s", err)
		}
	}(t)

	incoming := user2.GetOutgoing()
	if !strings.Contains(incoming, "foo") {
		t.Errorf("Message was not read from the user, expected quit to be part of %s", incoming)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2020-2021 Tigera, Inc. All rights reserved.

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

package migrate_test

import (
	"context"
	"fmt"

	"github.com/projectcalico/calicoctl/v3/calicoctl/commands/datastore/migrate"

	bapi "github.com/projectcalico/libcalico-go/lib/backend/api"
	"github.com/projectcalico/libcalico-go/lib/backend/model"
	client "github.com/projectcalico/libcalico-go/lib/clientv3"
	"github.com/projectcalico/libcalico-go/lib/ipam"
	"github.com/projectcalico/libcalico-go/lib/net"

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

var (
	nodeName           = "etcdNodeName"
	newNodeName        = "k8sNodeName"
	blockAffinityField = fmt.Sprintf("host:%s", nodeName)
	ipipTunnelHandle   = "ipip-tunnel-addr-etcdNodeName"
)

var _ = Describe("IPAM migration handling", func() {
	var block1 *model.KVPair
	var affinity1 *model.KVPair
	var handle1 *model.KVPair

	// Reset the IPAM information before each test
	BeforeEach(func() {
		block1 = &model.KVPair{
			Key: model.BlockKey{
				CIDR: net.MustParseCIDR("192.168.201.0/26"),
			},
			Value: &model.AllocationBlock{
				CIDR:     net.MustParseCIDR("192.168.201.0/26"),
				Affinity: &blockAffinityField,
				Attributes: []model.AllocationAttribute{
					{
						AttrPrimary: &ipipTunnelHandle,
						AttrSecondary: map[string]string{
							"node": nodeName,
							"type": "ipipTunnelAddress",
						},
					},
				},
			},
		}

		affinity1 = &model.KVPair{
			Key: model.BlockAffinityKey{
				CIDR: net.MustParseCIDR("192.168.201.0/26"),
				Host: nodeName,
			},
			Value: &model.BlockAffinity{
				State:   model.StateConfirmed,
				Deleted: false,
			},
		}

		handle1 = &model.KVPair{
			Key: model.IPAMHandleKey{
				HandleID: ipipTunnelHandle,
			},
			Value: &model.IPAMHandle{
				Block: map[string]int{
					"192.168.201.0/26": 1,
				},
				Deleted: false,
			},
		}
	})

	It("Should replace the node names in the IPAM block, block affinity, and handle", func() {
		blocks := model.KVPairList{
			KVPairs: []*model.KVPair{block1},
		}
		affinities := model.KVPairList{
			KVPairs: []*model.KVPair{affinity1},
		}
		handles := model.KVPairList{
			KVPairs: []*model.KVPair{handle1},
		}

		bc := NewMockIPAMBackendClient(blocks, affinities, handles)
		client := NewMockIPAMClient(bc)
		migrateIPAM := migrate.NewMigrateIPAM(client)
		migrateIPAM.SetNodeMap(map[string]string{nodeName: newNodeName})
		err := migrateIPAM.PullFromDatastore()
		Expect(err).NotTo(HaveOccurred())

		// Check that the block attributes were changed correctly
		Expect(migrateIPAM.IPAMBlocks).To(HaveLen(1))
		Expect(*migrateIPAM.IPAMBlocks[0].Value.Affinity).To(Equal(fmt.Sprintf("host:%s", newNodeName)))
		Expect(migrateIPAM.IPAMBlocks[0].Value.Attributes).To(HaveLen(1))
		Expect(*migrateIPAM.IPAMBlocks[0].Value.Attributes[0].AttrPrimary).To(Equal(fmt.Sprintf("ipip-tunnel-addr-%s", newNodeName)))
		Expect(migrateIPAM.IPAMBlocks[0].Value.Attributes[0].AttrSecondary["node"]).To(Equal(newNodeName))

		// Check that the block affinity attributes were changed correctly
		newAffinityKey := model.BlockAffinityKey{
			CIDR: net.MustParseCIDR("192.168.201.0/26"),
			Host: newNodeName,
		}
		newAffinityKeyPath, err := model.KeyToDefaultPath(newAffinityKey)
		Expect(err).NotTo(HaveOccurred())
		Expect(migrateIPAM.BlockAffinities).To(HaveLen(1))
		Expect(migrateIPAM.BlockAffinities[0].Key).To(Equal(newAffinityKeyPath))

		// Check that the IPAM handle attributes were changed correctly
		newHandleKey := model.IPAMHandleKey{
			HandleID: fmt.Sprintf("ipip-tunnel-addr-%s", newNodeName),
		}
		newHandleKeyPath, err := model.KeyToDefaultPath(newHandleKey)
		Expect(err).NotTo(HaveOccurred())
		Expect(migrateIPAM.IPAMHandles).To(HaveLen(1))
		Expect(migrateIPAM.IPAMHandles[0].Key).To(Equal(newHandleKeyPath))
	})

	It("Should not replace the node names in the IPAM block, block affinity, and handle if the node names are the same", func() {
		blocks := model.KVPairList{
			KVPairs: []*model.KVPair{block1},
		}
		affinities := model.KVPairList{
			KVPairs: []*model.KVPair{affinity1},
		}
		handles := model.KVPairList{
			KVPairs: []*model.KVPair{handle1},
		}

		bc := NewMockIPAMBackendClient(blocks, affinities, handles)
		client := NewMockIPAMClient(bc)
		migrateIPAM := migrate.NewMigrateIPAM(client)
		migrateIPAM.SetNodeMap(map[string]string{nodeName: nodeName})
		err := migrateIPAM.PullFromDatastore()
		Expect(err).NotTo(HaveOccurred())

		// Check that the block attributes were not changed
		Expect(migrateIPAM.IPAMBlocks).To(HaveLen(1))
		Expect(*migrateIPAM.IPAMBlocks[0].Value.Affinity).To(Equal(fmt.Sprintf("host:%s", nodeName)))
		Expect(migrateIPAM.IPAMBlocks[0].Value.Attributes).To(HaveLen(1))
		Expect(*migrateIPAM.IPAMBlocks[0].Value.Attributes[0].AttrPrimary).To(Equal(fmt.Sprintf("ipip-tunnel-addr-%s", nodeName)))
		Expect(migrateIPAM.IPAMBlocks[0].Value.Attributes[0].AttrSecondary["node"]).To(Equal(nodeName))

		// Check that the block affinity attributes were not changed
		newAffinityKeyPath, err := model.KeyToDefaultPath(affinity1.Key)
		Expect(err).NotTo(HaveOccurred())
		Expect(migrateIPAM.BlockAffinities).To(HaveLen(1))
		Expect(migrateIPAM.BlockAffinities[0].Key).To(Equal(newAffinityKeyPath))

		// Check that the IPAM handle attributes were not changed
		newHandleKeyPath, err := model.KeyToDefaultPath(handle1.Key)
		Expect(err).NotTo(HaveOccurred())
		Expect(migrateIPAM.IPAMHandles).To(HaveLen(1))
		Expect(migrateIPAM.IPAMHandles[0].Key).To(Equal(newHandleKeyPath))
	})
})

// MockIPAMClient subs out the clientv3.Interface but only in a way where'
// the bapi.Client is available for IPAM migration tests.
type MockIPAMClient struct {
	backend bapi.Client
}

func NewMockIPAMClient(bc bapi.Client) client.Interface {
	return &MockIPAMClient{
		backend: bc,
	}
}

func (c *MockIPAMClient) Backend() bapi.Client {
	return c.backend
}

func (c *MockIPAMClient) Nodes() client.NodeInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) GlobalNetworkPolicies() client.GlobalNetworkPolicyInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) NetworkPolicies() client.NetworkPolicyInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) IPPools() client.IPPoolInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) IPReservations() client.IPReservationInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) Profiles() client.ProfileInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) GlobalNetworkSets() client.GlobalNetworkSetInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) NetworkSets() client.NetworkSetInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) HostEndpoints() client.HostEndpointInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) WorkloadEndpoints() client.WorkloadEndpointInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) BGPPeers() client.BGPPeerInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) IPAM() ipam.Interface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) BGPConfigurations() client.BGPConfigurationInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) FelixConfigurations() client.FelixConfigurationInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) ClusterInformation() client.ClusterInformationInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) KubeControllersConfiguration() client.KubeControllersConfigurationInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) EnsureInitialized(ctx context.Context, calicoVersion, clusterType string) error {
	// DO NOTHING
	return nil
}

// MockIPAMBackendClient stubs out bapi.Client but only implements List
// for the IPAM objects in order to test IPAM migration logic.
type MockIPAMBackendClient struct {
	blocks     model.KVPairList
	affinities model.KVPairList
	handles    model.KVPairList
}

func NewMockIPAMBackendClient(blocks model.KVPairList, affinities model.KVPairList, handles model.KVPairList) bapi.Client {
	return &MockIPAMBackendClient{
		blocks:     blocks,
		affinities: affinities,
		handles:    handles,
	}
}

func (bc *MockIPAMBackendClient) Create(ctx context.Context, object *model.KVPair) (*model.KVPair, error) {
	// DO NOTHING
	return object, nil
}

func (bc *MockIPAMBackendClient) Update(ctx context.Context, object *model.KVPair) (*model.KVPair, error) {
	// DO NOTHING
	return object, nil
}

func (bc *MockIPAMBackendClient) Apply(ctx context.Context, object *model.KVPair) (*model.KVPair, error) {
	// DO NOTHING
	return object, nil
}

func (bc *MockIPAMBackendClient) Delete(ctx context.Context, key model.Key, revision string) (*model.KVPair, error) {
	// DO NOTHING
	return nil, nil
}

func (bc *MockIPAMBackendClient) DeleteKVP(ctx context.Context, object *model.KVPair) (*model.KVPair, error) {
	// DO NOTHING
	return object, nil
}

func (bc *MockIPAMBackendClient) Get(ctx context.Context, key model.Key, revision string) (*model.KVPair, error) {
	// DO NOTHING
	return nil, nil
}

func (bc *MockIPAMBackendClient) List(ctx context.Context, list model.ListInterface, revision string) (*model.KVPairList, error) {
	// Since this is a mock client, we only return the values based on the type of the ListInterface
	switch list.(type) {
	case model.BlockListOptions:
		return &bc.blocks, nil
	case model.BlockAffinityListOptions:
		return &bc.affinities, nil
	case model.IPAMHandleListOptions:
		return &bc.handles, nil
	}
	return nil, nil
}

func (bc *MockIPAMBackendClient) Watch(ctx context.Context, list model.ListInterface, revision string) (bapi.WatchInterface, error) {
	// DO NOTHING
	return bapi.NewFake(), nil
}

func (bc *MockIPAMBackendClient) EnsureInitialized() error {
	// DO NOTHING
	return nil
}

func (bc *MockIPAMBackendClient) Clean() error {
	// DO NOTHING
	return nil
}
<commit_msg>Add CalicoNodeStatus() stub to MockIPAMClient<commit_after>// Copyright (c) 2020-2021 Tigera, Inc. All rights reserved.

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

package migrate_test

import (
	"context"
	"fmt"

	"github.com/projectcalico/calicoctl/v3/calicoctl/commands/datastore/migrate"

	bapi "github.com/projectcalico/libcalico-go/lib/backend/api"
	"github.com/projectcalico/libcalico-go/lib/backend/model"
	client "github.com/projectcalico/libcalico-go/lib/clientv3"
	"github.com/projectcalico/libcalico-go/lib/ipam"
	"github.com/projectcalico/libcalico-go/lib/net"

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

var (
	nodeName           = "etcdNodeName"
	newNodeName        = "k8sNodeName"
	blockAffinityField = fmt.Sprintf("host:%s", nodeName)
	ipipTunnelHandle   = "ipip-tunnel-addr-etcdNodeName"
)

var _ = Describe("IPAM migration handling", func() {
	var block1 *model.KVPair
	var affinity1 *model.KVPair
	var handle1 *model.KVPair

	// Reset the IPAM information before each test
	BeforeEach(func() {
		block1 = &model.KVPair{
			Key: model.BlockKey{
				CIDR: net.MustParseCIDR("192.168.201.0/26"),
			},
			Value: &model.AllocationBlock{
				CIDR:     net.MustParseCIDR("192.168.201.0/26"),
				Affinity: &blockAffinityField,
				Attributes: []model.AllocationAttribute{
					{
						AttrPrimary: &ipipTunnelHandle,
						AttrSecondary: map[string]string{
							"node": nodeName,
							"type": "ipipTunnelAddress",
						},
					},
				},
			},
		}

		affinity1 = &model.KVPair{
			Key: model.BlockAffinityKey{
				CIDR: net.MustParseCIDR("192.168.201.0/26"),
				Host: nodeName,
			},
			Value: &model.BlockAffinity{
				State:   model.StateConfirmed,
				Deleted: false,
			},
		}

		handle1 = &model.KVPair{
			Key: model.IPAMHandleKey{
				HandleID: ipipTunnelHandle,
			},
			Value: &model.IPAMHandle{
				Block: map[string]int{
					"192.168.201.0/26": 1,
				},
				Deleted: false,
			},
		}
	})

	It("Should replace the node names in the IPAM block, block affinity, and handle", func() {
		blocks := model.KVPairList{
			KVPairs: []*model.KVPair{block1},
		}
		affinities := model.KVPairList{
			KVPairs: []*model.KVPair{affinity1},
		}
		handles := model.KVPairList{
			KVPairs: []*model.KVPair{handle1},
		}

		bc := NewMockIPAMBackendClient(blocks, affinities, handles)
		client := NewMockIPAMClient(bc)
		migrateIPAM := migrate.NewMigrateIPAM(client)
		migrateIPAM.SetNodeMap(map[string]string{nodeName: newNodeName})
		err := migrateIPAM.PullFromDatastore()
		Expect(err).NotTo(HaveOccurred())

		// Check that the block attributes were changed correctly
		Expect(migrateIPAM.IPAMBlocks).To(HaveLen(1))
		Expect(*migrateIPAM.IPAMBlocks[0].Value.Affinity).To(Equal(fmt.Sprintf("host:%s", newNodeName)))
		Expect(migrateIPAM.IPAMBlocks[0].Value.Attributes).To(HaveLen(1))
		Expect(*migrateIPAM.IPAMBlocks[0].Value.Attributes[0].AttrPrimary).To(Equal(fmt.Sprintf("ipip-tunnel-addr-%s", newNodeName)))
		Expect(migrateIPAM.IPAMBlocks[0].Value.Attributes[0].AttrSecondary["node"]).To(Equal(newNodeName))

		// Check that the block affinity attributes were changed correctly
		newAffinityKey := model.BlockAffinityKey{
			CIDR: net.MustParseCIDR("192.168.201.0/26"),
			Host: newNodeName,
		}
		newAffinityKeyPath, err := model.KeyToDefaultPath(newAffinityKey)
		Expect(err).NotTo(HaveOccurred())
		Expect(migrateIPAM.BlockAffinities).To(HaveLen(1))
		Expect(migrateIPAM.BlockAffinities[0].Key).To(Equal(newAffinityKeyPath))

		// Check that the IPAM handle attributes were changed correctly
		newHandleKey := model.IPAMHandleKey{
			HandleID: fmt.Sprintf("ipip-tunnel-addr-%s", newNodeName),
		}
		newHandleKeyPath, err := model.KeyToDefaultPath(newHandleKey)
		Expect(err).NotTo(HaveOccurred())
		Expect(migrateIPAM.IPAMHandles).To(HaveLen(1))
		Expect(migrateIPAM.IPAMHandles[0].Key).To(Equal(newHandleKeyPath))
	})

	It("Should not replace the node names in the IPAM block, block affinity, and handle if the node names are the same", func() {
		blocks := model.KVPairList{
			KVPairs: []*model.KVPair{block1},
		}
		affinities := model.KVPairList{
			KVPairs: []*model.KVPair{affinity1},
		}
		handles := model.KVPairList{
			KVPairs: []*model.KVPair{handle1},
		}

		bc := NewMockIPAMBackendClient(blocks, affinities, handles)
		client := NewMockIPAMClient(bc)
		migrateIPAM := migrate.NewMigrateIPAM(client)
		migrateIPAM.SetNodeMap(map[string]string{nodeName: nodeName})
		err := migrateIPAM.PullFromDatastore()
		Expect(err).NotTo(HaveOccurred())

		// Check that the block attributes were not changed
		Expect(migrateIPAM.IPAMBlocks).To(HaveLen(1))
		Expect(*migrateIPAM.IPAMBlocks[0].Value.Affinity).To(Equal(fmt.Sprintf("host:%s", nodeName)))
		Expect(migrateIPAM.IPAMBlocks[0].Value.Attributes).To(HaveLen(1))
		Expect(*migrateIPAM.IPAMBlocks[0].Value.Attributes[0].AttrPrimary).To(Equal(fmt.Sprintf("ipip-tunnel-addr-%s", nodeName)))
		Expect(migrateIPAM.IPAMBlocks[0].Value.Attributes[0].AttrSecondary["node"]).To(Equal(nodeName))

		// Check that the block affinity attributes were not changed
		newAffinityKeyPath, err := model.KeyToDefaultPath(affinity1.Key)
		Expect(err).NotTo(HaveOccurred())
		Expect(migrateIPAM.BlockAffinities).To(HaveLen(1))
		Expect(migrateIPAM.BlockAffinities[0].Key).To(Equal(newAffinityKeyPath))

		// Check that the IPAM handle attributes were not changed
		newHandleKeyPath, err := model.KeyToDefaultPath(handle1.Key)
		Expect(err).NotTo(HaveOccurred())
		Expect(migrateIPAM.IPAMHandles).To(HaveLen(1))
		Expect(migrateIPAM.IPAMHandles[0].Key).To(Equal(newHandleKeyPath))
	})
})

// MockIPAMClient subs out the clientv3.Interface but only in a way where'
// the bapi.Client is available for IPAM migration tests.
type MockIPAMClient struct {
	backend bapi.Client
}

func NewMockIPAMClient(bc bapi.Client) client.Interface {
	return &MockIPAMClient{
		backend: bc,
	}
}

func (c *MockIPAMClient) Backend() bapi.Client {
	return c.backend
}

func (c *MockIPAMClient) Nodes() client.NodeInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) GlobalNetworkPolicies() client.GlobalNetworkPolicyInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) NetworkPolicies() client.NetworkPolicyInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) IPPools() client.IPPoolInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) IPReservations() client.IPReservationInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) Profiles() client.ProfileInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) GlobalNetworkSets() client.GlobalNetworkSetInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) NetworkSets() client.NetworkSetInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) HostEndpoints() client.HostEndpointInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) WorkloadEndpoints() client.WorkloadEndpointInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) BGPPeers() client.BGPPeerInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) IPAM() ipam.Interface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) BGPConfigurations() client.BGPConfigurationInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) FelixConfigurations() client.FelixConfigurationInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) ClusterInformation() client.ClusterInformationInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) KubeControllersConfiguration() client.KubeControllersConfigurationInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) CalicoNodeStatus() client.CalicoNodeStatusInterface {
	// DO NOTHING
	return nil
}

func (c *MockIPAMClient) EnsureInitialized(ctx context.Context, calicoVersion, clusterType string) error {
	// DO NOTHING
	return nil
}

// MockIPAMBackendClient stubs out bapi.Client but only implements List
// for the IPAM objects in order to test IPAM migration logic.
type MockIPAMBackendClient struct {
	blocks     model.KVPairList
	affinities model.KVPairList
	handles    model.KVPairList
}

func NewMockIPAMBackendClient(blocks model.KVPairList, affinities model.KVPairList, handles model.KVPairList) bapi.Client {
	return &MockIPAMBackendClient{
		blocks:     blocks,
		affinities: affinities,
		handles:    handles,
	}
}

func (bc *MockIPAMBackendClient) Create(ctx context.Context, object *model.KVPair) (*model.KVPair, error) {
	// DO NOTHING
	return object, nil
}

func (bc *MockIPAMBackendClient) Update(ctx context.Context, object *model.KVPair) (*model.KVPair, error) {
	// DO NOTHING
	return object, nil
}

func (bc *MockIPAMBackendClient) Apply(ctx context.Context, object *model.KVPair) (*model.KVPair, error) {
	// DO NOTHING
	return object, nil
}

func (bc *MockIPAMBackendClient) Delete(ctx context.Context, key model.Key, revision string) (*model.KVPair, error) {
	// DO NOTHING
	return nil, nil
}

func (bc *MockIPAMBackendClient) DeleteKVP(ctx context.Context, object *model.KVPair) (*model.KVPair, error) {
	// DO NOTHING
	return object, nil
}

func (bc *MockIPAMBackendClient) Get(ctx context.Context, key model.Key, revision string) (*model.KVPair, error) {
	// DO NOTHING
	return nil, nil
}

func (bc *MockIPAMBackendClient) List(ctx context.Context, list model.ListInterface, revision string) (*model.KVPairList, error) {
	// Since this is a mock client, we only return the values based on the type of the ListInterface
	switch list.(type) {
	case model.BlockListOptions:
		return &bc.blocks, nil
	case model.BlockAffinityListOptions:
		return &bc.affinities, nil
	case model.IPAMHandleListOptions:
		return &bc.handles, nil
	}
	return nil, nil
}

func (bc *MockIPAMBackendClient) Watch(ctx context.Context, list model.ListInterface, revision string) (bapi.WatchInterface, error) {
	// DO NOTHING
	return bapi.NewFake(), nil
}

func (bc *MockIPAMBackendClient) EnsureInitialized() error {
	// DO NOTHING
	return nil
}

func (bc *MockIPAMBackendClient) Clean() error {
	// DO NOTHING
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2014 The Serviced 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.

// +build unit

// Package agent implements a service that runs on a serviced node. It is
// responsible for ensuring that a particular node is running the correct services
// and reporting the state and health of those services back to the master
// serviced.

package facade

import (
	"github.com/control-center/serviced/domain/servicedefinition"

	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"testing"
)

func getTestingService() servicedefinition.ServiceDefinition {
	service := servicedefinition.ServiceDefinition{
		Name:        "testsvc",
		Description: "Top level service. This directory is part of a unit test.",
		LogFilters: map[string]string{
			"Pepe": "My Test Filter",
		},
		Services: []servicedefinition.ServiceDefinition{
			servicedefinition.ServiceDefinition{
				Name:    "s1",
				Command: "/usr/bin/python -m SimpleHTTPServer",
				ImageID: "ubuntu",
				ConfigFiles: map[string]servicedefinition.ConfigFile{
					"/etc/my.cnf": servicedefinition.ConfigFile{Filename: "/etc/my.cnf", Content: "\n# SAMPLE config file for mysql\n\n[mysqld]\n\ninnodb_buffer_pool_size = 16G\n\n"},
				},
				Endpoints: []servicedefinition.EndpointDefinition{
					servicedefinition.EndpointDefinition{
						Protocol:    "tcp",
						PortNumber:  8080,
						Application: "www",
						Purpose:     "export",
					},
					servicedefinition.EndpointDefinition{
						Protocol:    "tcp",
						PortNumber:  8081,
						Application: "websvc",
						Purpose:     "import",
					},
				},
				LogConfigs: []servicedefinition.LogConfig{
					servicedefinition.LogConfig{
						Path: "/tmp/foo",
						Type: "foo",
						Filters: []string{
							"Pepe",
						},
					},
				},
				LogFilters: map[string]string{
					"Pepe2": "My Second Filter",
				},
				Services: []servicedefinition.ServiceDefinition{
					servicedefinition.ServiceDefinition{
						Name:    "s1child",
						Command: "/usr/bin/python -m SimpleHTTPServer",
						ImageID: "ubuntu",
						LogConfigs: []servicedefinition.LogConfig{
							servicedefinition.LogConfig{
								Path: "/tmp/foo2",
								Type: "foo2",
								Filters: []string{
									"Pepe4",
								},
							},
						},
						LogFilters: map[string]string{
							"Pepe4": "My Fourth Filter",
						},
					},

				},
			},
			servicedefinition.ServiceDefinition{
				Name:    "s2",
				Command: "/usr/bin/python -m SimpleHTTPServer",
				ImageID: "ubuntu",
				Endpoints: []servicedefinition.EndpointDefinition{
					servicedefinition.EndpointDefinition{
						Protocol:    "tcp",
						PortNumber:  8080,
						Application: "websvc",
						Purpose:     "export",
					},
				},
				LogConfigs: []servicedefinition.LogConfig{
					servicedefinition.LogConfig{
						Path: "/tmp/foo",
						Type: "foo",
						Filters: []string{
							"Pepe3",
						},
					},
				},
				LogFilters: map[string]string{
					"Pepe3": "My Third Filter",
				},
				Services: []servicedefinition.ServiceDefinition{
					servicedefinition.ServiceDefinition{
						Name:    "s2child",
						Command: "/usr/bin/python -m SimpleHTTPServer",
						ImageID: "ubuntu",
						LogConfigs: []servicedefinition.LogConfig{
							servicedefinition.LogConfig{
								Path: "/tmp/foo2",
								Type: "foo2",
								Filters: []string{
									"Pepe4",
								},
							},
						},
						LogFilters: map[string]string{
							"Pepe4": "My Fourth Filter",
						},
					},
				},
			},
		},
	}

	return service
}

func getTestingServiceWithAuditEnabled() servicedefinition.ServiceDefinition {
	service := servicedefinition.ServiceDefinition{
		Name:        "testsvc",
		Description: "Top level service. This directory is part of a unit test.",
		LogFilters: map[string]string{
			"Pepe": "My Test Filter",
		},
		Services: []servicedefinition.ServiceDefinition{
			servicedefinition.ServiceDefinition{
				Name:    "s1",
				Command: "/usr/bin/python -m SimpleHTTPServer",
				ImageID: "ubuntu",
				ConfigFiles: map[string]servicedefinition.ConfigFile{
					"/etc/my.cnf": servicedefinition.ConfigFile{Filename: "/etc/my.cnf", Content: "\n# SAMPLE config file for mysql\n\n[mysqld]\n\ninnodb_buffer_pool_size = 16G\n\n"},
				},
				LogConfigs: []servicedefinition.LogConfig{
					servicedefinition.LogConfig{
						Path: "/tmp/foo",
						Type: "foo",
						Filters: []string{
							"Pepe",
						},
						IsAudit: true,
					},
				},
				LogFilters: map[string]string{
					"Pepe2": "My Second Filter",
				},
				Services: []servicedefinition.ServiceDefinition{
					servicedefinition.ServiceDefinition{
						Name:    "s1child",
						Command: "/usr/bin/python -m SimpleHTTPServer",
						ImageID: "ubuntu",
						LogConfigs: []servicedefinition.LogConfig{
							servicedefinition.LogConfig{
								Path: "/tmp/foo2",
								Type: "foo2",
								Filters: []string{
									"Pepe4",
								},
								IsAudit: true,
							},
						},
						LogFilters: map[string]string{
							"Pepe4": "My Fourth Filter",
						},
					},

				},
			},
			servicedefinition.ServiceDefinition{
				Name:    "s2",
				Command: "/usr/bin/python -m SimpleHTTPServer",
				ImageID: "ubuntu",
				LogConfigs: []servicedefinition.LogConfig{
					servicedefinition.LogConfig{
						Path: "/tmp/foo",
						Type: "foo",
						Filters: []string{
							"Pepe3",
						},
					},
				},
				LogFilters: map[string]string{
					"Pepe3": "My Third Filter",
				},
				Services: []servicedefinition.ServiceDefinition{
					servicedefinition.ServiceDefinition{
						Name:    "s2child",
						Command: "/usr/bin/python -m SimpleHTTPServer",
						ImageID: "ubuntu",
						LogConfigs: []servicedefinition.LogConfig{
							servicedefinition.LogConfig{
								Path: "/tmp/foo2",
								Type: "foo2",
								Filters: []string{
									"Pepe4",
								},
								IsAudit: true,
							},
						},
						LogFilters: map[string]string{
							"Pepe4": "My Fourth Filter",
						},
					},
				},
			},
		},
	}

	return service
}

func TestGettingFilterDefinitionsFromServiceDefinitions(t *testing.T) {
	services := make([]servicedefinition.ServiceDefinition, 1)
	services[0] = getTestingService()
	filterDefs := getFilterDefinitions(services)

	// make sure we find the specific filter definition we are looking for
	if filterDefs["Pepe"] != "My Test Filter" {
		t.Error("Was unable to extract the filter definition")
	}

	// make sure the number matches the number we define
	if len(filterDefs) != 4 {
		t.Error(fmt.Sprintf("Found %d instead of 4 filter definitions", len(filterDefs)))
	}
}

func TestConstructingFilterString(t *testing.T) {
	services := make([]servicedefinition.ServiceDefinition, 1)
	services[0] = getTestingService()
	filterDefs := getFilterDefinitions(services)
	typeFilter := []string{}
	filters := getFiltersFromTemplates(services, filterDefs, &typeFilter)
	testString := "My Test Filter"

	// make sure our test filter definition is in the constructed filters
	if !strings.Contains(filters, testString) {
		t.Error(fmt.Sprintf("Was unable to find %s in the filters", testString))
	}
}

func TestGetAuditLogSectionForNoservice(t *testing.T) {
	services := []servicedefinition.ServiceDefinition{}
	auditLogTypes := []string{}
	auditLogSection := getAuditLogSectionFromTemplates(services, &auditLogTypes)
	if len(auditLogSection) > 0 {
		t.Error(fmt.Sprintf("Audit Log Section should be empty but it is not %d", len(auditLogSection)))
	}
}

func TestGetAuditLogSectionForServicesNotEnabledAudit(t *testing.T) {
	services := make([]servicedefinition.ServiceDefinition, 1)
	services[0] = getTestingService()
	auditableTypes := []string{}
	auditLogSection := getAuditLogSectionFromTemplates(services, &auditableTypes)
	if len(auditLogSection) != 0 {
		t.Error(fmt.Sprintf("expected am empty auditLogSection , but found %d size : AuditLogSection = %s", len(auditLogSection), auditLogSection))
	}
}
func TestMultipleTypesForAuditLogging(t *testing.T){
	services := make([]servicedefinition.ServiceDefinition, 1)
	services[0] = getTestingServiceWithAuditEnabled()
	auditableTypes := []string{}
	auditLogSection := getAuditLogSectionFromTemplates(services, &auditableTypes)
	fieldTypeCount := strings.Count(auditLogSection, "if [fields][type]")
	if fieldTypeCount !=2 {
		t.Error(fmt.Sprintf("expected 2 for two different LogCoongfig Types, but found %d : AuditLogSection = %s", fieldTypeCount, auditLogSection))
	}
}

func TestNoDuplicateAuditTypes(t *testing.T) {
	services := make([]servicedefinition.ServiceDefinition, 1)
	services[0] = getTestingServiceWithAuditEnabled()
	auditableTypes := []string{}
	auditLogSection := getAuditLogSectionFromTemplates(services, &auditableTypes)
	auditTypeCount := strings.Count(auditLogSection, "if [fields][type] == \"foo2\"")
	if auditTypeCount !=1 {
		t.Error(fmt.Sprintf("expected only 1 section for 'foo2' type, but found %d: AuditLogSection = %s ", auditTypeCount, auditLogSection))
	}
}

func TestNoDuplicateFilters(t *testing.T) {
	services := make([]servicedefinition.ServiceDefinition, 1)
	services[0] = getTestingService()
	filterDefs := getFilterDefinitions(services)
	typeFilter := []string{}
	filters := getFiltersFromTemplates(services, filterDefs, &typeFilter)

	filterCount := strings.Count(filters, "if [file] == \"/tmp/foo2\"")
	if filterCount != 1 {
		t.Error(fmt.Sprintf("expected only 1 filter for 'foo2', but found %d: filters=%s", filterCount, filters))
	}
}

func TestWritingConfigFile(t *testing.T) {
	filters := "This is my test filter"
	auditLogSection := "Audit Log Section string"
	tmpfile, err := ioutil.TempFile("", "logstash_test.conf")
	t.Logf("Created tempfile: %s", tmpfile.Name())
	if err != nil {
		t.Logf("could not create tempfile: %s", err)
		t.FailNow()
	}
	defer tmpfile.Close()
	defer os.Remove(tmpfile.Name())
	_, err = tmpfile.Write([]byte("${FILTER_SECTION}"))
	_, err = tmpfile.Write([]byte("${AUDIT_SECTION"))
	if err != nil {
		t.Logf("%s", err)
		t.FailNow()
	}
	err = tmpfile.Sync()
	if err != nil {
		t.Logf("%s", err)
		t.FailNow()
	}

	if err = writeLogStashConfigFile(filters, auditLogSection, tmpfile.Name()); err != nil {
		t.Errorf("error calling writeLogStashConfigFile: %s", err)
		t.Fail()
	}

	// read the contents
	contents, err := ioutil.ReadFile(tmpfile.Name())
	if err != nil {
		t.Error(fmt.Sprintf("Unable to read output file %v", err))
	}

	// make sure our filter and auditLogSection string is in it
	if !strings.Contains(string(contents), filters) && !strings.Contains(string(contents), auditLogSection) {
		t.Logf("Read in contents: %s", string(contents))
		t.Log(filters)
		t.Error("Was unable to write the logstash conf file")

	}
}
<commit_msg>Fixed logstash tests to take into account escaping /<commit_after>// Copyright 2014 The Serviced 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.

// +build unit

// Package agent implements a service that runs on a serviced node. It is
// responsible for ensuring that a particular node is running the correct services
// and reporting the state and health of those services back to the master
// serviced.

package facade

import (
	"github.com/control-center/serviced/domain/servicedefinition"

	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"testing"
)

func getTestingService() servicedefinition.ServiceDefinition {
	service := servicedefinition.ServiceDefinition{
		Name:        "testsvc",
		Description: "Top level service. This directory is part of a unit test.",
		LogFilters: map[string]string{
			"Pepe": "My Test Filter",
		},
		Services: []servicedefinition.ServiceDefinition{
			servicedefinition.ServiceDefinition{
				Name:    "s1",
				Command: "/usr/bin/python -m SimpleHTTPServer",
				ImageID: "ubuntu",
				ConfigFiles: map[string]servicedefinition.ConfigFile{
					"/etc/my.cnf": servicedefinition.ConfigFile{Filename: "/etc/my.cnf", Content: "\n# SAMPLE config file for mysql\n\n[mysqld]\n\ninnodb_buffer_pool_size = 16G\n\n"},
				},
				Endpoints: []servicedefinition.EndpointDefinition{
					servicedefinition.EndpointDefinition{
						Protocol:    "tcp",
						PortNumber:  8080,
						Application: "www",
						Purpose:     "export",
					},
					servicedefinition.EndpointDefinition{
						Protocol:    "tcp",
						PortNumber:  8081,
						Application: "websvc",
						Purpose:     "import",
					},
				},
				LogConfigs: []servicedefinition.LogConfig{
					servicedefinition.LogConfig{
						Path: "/tmp/foo",
						Type: "foo",
						Filters: []string{
							"Pepe",
						},
					},
				},
				LogFilters: map[string]string{
					"Pepe2": "My Second Filter",
				},
				Services: []servicedefinition.ServiceDefinition{
					servicedefinition.ServiceDefinition{
						Name:    "s1child",
						Command: "/usr/bin/python -m SimpleHTTPServer",
						ImageID: "ubuntu",
						LogConfigs: []servicedefinition.LogConfig{
							servicedefinition.LogConfig{
								Path: "/tmp/foo2",
								Type: "foo2",
								Filters: []string{
									"Pepe4",
								},
							},
						},
						LogFilters: map[string]string{
							"Pepe4": "My Fourth Filter",
						},
					},

				},
			},
			servicedefinition.ServiceDefinition{
				Name:    "s2",
				Command: "/usr/bin/python -m SimpleHTTPServer",
				ImageID: "ubuntu",
				Endpoints: []servicedefinition.EndpointDefinition{
					servicedefinition.EndpointDefinition{
						Protocol:    "tcp",
						PortNumber:  8080,
						Application: "websvc",
						Purpose:     "export",
					},
				},
				LogConfigs: []servicedefinition.LogConfig{
					servicedefinition.LogConfig{
						Path: "/tmp/foo",
						Type: "foo",
						Filters: []string{
							"Pepe3",
						},
					},
				},
				LogFilters: map[string]string{
					"Pepe3": "My Third Filter",
				},
				Services: []servicedefinition.ServiceDefinition{
					servicedefinition.ServiceDefinition{
						Name:    "s2child",
						Command: "/usr/bin/python -m SimpleHTTPServer",
						ImageID: "ubuntu",
						LogConfigs: []servicedefinition.LogConfig{
							servicedefinition.LogConfig{
								Path: "/tmp/foo2",
								Type: "foo2",
								Filters: []string{
									"Pepe4",
								},
							},
						},
						LogFilters: map[string]string{
							"Pepe4": "My Fourth Filter",
						},
					},
				},
			},
		},
	}

	return service
}

func getTestingServiceWithAuditEnabled() servicedefinition.ServiceDefinition {
	service := servicedefinition.ServiceDefinition{
		Name:        "testsvc",
		Description: "Top level service. This directory is part of a unit test.",
		LogFilters: map[string]string{
			"Pepe": "My Test Filter",
		},
		Services: []servicedefinition.ServiceDefinition{
			servicedefinition.ServiceDefinition{
				Name:    "s1",
				Command: "/usr/bin/python -m SimpleHTTPServer",
				ImageID: "ubuntu",
				ConfigFiles: map[string]servicedefinition.ConfigFile{
					"/etc/my.cnf": servicedefinition.ConfigFile{Filename: "/etc/my.cnf", Content: "\n# SAMPLE config file for mysql\n\n[mysqld]\n\ninnodb_buffer_pool_size = 16G\n\n"},
				},
				LogConfigs: []servicedefinition.LogConfig{
					servicedefinition.LogConfig{
						Path: "/tmp/foo",
						Type: "foo",
						Filters: []string{
							"Pepe",
						},
						IsAudit: true,
					},
				},
				LogFilters: map[string]string{
					"Pepe2": "My Second Filter",
				},
				Services: []servicedefinition.ServiceDefinition{
					servicedefinition.ServiceDefinition{
						Name:    "s1child",
						Command: "/usr/bin/python -m SimpleHTTPServer",
						ImageID: "ubuntu",
						LogConfigs: []servicedefinition.LogConfig{
							servicedefinition.LogConfig{
								Path: "/tmp/foo2",
								Type: "foo2",
								Filters: []string{
									"Pepe4",
								},
								IsAudit: true,
							},
						},
						LogFilters: map[string]string{
							"Pepe4": "My Fourth Filter",
						},
					},

				},
			},
			servicedefinition.ServiceDefinition{
				Name:    "s2",
				Command: "/usr/bin/python -m SimpleHTTPServer",
				ImageID: "ubuntu",
				LogConfigs: []servicedefinition.LogConfig{
					servicedefinition.LogConfig{
						Path: "/tmp/foo",
						Type: "foo",
						Filters: []string{
							"Pepe3",
						},
					},
				},
				LogFilters: map[string]string{
					"Pepe3": "My Third Filter",
				},
				Services: []servicedefinition.ServiceDefinition{
					servicedefinition.ServiceDefinition{
						Name:    "s2child",
						Command: "/usr/bin/python -m SimpleHTTPServer",
						ImageID: "ubuntu",
						LogConfigs: []servicedefinition.LogConfig{
							servicedefinition.LogConfig{
								Path: "/tmp/foo2",
								Type: "foo2",
								Filters: []string{
									"Pepe4",
								},
								IsAudit: true,
							},
						},
						LogFilters: map[string]string{
							"Pepe4": "My Fourth Filter",
						},
					},
				},
			},
		},
	}

	return service
}

func TestGettingFilterDefinitionsFromServiceDefinitions(t *testing.T) {
	services := make([]servicedefinition.ServiceDefinition, 1)
	services[0] = getTestingService()
	filterDefs := getFilterDefinitions(services)

	// make sure we find the specific filter definition we are looking for
	if filterDefs["Pepe"] != "My Test Filter" {
		t.Error("Was unable to extract the filter definition")
	}

	// make sure the number matches the number we define
	if len(filterDefs) != 4 {
		t.Error(fmt.Sprintf("Found %d instead of 4 filter definitions", len(filterDefs)))
	}
}

func TestConstructingFilterString(t *testing.T) {
	services := make([]servicedefinition.ServiceDefinition, 1)
	services[0] = getTestingService()
	filterDefs := getFilterDefinitions(services)
	typeFilter := []string{}
	filters := getFiltersFromTemplates(services, filterDefs, &typeFilter)
	testString := "My Test Filter"

	// make sure our test filter definition is in the constructed filters
	if !strings.Contains(filters, testString) {
		t.Error(fmt.Sprintf("Was unable to find %s in the filters", testString))
	}
}

func TestGetAuditLogSectionForNoservice(t *testing.T) {
	services := []servicedefinition.ServiceDefinition{}
	auditLogTypes := []string{}
	auditLogSection := getAuditLogSectionFromTemplates(services, &auditLogTypes)
	if len(auditLogSection) > 0 {
		t.Error(fmt.Sprintf("Audit Log Section should be empty but it is not %d", len(auditLogSection)))
	}
}

func TestGetAuditLogSectionForServicesNotEnabledAudit(t *testing.T) {
	services := make([]servicedefinition.ServiceDefinition, 1)
	services[0] = getTestingService()
	auditableTypes := []string{}
	auditLogSection := getAuditLogSectionFromTemplates(services, &auditableTypes)
	if len(auditLogSection) != 0 {
		t.Error(fmt.Sprintf("expected am empty auditLogSection , but found %d size : AuditLogSection = %s", len(auditLogSection), auditLogSection))
	}
}
func TestMultipleTypesForAuditLogging(t *testing.T){
	services := make([]servicedefinition.ServiceDefinition, 1)
	services[0] = getTestingServiceWithAuditEnabled()
	auditableTypes := []string{}
	auditLogSection := getAuditLogSectionFromTemplates(services, &auditableTypes)
	fieldTypeCount := strings.Count(auditLogSection, "if [fields][type]")
	if fieldTypeCount !=2 {
		t.Error(fmt.Sprintf("expected 2 for two different LogCoongfig Types, but found %d : AuditLogSection = %s", fieldTypeCount, auditLogSection))
	}
}

func TestNoDuplicateAuditTypes(t *testing.T) {
	services := make([]servicedefinition.ServiceDefinition, 1)
	services[0] = getTestingServiceWithAuditEnabled()
	auditableTypes := []string{}
	auditLogSection := getAuditLogSectionFromTemplates(services, &auditableTypes)
	auditTypeCount := strings.Count(auditLogSection, "if [fields][type] == \"foo2\"")
	if auditTypeCount !=1 {
		t.Error(fmt.Sprintf("expected only 1 section for 'foo2' type, but found %d: AuditLogSection = %s ", auditTypeCount, auditLogSection))
	}
}

func TestNoDuplicateFilters(t *testing.T) {
	services := make([]servicedefinition.ServiceDefinition, 1)
	services[0] = getTestingService()
	filterDefs := getFilterDefinitions(services)
	typeFilter := []string{}
	filters := getFiltersFromTemplates(services, filterDefs, &typeFilter)

	filterCount := strings.Count(filters, "if [file] =~ \"\\/tmp\\/foo2\"")
	if filterCount != 1 {
		t.Error(fmt.Sprintf("expected only 1 filter for 'foo2', but found %d: filters=%s", filterCount, filters))
	}
}

func TestWritingConfigFile(t *testing.T) {
	filters := "This is my test filter"
	auditLogSection := "Audit Log Section string"
	tmpfile, err := ioutil.TempFile("", "logstash_test.conf")
	t.Logf("Created tempfile: %s", tmpfile.Name())
	if err != nil {
		t.Logf("could not create tempfile: %s", err)
		t.FailNow()
	}
	defer tmpfile.Close()
	defer os.Remove(tmpfile.Name())
	_, err = tmpfile.Write([]byte("${FILTER_SECTION}"))
	_, err = tmpfile.Write([]byte("${AUDIT_SECTION"))
	if err != nil {
		t.Logf("%s", err)
		t.FailNow()
	}
	err = tmpfile.Sync()
	if err != nil {
		t.Logf("%s", err)
		t.FailNow()
	}

	if err = writeLogStashConfigFile(filters, auditLogSection, tmpfile.Name()); err != nil {
		t.Errorf("error calling writeLogStashConfigFile: %s", err)
		t.Fail()
	}

	// read the contents
	contents, err := ioutil.ReadFile(tmpfile.Name())
	if err != nil {
		t.Error(fmt.Sprintf("Unable to read output file %v", err))
	}

	// make sure our filter and auditLogSection string is in it
	if !strings.Contains(string(contents), filters) && !strings.Contains(string(contents), auditLogSection) {
		t.Logf("Read in contents: %s", string(contents))
		t.Log(filters)
		t.Error("Was unable to write the logstash conf file")

	}
}
<|endoftext|>


<commit_before>package bodyparser

import (
    . "github.com/levythu/gurgling"
    . "github.com/levythu/gurgling/definition"
    "strings"
    "encoding/json"
    "io/ioutil"
    "fmt"
)

// Force to fetch data and store it in req.F["body"]

type BodyParser struct {
    // implement IMidware

    // if nil, no filter.
    MethodFilter map[string]bool
    MaxMemoryUse int64
}

func ABodyParser() IMidware {
    return &BodyParser {
        MethodFilter: map[string]bool {
            "POST": true,
            "PUT": true,
        },
        MaxMemoryUse: 1024*1024*4,   //4MB cache for multipart form.
    }
}

func parseContentType(raw string) string {
    // ACCORDING to rfc1341, the contentType should contain type in its head and optical parameters
    // divided by semicolons.
    var i=strings.Index(raw, ";")
    if i<0 {
        return raw
    }
    return raw[:i]
}

func (this *BodyParser)Handler(req Request, res Response) (isCont bool, nReq Request, nRes Response) {
    isCont=true
    nReq=req
    nRes=res

    if !(this.MethodFilter==nil || this.MethodFilter[req.Method()]) {
        return
    }

    var contentType=strings.ToLower(parseContentType(req.Get(CONTENT_TYPE_KEY)))
    fmt.Println(contentType)
    if contentType=="application/x-www-form-urlencoded" {
        // Parse it as key-value.
        // in the case the body is url.Values
        var err=req.R().ParseForm()
        if err==nil {
            req.F()["body"]=req.R().PostForm
        }
    } else if contentType=="multipart/form-data" {
        // Parse it as multipart form.
        // in the case the body is *multipart.Form
        var err=req.R().ParseMultipartForm(this.MaxMemoryUse)
        if err==nil {
            req.F()["body"]=req.R().MultipartForm
        }
    } else if contentType=="application/json" {
        // Parse it as JSON.
        // in the case the body is map[string]Tout
        var rawData, err=ioutil.ReadAll(req.R().Body)
        if err!=nil {
            return
        }
        var ret map[string]Tout
        err=json.Unmarshal(rawData, &ret)
        if err==nil {
            req.F()["body"]=ret
        }
    } else {
        // Fetch it but do not parse
        // in the case the body is []byte
        var rawData, err=ioutil.ReadAll(req.R().Body)
        if err==nil {
            req.F()["body"]=rawData
        }
    }
    return
}
<commit_msg>remove redundancy<commit_after>package bodyparser

import (
    . "github.com/levythu/gurgling"
    . "github.com/levythu/gurgling/definition"
    "strings"
    "encoding/json"
    "io/ioutil"
)

// Force to fetch data and store it in req.F["body"]

type BodyParser struct {
    // implement IMidware

    // if nil, no filter.
    MethodFilter map[string]bool
    MaxMemoryUse int64
}

func ABodyParser() IMidware {
    return &BodyParser {
        MethodFilter: map[string]bool {
            "POST": true,
            "PUT": true,
        },
        MaxMemoryUse: 1024*1024*4,   //4MB cache for multipart form.
    }
}

func parseContentType(raw string) string {
    // ACCORDING to rfc1341, the contentType should contain type in its head and optical parameters
    // divided by semicolons.
    var i=strings.Index(raw, ";")
    if i<0 {
        return raw
    }
    return raw[:i]
}

func (this *BodyParser)Handler(req Request, res Response) (isCont bool, nReq Request, nRes Response) {
    isCont=true
    nReq=req
    nRes=res

    if !(this.MethodFilter==nil || this.MethodFilter[req.Method()]) {
        return
    }

    var contentType=strings.ToLower(parseContentType(req.Get(CONTENT_TYPE_KEY)))
    if contentType=="application/x-www-form-urlencoded" {
        // Parse it as key-value.
        // in the case the body is url.Values
        var err=req.R().ParseForm()
        if err==nil {
            req.F()["body"]=req.R().PostForm
        }
    } else if contentType=="multipart/form-data" {
        // Parse it as multipart form.
        // in the case the body is *multipart.Form
        var err=req.R().ParseMultipartForm(this.MaxMemoryUse)
        if err==nil {
            req.F()["body"]=req.R().MultipartForm
        }
    } else if contentType=="application/json" {
        // Parse it as JSON.
        // in the case the body is map[string]Tout
        var rawData, err=ioutil.ReadAll(req.R().Body)
        if err!=nil {
            return
        }
        var ret map[string]Tout
        err=json.Unmarshal(rawData, &ret)
        if err==nil {
            req.F()["body"]=ret
        }
    } else {
        // Fetch it but do not parse
        // in the case the body is []byte
        var rawData, err=ioutil.ReadAll(req.R().Body)
        if err==nil {
            req.F()["body"]=rawData
        }
    }
    return
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/brucesho/dockerfillers/utils"
	"path"
)

func (cmdSet *CommandSet) CmdHelp(args ...string) error {
	if len(args) == 0 || len(args) > 1 {
		printUsage(cmdSet, false)
	} else {
		command, exists := cmdSet.commands[args[0]]
		if !exists {
			return errors.New(fmt.Sprintf("No help on %s - command does not exist\n", args[0]))
		} else {
			fmt.Printf("%s: %s\n", args[0], command.description)
		}
	}

	return nil
}

func (cmdSet *CommandSet) CmdDiffchanges(args ...string) error {
	if len(args) != 1 {
		fmt.Println("Usage: diffchanges [IMAGE]")
		return nil
	}

	imageIds, err := utils.GetImageIdsFromName(args[0])
	if err != nil {
		return err
	}

	if len(imageIds) == 0 {
		return fmt.Errorf("No matching image found: %s", args[0])
	}

	dockerInfo, err := utils.GetDockerInfo()
	if err != nil {
		return err
	}
	driverRootDir := dockerInfo.StorageDriver.RootDir

	switch dockerInfo.StorageDriver.Kind {
	case "aufs":
		for _, imageId := range imageIds {
			imageDiffDir := utils.AufsGetDiffDir(driverRootDir, imageId)
			parentDiffDirs, err := utils.AufsGetParentDiffDirs(driverRootDir, imageId)
			if err != nil {
				return err
			}

			changes, err := utils.AufsGetChanges(parentDiffDirs, imageDiffDir)
			if err != nil {
				return err
			}

			for _, change := range changes {
				fmt.Printf("%s\n", change.String())
			}
		}

	case "devicemapper":
		for _, imageId := range imageIds {

			parentImage, err := utils.GetImageParent(path.Dir(driverRootDir), imageId)
			if err != nil {
				return err
			}

			rootfsPath, containerId, err := utils.DeviceMapperGetRootFS(driverRootDir, imageId)
			if err != nil {
				return err
			}
			defer utils.DeviceMapperRemoveContainer(containerId)

			parentRootfsPath, parentContainerId, err := utils.DeviceMapperGetRootFS(driverRootDir, parentImage)
			if err != nil {
				return err
			}
			defer utils.DeviceMapperRemoveContainer(parentContainerId)

			changes, err := utils.ChangesDirs(rootfsPath, parentRootfsPath)
			if err != nil {
				return err
			}

			for _, change := range changes {
				fmt.Printf("%s\n", change.String())
			}

		}

	default:
		return fmt.Errorf("Error: storage driver %s is unsupported.\n", dockerInfo.StorageDriver.Kind)
	}

	return nil
}

func (cmdSet *CommandSet) CmdDiffsize(args ...string) error {
	if len(args) != 1 {
		fmt.Println("Usage: diffsize [IMAGE]")
		return nil
	}

	dockerInfo, err := utils.GetDockerInfo()
	if err != nil {
		return err
	}

	switch dockerInfo.StorageDriver.Kind {
	case "aufs":
		aufsRootDir := dockerInfo.StorageDriver.RootDir
		imageIds, err := utils.GetImageIdsFromName(args[0])
		if err != nil {
			return err
		}

		if len(imageIds) == 0 {
			return fmt.Errorf("No matching image found: %s", args[0])
		}

		for _, imageId := range imageIds {
			imageDiffDir := utils.AufsGetDiffDir(aufsRootDir, imageId)
			parentDiffDirs, err := utils.AufsGetParentDiffDirs(aufsRootDir, imageId)
			if err != nil {
				return err
			}

			changes, err := utils.AufsGetChanges(parentDiffDirs, imageDiffDir)
			if err != nil {
				return err
			}

			var totalSize int64 = 0
			for _, change := range changes {
				fmt.Printf("%s\n", change.String())
				totalSize += change.Size
			}
			fmt.Printf("%d\n", totalSize)
		}
	default:
		return fmt.Errorf("Error: storage driver %s is unsupported.\n", dockerInfo.StorageDriver.Kind)
	}

	return nil
}
<commit_msg>devicemapper support finished<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/brucesho/dockerfillers/utils"
	"path"
)

func (cmdSet *CommandSet) CmdHelp(args ...string) error {
	if len(args) == 0 || len(args) > 1 {
		printUsage(cmdSet, false)
	} else {
		command, exists := cmdSet.commands[args[0]]
		if !exists {
			return errors.New(fmt.Sprintf("No help on %s - command does not exist\n", args[0]))
		} else {
			fmt.Printf("%s: %s\n", args[0], command.description)
		}
	}

	return nil
}

func (cmdSet *CommandSet) CmdDiffchanges(args ...string) error {
	if len(args) != 1 {
		fmt.Println("Usage: diffchanges [IMAGE]")
		return nil
	}

	imageIds, err := utils.GetImageIdsFromName(args[0])
	if err != nil {
		return err
	}

	if len(imageIds) == 0 {
		return fmt.Errorf("No matching image found: %s", args[0])
	}

	dockerInfo, err := utils.GetDockerInfo()
	if err != nil {
		return err
	}
	driverRootDir := dockerInfo.StorageDriver.RootDir

	switch dockerInfo.StorageDriver.Kind {
	case "aufs":
		for _, imageId := range imageIds {
			imageDiffDir := utils.AufsGetDiffDir(driverRootDir, imageId)
			parentDiffDirs, err := utils.AufsGetParentDiffDirs(driverRootDir, imageId)
			if err != nil {
				return err
			}

			changes, err := utils.AufsGetChanges(parentDiffDirs, imageDiffDir)
			if err != nil {
				return err
			}

			for _, change := range changes {
				fmt.Printf("%s\n", change.String())
			}
		}

	case "devicemapper":
		for _, imageId := range imageIds {

			parentImage, err := utils.GetImageParent(path.Dir(driverRootDir), imageId)
			if err != nil {
				return err
			}

			rootfsPath, containerId, err := utils.DeviceMapperGetRootFS(driverRootDir, imageId)
			if err != nil {
				return err
			}
			defer utils.DeviceMapperRemoveContainer(containerId)

			parentRootfsPath, parentContainerId, err := utils.DeviceMapperGetRootFS(driverRootDir, parentImage)
			if err != nil {
				return err
			}
			defer utils.DeviceMapperRemoveContainer(parentContainerId)

			changes, err := utils.ChangesDirs(rootfsPath, parentRootfsPath)
			if err != nil {
				return err
			}

			for _, change := range changes {
				fmt.Printf("%s\n", change.String())
			}
		}

	default:
		return fmt.Errorf("Error: storage driver %s is unsupported.\n", dockerInfo.StorageDriver.Kind)
	}

	return nil
}

func (cmdSet *CommandSet) CmdDiffsize(args ...string) error {
	if len(args) != 1 {
		fmt.Println("Usage: diffsize [IMAGE]")
		return nil
	}

	imageIds, err := utils.GetImageIdsFromName(args[0])
	if err != nil {
		return err
	}

	if len(imageIds) == 0 {
		return fmt.Errorf("No matching image found: %s", args[0])
	}

	dockerInfo, err := utils.GetDockerInfo()
	if err != nil {
		return err
	}
	driverRootDir := dockerInfo.StorageDriver.RootDir

	switch dockerInfo.StorageDriver.Kind {
	case "aufs":
		for _, imageId := range imageIds {
			imageDiffDir := utils.AufsGetDiffDir(driverRootDir, imageId)
			parentDiffDirs, err := utils.AufsGetParentDiffDirs(driverRootDir, imageId)
			if err != nil {
				return err
			}

			changes, err := utils.AufsGetChanges(parentDiffDirs, imageDiffDir)
			if err != nil {
				return err
			}

			var totalSize int64 = 0
			for _, change := range changes {
				fmt.Printf("%s\n", change.String())
				totalSize += change.Size
			}
			fmt.Printf("%d\n", totalSize)
		}

	case "devicemapper":
		for _, imageId := range imageIds {

			parentImage, err := utils.GetImageParent(path.Dir(driverRootDir), imageId)
			if err != nil {
				return err
			}

			rootfsPath, containerId, err := utils.DeviceMapperGetRootFS(driverRootDir, imageId)
			if err != nil {
				return err
			}
			defer utils.DeviceMapperRemoveContainer(containerId)

			parentRootfsPath, parentContainerId, err := utils.DeviceMapperGetRootFS(driverRootDir, parentImage)
			if err != nil {
				return err
			}
			defer utils.DeviceMapperRemoveContainer(parentContainerId)

			changes, err := utils.ChangesDirs(rootfsPath, parentRootfsPath)
			if err != nil {
				return err
			}

			var totalSize int64 = 0
			for _, change := range changes {
				fmt.Printf("%s\n", change.String())
				totalSize += change.Size
			}
			fmt.Printf("%d\n", totalSize)
		}

	default:
		return fmt.Errorf("Error: storage driver %s is unsupported.\n", dockerInfo.StorageDriver.Kind)
	}

	return nil
}
<|endoftext|>