<commit_before>package main

import (
	"net/http"

	"github.com/julienschmidt/httprouter"
)

/* Read functions
 */
func ListRights(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
}

func ListUserRights(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
}

func ListUserRepoRights(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
}

/* GLOBAL RIGHTS
 */
func GrantGlobalRight(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`grant_global_right`, ``, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	crq := proto.NewGrantRequest()
	err := DecodeJsonBody(r, &crq)
	// check body is consistent with URI
	if err != nil || crq.Grant.RecipientType != params.ByName(`rtyp`) ||
		crq.Grant.RecipientId != params.ByName(`rid`) {
		DispatchBadRequest(&w, err)
		return
	}

	returnChannel := make(chan msg.Result)
	handler := handlerMap[`supervisor`].(supervisor)
	handler.input <- msg.Request{
		Type:       `supervisor`,
		Action:     `right`,
		Reply:      returnChannel,
		RemoteAddr: extractAddress(r.RemoteAddr),
		User:       params.ByName(`AuthenticatedUser`),
		Super: &msg.Supervisor{
			Action: `grant`,
		},
		Grant: proto.Grant{
			RecipientType: crq.Grant.RecipientType,
			RecipientId:   crq.Grant.RecipientId,
			PermissionId:  crq.Grant.PermissionId,
			Category:      crq.Grant.Category,
		},
	}
	result := <-returnChannel
	SendMsgResult(&w, &result)
}

func RevokeGlobalRight(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`revoke_global_right`, ``, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	returnChannel := make(chan msg.Result)
	handler := handlerMap[`supervisor`].(supervisor)
	handler.input <- msg.Request{
		Type:       `supervisor`,
		Action:     `right`,
		Reply:      returnChannel,
		RemoteAddr: extractAddress(r.RemoteAddr),
		User:       params.ByName(`AuthenticatedUser`),
		Super: &msg.Supervisor{
			Action:  `revoke`,
			GrantId: params.ByName(`grant`),
		},
	}
	result := <-returnChannel
	SendMsgResult(&w, &result)
}

/* LIMITED RIGHTS
 */
func GrantLimitedRight(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)

	scope := params.ByName(`scope`)
	obj := params.ByName(`uuid`)
	switch scope {
	case `repository`:
	default:
		// only implement repository for now
		DispatchNotImplemented(&w, nil)
		return
	}

	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`grant_limited_right`, obj, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	crq := proto.NewGrantRequest()
	err := DecodeJsonBody(r, &crq)
	// check body is consistent with URI
	if err != nil || crq.Grant.RecipientType != params.ByName(`rtyp`) ||
		crq.Grant.RecipientId != params.ByName(`rid`) {
		DispatchBadRequest(&w, err)
		return
	}

	returnChannel := make(chan msg.Result)
	handler := handlerMap[`supervisor`].(supervisor)
	handler.input <- msg.Request{
		Type:       `supervisor`,
		Action:     `right`,
		Reply:      returnChannel,
		RemoteAddr: extractAddress(r.RemoteAddr),
		User:       params.ByName(`AuthenticatedUser`),
		Super: &msg.Supervisor{
			Action: `grant`,
		},
		Grant: proto.Grant{
			RecipientType: crq.Grant.RecipientType,
			RecipientId:   crq.Grant.RecipientId,
			PermissionId:  crq.Grant.PermissionId,
			Category:      crq.Grant.Category,
			RepositoryId:  crq.Grant.RepositoryId,
			ObjectType:    crq.Grant.ObjectType,
			ObjectId:      crq.Grant.ObjectId,
		},
	}
	result := <-returnChannel
	SendMsgResult(&w, &result)
}

func RevokeLimitedRight(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)

	scope := params.ByName(`scope`)
	obj := params.ByName(`uuid`)
	switch scope {
	case `repository`:
	default:
		// only implement repository for now
		DispatchNotImplemented(&w, nil)
		return
	}

	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`revoke_limited_right`, obj, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	returnChannel := make(chan msg.Result)
	handler := handlerMap[`supervisor`].(supervisor)
	handler.input <- msg.Request{
		Type:       `supervisor`,
		Action:     `right`,
		Reply:      returnChannel,
		RemoteAddr: extractAddress(r.RemoteAddr),
		User:       params.ByName(`AuthenticatedUser`),
		Super: &msg.Supervisor{
			Action:  `revoke`,
			GrantId: params.ByName(`grant`),
		},
	}
	result := <-returnChannel
	SendMsgResult(&w, &result)
}

/* SYSTEM RIGHTS
 */
func GrantSystemRight(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`grant_system_right`, ``, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	crq := proto.NewGrantRequest()
	err := DecodeJsonBody(r, &crq)
	// check body is consistent with URI
	if err != nil || crq.Grant.RecipientType != params.ByName(`rtyp`) ||
		crq.Grant.RecipientId != params.ByName(`rid`) {
		DispatchBadRequest(&w, err)
		return
	}

	returnChannel := make(chan msg.Result)
	handler := handlerMap[`supervisor`].(supervisor)
	handler.input <- msg.Request{
		Type:       `supervisor`,
		Action:     `right`,
		Reply:      returnChannel,
		RemoteAddr: extractAddress(r.RemoteAddr),
		User:       params.ByName(`AuthenticatedUser`),
		Super: &msg.Supervisor{
			Action: `grant`,
		},
		Grant: proto.Grant{
			RecipientType: crq.Grant.RecipientType,
			RecipientId:   crq.Grant.RecipientId,
			PermissionId:  crq.Grant.PermissionId,
			Category:      crq.Grant.Category,
		},
	}
	result := <-returnChannel
	SendMsgResult(&w, &result)
}

func RevokeSystemRight(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`revoke_system_right`, ``, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	returnChannel := make(chan msg.Result)
	handler := handlerMap[`supervisor`].(supervisor)
	handler.input <- msg.Request{
		Type:       `supervisor`,
		Action:     `right`,
		Reply:      returnChannel,
		RemoteAddr: extractAddress(r.RemoteAddr),
		User:       params.ByName(`AuthenticatedUser`),
		Super: &msg.Supervisor{
			Action:  `revoke`,
			GrantId: params.ByName(`grant`),
		},
	}
	result := <-returnChannel
	SendMsgResult(&w, &result)
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>http_handler/grant: check category<commit_after>package main

import (
	"net/http"

	"github.com/julienschmidt/httprouter"
)

/* Read functions
 */
func ListRights(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
}

func ListUserRights(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
}

func ListUserRepoRights(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
}

/* GLOBAL RIGHTS
 */
func GrantGlobalRight(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`grant_global_right`, ``, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	crq := proto.NewGrantRequest()
	err := DecodeJsonBody(r, &crq)
	// check body is consistent with URI
	if err != nil || crq.Grant.RecipientType != params.ByName(`rtyp`) ||
		crq.Grant.RecipientId != params.ByName(`rid`) ||
		crq.Grant.Category != `global` {
		DispatchBadRequest(&w, err)
		return
	}

	returnChannel := make(chan msg.Result)
	handler := handlerMap[`supervisor`].(supervisor)
	handler.input <- msg.Request{
		Type:       `supervisor`,
		Action:     `right`,
		Reply:      returnChannel,
		RemoteAddr: extractAddress(r.RemoteAddr),
		User:       params.ByName(`AuthenticatedUser`),
		Super: &msg.Supervisor{
			Action: `grant`,
		},
		Grant: proto.Grant{
			RecipientType: crq.Grant.RecipientType,
			RecipientId:   crq.Grant.RecipientId,
			PermissionId:  crq.Grant.PermissionId,
			Category:      crq.Grant.Category,
		},
	}
	result := <-returnChannel
	SendMsgResult(&w, &result)
}

func RevokeGlobalRight(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`revoke_global_right`, ``, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	returnChannel := make(chan msg.Result)
	handler := handlerMap[`supervisor`].(supervisor)
	handler.input <- msg.Request{
		Type:       `supervisor`,
		Action:     `right`,
		Reply:      returnChannel,
		RemoteAddr: extractAddress(r.RemoteAddr),
		User:       params.ByName(`AuthenticatedUser`),
		Super: &msg.Supervisor{
			Action:  `revoke`,
			GrantId: params.ByName(`grant`),
		},
	}
	result := <-returnChannel
	SendMsgResult(&w, &result)
}

/* LIMITED RIGHTS
 */
func GrantLimitedRight(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)

	scope := params.ByName(`scope`)
	obj := params.ByName(`uuid`)
	switch scope {
	case `repository`:
	default:
		// only implement repository for now
		DispatchNotImplemented(&w, nil)
		return
	}

	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`grant_limited_right`, obj, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	crq := proto.NewGrantRequest()
	err := DecodeJsonBody(r, &crq)
	// check body is consistent with URI
	if err != nil || crq.Grant.RecipientType != params.ByName(`rtyp`) ||
		crq.Grant.RecipientId != params.ByName(`rid`) ||
		crq.Grant.Category != `limited` {
		DispatchBadRequest(&w, err)
		return
	}

	returnChannel := make(chan msg.Result)
	handler := handlerMap[`supervisor`].(supervisor)
	handler.input <- msg.Request{
		Type:       `supervisor`,
		Action:     `right`,
		Reply:      returnChannel,
		RemoteAddr: extractAddress(r.RemoteAddr),
		User:       params.ByName(`AuthenticatedUser`),
		Super: &msg.Supervisor{
			Action: `grant`,
		},
		Grant: proto.Grant{
			RecipientType: crq.Grant.RecipientType,
			RecipientId:   crq.Grant.RecipientId,
			PermissionId:  crq.Grant.PermissionId,
			Category:      crq.Grant.Category,
			RepositoryId:  crq.Grant.RepositoryId,
			ObjectType:    crq.Grant.ObjectType,
			ObjectId:      crq.Grant.ObjectId,
		},
	}
	result := <-returnChannel
	SendMsgResult(&w, &result)
}

func RevokeLimitedRight(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)

	scope := params.ByName(`scope`)
	obj := params.ByName(`uuid`)
	switch scope {
	case `repository`:
	default:
		// only implement repository for now
		DispatchNotImplemented(&w, nil)
		return
	}

	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`revoke_limited_right`, obj, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	returnChannel := make(chan msg.Result)
	handler := handlerMap[`supervisor`].(supervisor)
	handler.input <- msg.Request{
		Type:       `supervisor`,
		Action:     `right`,
		Reply:      returnChannel,
		RemoteAddr: extractAddress(r.RemoteAddr),
		User:       params.ByName(`AuthenticatedUser`),
		Super: &msg.Supervisor{
			Action:  `revoke`,
			GrantId: params.ByName(`grant`),
		},
	}
	result := <-returnChannel
	SendMsgResult(&w, &result)
}

/* SYSTEM RIGHTS
 */
func GrantSystemRight(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`grant_system_right`, ``, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	crq := proto.NewGrantRequest()
	err := DecodeJsonBody(r, &crq)
	// check body is consistent with URI
	if err != nil || crq.Grant.RecipientType != params.ByName(`rtyp`) ||
		crq.Grant.RecipientId != params.ByName(`rid`) ||
		crq.Grant.Category != `system` {
		DispatchBadRequest(&w, err)
		return
	}

	returnChannel := make(chan msg.Result)
	handler := handlerMap[`supervisor`].(supervisor)
	handler.input <- msg.Request{
		Type:       `supervisor`,
		Action:     `right`,
		Reply:      returnChannel,
		RemoteAddr: extractAddress(r.RemoteAddr),
		User:       params.ByName(`AuthenticatedUser`),
		Super: &msg.Supervisor{
			Action: `grant`,
		},
		Grant: proto.Grant{
			RecipientType: crq.Grant.RecipientType,
			RecipientId:   crq.Grant.RecipientId,
			PermissionId:  crq.Grant.PermissionId,
			Category:      crq.Grant.Category,
		},
	}
	result := <-returnChannel
	SendMsgResult(&w, &result)
}

func RevokeSystemRight(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`revoke_system_right`, ``, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	returnChannel := make(chan msg.Result)
	handler := handlerMap[`supervisor`].(supervisor)
	handler.input <- msg.Request{
		Type:       `supervisor`,
		Action:     `right`,
		Reply:      returnChannel,
		RemoteAddr: extractAddress(r.RemoteAddr),
		User:       params.ByName(`AuthenticatedUser`),
		Super: &msg.Supervisor{
			Action:  `revoke`,
			GrantId: params.ByName(`grant`),
		},
	}
	result := <-returnChannel
	SendMsgResult(&w, &result)
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"io"
)

// errNonZeroByte will be returned when something non-zero was read
var errNonZeroByte = errors.New("non-zero byte read")

// ZeroReader reads from R until a non-zero byte is read
type ZeroReader struct {
	R io.Reader
}

// Read reads up to len(p) bytes. It returnes how many leading zeros was
// read. If a non-zero byte occures, errNonZeroByte is returned.
func (zr ZeroReader) Read(p []byte) (zeros int, err error) {
	for len(p) > 0 && err == nil {
		var n int
		n, err = zr.R.Read(p)
		for i := range p[:n] {
			if p[i] != 0 {
				zeros += i
				err = errNonZeroByte
				return
			}
		}
		p = p[n:]
		zeros += n
	}
	return
}

// ReadZeros will read from r until incoming bytes are zero.
// If non-zero byte occures errNonZeroByte will be returned.
// It returnes number of zeros read from the source and optional error;
// io.EOF is never returned, so if err is nil, it means source doesn't contain
// any non-zero bytes.
func ReadZeros(r io.Reader) (zeros int, err error) {
	buf := make([]byte, 512*1024) // read buffer 512kb
	// Create zero reader, ensure first read is small as most sources will have
	// non-zero byte somwhere at the beginning
	r = io.MultiReader(io.LimitReader(ZeroReader{r}, 512), ZeroReader{r})
	for err == nil {
		var n int
		n, err = r.Read(buf)
		zeros += n
	}
	if err == io.EOF {
		err = nil
	}
	return
}
<commit_msg>Fix typo<commit_after>package main

import (
	"errors"
	"io"
)

// errNonZeroByte will be returned when something non-zero was read
var errNonZeroByte = errors.New("non-zero byte read")

// ZeroReader reads from R until a non-zero byte is read
type ZeroReader struct {
	R io.Reader
}

// Read reads up to len(p) bytes. It returns how many leading zeros was
// read. If a non-zero byte occures, errNonZeroByte is returned.
func (zr ZeroReader) Read(p []byte) (zeros int, err error) {
	for len(p) > 0 && err == nil {
		var n int
		n, err = zr.R.Read(p)
		for i := range p[:n] {
			if p[i] != 0 {
				zeros += i
				err = errNonZeroByte
				return
			}
		}
		p = p[n:]
		zeros += n
	}
	return
}

// ReadZeros will read from r until incoming bytes are zero.
// If non-zero byte occures errNonZeroByte will be returned.
// It returns number of zeros read from the source and optional error;
// io.EOF is never returned, so if err is nil, it means source doesn't contain
// any non-zero bytes.
func ReadZeros(r io.Reader) (zeros int, err error) {
	buf := make([]byte, 512*1024) // read buffer 512kb
	// Create zero reader, ensure first read is small as most sources will have
	// non-zero byte somwhere at the beginning
	r = io.MultiReader(io.LimitReader(ZeroReader{r}, 512), ZeroReader{r})
	for err == nil {
		var n int
		n, err = r.Read(buf)
		zeros += n
	}
	if err == io.EOF {
		err = nil
	}
	return
}
<|endoftext|>


<commit_before>package chef

import (
	"encoding/json"
	"io"
)

// Reader is a map string interface of arbitrary json
type Reader map[string]interface{}

// Read uses json.Marshal internally to provide a []byte interface to our raw json data
func (b *Reader) Read(p []byte) (size int, err error) {
	if buf, err := json.Marshal(&b); err == nil {
		copy(p, buf)
		return len(p), io.EOF
	}
	return len(p), nil
}
<commit_msg>Reader: Factor unreachable code. (#4)<commit_after>package chef

import (
	"encoding/json"
	"io"
)

// Reader is a map string interface of arbitrary json
type Reader map[string]interface{}

// Read uses json.Marshal internally to provide a []byte interface to our raw json data
func (b *Reader) Read(p []byte) (size int, err error) {
	if buf, err := json.Marshal(&b); err == nil {
		copy(p, buf)
	}
	return len(p), io.EOF
}
<|endoftext|>


<commit_before>package checkstyle

import (
	"bytes"
	"encoding/json"
	"go/ast"
	"go/format"
	"go/parser"
	"go/token"
	"strconv"
	"strings"
)

type ProblemType string

const (
	FileLine     ProblemType = "file_line"
	FunctionLine ProblemType = "func_line"
	Formated     ProblemType = "formated"
)

type Problem struct {
	Position    *token.Position
	Description string
	SourceLine  string
	Type        ProblemType
}

type Checker interface {
	Check(fileName string, src []byte) ([]Problem, error)
	IsFatal(p *Problem) bool
}

type checker struct {
	FunctionComment bool     `json:"func_comment"`
	FileLine        int      `json:"file_line"`
	FunctionLine    int      `json:"func_line"`
	MaxIndent       int      `json:"max_indent"`
	Formated        bool     `json:"formated"`
	Fatal           []string `json:"fatal"`
}

func New(config []byte) (Checker, error) {
	var _checker checker
	err := json.Unmarshal(config, &_checker)
	if err != nil {
		return nil, err
	}
	return &_checker, nil
}

func (c *checker) Check(fileName string, src []byte) (ps []Problem, err error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, fileName, src, parser.ParseComments)
	if err != nil {
		return nil, err
	}
	return (&file{fileName, src, c, f, fset, []Problem{}}).check(), nil
}

func (c *checker) IsFatal(p *Problem) bool {
	for _, v := range c.Fatal {
		if v == string(p.Type) {
			return true
		}
	}
	return false
}

type file struct {
	fileName string
	src      []byte

	config *checker

	ast  *ast.File
	fset *token.FileSet

	problems []Problem
}

func (f *file) isTest() bool {
	return strings.HasSuffix(f.fileName, "_test.go")
}

func (f *file) check() (ps []Problem) {
	f.checkFormat()
	f.checkFileLine()
	f.checkFunctionLine()
	return f.problems
}

func (f *file) checkFormat() {
	if !f.config.Formated {
		return
	}
	src, err := format.Source(f.src)
	if err != nil {
		panic(f.fileName + err.Error())
	}
	if bytes.Compare(src, f.src) != 0 {
		desc := "source is not formated"
		pos := f.fset.Position(f.ast.Pos())
		problem := Problem{Description: desc, Position: &pos, Type: Formated}
		f.problems = append(f.problems, problem)
	}
}

func (f *file) checkFileLine() {
	if f.isTest() {
		return
	}

	lineLimit := f.config.FileLine
	if lineLimit == 0 {
		return
	}

	f.fset.Iterate(func(_file *token.File) bool {
		lineCount := _file.LineCount()
		if lineCount > lineLimit {
			desc := strconv.Itoa(lineCount) + " lines more than " + strconv.Itoa(lineLimit)
			pos := f.fset.Position(f.ast.End())
			problem := Problem{Description: desc, Position: &pos, Type: FileLine}
			f.problems = append(f.problems, problem)
			return false
		}
		return true
	})
}

func (f *file) checkFunctionLine() {
	if f.isTest() {
		return
	}

	lineLimit := f.config.FunctionLine

	if lineLimit == 0 {
		return
	}
	for _, v := range f.ast.Decls {
		switch v := v.(type) {
		case *ast.FuncDecl:
			start := f.fset.Position(v.Pos())
			startLine := start.Line
			endLine := f.fset.Position(v.End()).Line
			lineCount := endLine - startLine
			if lineCount > lineLimit {
				desc := "func " + v.Name.Name + "() " + strconv.Itoa(lineCount) + " lines more than " + strconv.Itoa(lineLimit)
				problem := Problem{Description: desc, Position: &start, Type: FunctionLine}
				f.problems = append(f.problems, problem)
			}
		}
	}
}
<commit_msg>fix problem array address reuse bug<commit_after>package checkstyle

import (
	"bytes"
	"encoding/json"
	"go/ast"
	"go/format"
	"go/parser"
	"go/token"
	"strconv"
	"strings"
)

type ProblemType string

const (
	FileLine     ProblemType = "file_line"
	FunctionLine ProblemType = "func_line"
	Formated     ProblemType = "formated"
)

type Problem struct {
	Position    *token.Position
	Description string
	SourceLine  string
	Type        ProblemType
}

type Checker interface {
	Check(fileName string, src []byte) ([]Problem, error)
	IsFatal(p *Problem) bool
}

type checker struct {
	FunctionComment bool     `json:"func_comment"`
	FileLine        int      `json:"file_line"`
	FunctionLine    int      `json:"func_line"`
	MaxIndent       int      `json:"max_indent"`
	Formated        bool     `json:"formated"`
	Fatal           []string `json:"fatal"`
}

func New(config []byte) (Checker, error) {
	var _checker checker
	err := json.Unmarshal(config, &_checker)
	if err != nil {
		return nil, err
	}
	return &_checker, nil
}

func (c *checker) Check(fileName string, src []byte) (ps []Problem, err error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, fileName, src, parser.ParseComments)
	if err != nil {
		return nil, err
	}
	return (&file{fileName, src, c, f, fset, []Problem{}}).check(), nil
}

func (c *checker) IsFatal(p *Problem) bool {
	for _, v := range c.Fatal {
		if v == string(p.Type) {
			return true
		}
	}
	return false
}

type file struct {
	fileName string
	src      []byte

	config *checker

	ast  *ast.File
	fset *token.FileSet

	problems []Problem
}

func (f *file) isTest() bool {
	return strings.HasSuffix(f.fileName, "_test.go")
}

func (f *file) check() (ps []Problem) {
	f.checkFormat()
	f.checkFileLine()
	f.checkFunctionLine()
	return f.problems
}

func (f *file) checkFormat() {
	if !f.config.Formated {
		return
	}
	src, err := format.Source(f.src)
	if err != nil {
		panic(f.fileName + err.Error())
	}
	if bytes.Compare(src, f.src) != 0 {
		desc := "source is not formated"
		pos := f.fset.Position(f.ast.Pos())
		problem := Problem{Description: desc, Position: &pos, Type: Formated}
		f.problems = append(f.problems, problem)
	}
}

func (f *file) checkFileLine() {
	if f.isTest() {
		return
	}

	lineLimit := f.config.FileLine
	if lineLimit == 0 {
		return
	}

	f.fset.Iterate(func(_file *token.File) bool {
		lineCount := _file.LineCount()
		if lineCount > lineLimit {
			desc := strconv.Itoa(lineCount) + " lines more than " + strconv.Itoa(lineLimit)
			pos := f.fset.Position(f.ast.End())
			problem := Problem{Description: desc, Position: &pos, Type: FileLine}
			f.problems = append(f.problems, problem)
			return false
		}
		return true
	})
}

func genFuncLineProblem(name string, lineCount, lineLimit int, start token.Position) Problem {
	desc := "func " + name + "() " + strconv.Itoa(lineCount) +
		" lines more than " + strconv.Itoa(lineLimit)
	return Problem{Description: desc, Position: &start, Type: FunctionLine}
}

func (f *file) checkFunctionLine() {
	if f.isTest() {
		return
	}

	lineLimit := f.config.FunctionLine

	if lineLimit == 0 {
		return
	}
	for _, v := range f.ast.Decls {
		switch v := v.(type) {
		case *ast.FuncDecl:
			start := f.fset.Position(v.Pos())
			startLine := start.Line
			endLine := f.fset.Position(v.End()).Line
			lineCount := endLine - startLine
			if lineCount > lineLimit {
				problem := genFuncLineProblem(v.Name.Name, lineCount, lineLimit, start)
				f.problems = append(f.problems, problem)
			}
		}
	}
}
<|endoftext|>


<commit_before>// Implement test cases for the "chloe" application
package main

import (
    "testing"
    "strings"

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

// Test application usage string printing
func TestChloeUsage(test *testing.T) {

}

// Test Helper functions
func TestContainsString(test *testing.T) {
    sampleStrings  := []string{"a", "b", "c"}
    assert.Equal(test, false, containsString(sampleStrings, "d"))
    assert.Equal(test, false, containsString(sampleStrings, "aa"))
    assert.Equal(test, false, containsString(sampleStrings, "abc"))

    assert.Equal(test, true,  containsString(sampleStrings, "a"))
    assert.Equal(test, true,  containsString(sampleStrings, "b"))
    assert.Equal(test, true,  containsString(sampleStrings, "c"))
}

func TestGetAllOptions(test *testing.T) {
    commands, options := getAllOptions()

    commandLines := strings.Split(commands, "\n")
    assert.Equal(test, 2, len(commandLines) - 1, "only two commands are supported")

    optionLines := strings.Split(options, "\n")
    assert.Equal(test, 4, len(optionLines) - 1, "only four options are supported")
}

func TestIsValidCommand(test *testing.T) {
    for _, item := range ValidCommands {
        assert.Equal(test, true, isValidCommand(item.name), "valid commands should be valid")
    }
    assert.Equal(test, false, isValidCommand("invalid_command"), "invalid commands should be rejected")
}
<commit_msg>Moar tests<commit_after>// Implement test cases for the "chloe" application
package main

import (
    "os"
    "fmt"
    "testing"
    "strings"

    "path/filepath"
    "io/ioutil"

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

const (
    TEST_DIR = "tmp_test_dir"
)

// Helper function to setup a test fixture dir and write to
// it a file with the name "fname" and content "content"
func writeFileToTestDir(fname, content string) {
    testDirPath := "." + string(filepath.Separator) + TEST_DIR
    testFilePath := testDirPath + string(filepath.Separator) + fname

    _ = os.MkdirAll(testDirPath, 0755)
    _ = ioutil.WriteFile(testFilePath, []byte(content), os.ModePerm)
}

func cleanupTestDir() {
    _ = os.RemoveAll(fmt.Sprintf(".%s%s", string(filepath.Separator), TEST_DIR))
}

// Test Helper functions
func TestContainsString(test *testing.T) {
    sampleStrings  := []string{"a", "b", "c"}
    assert.Equal(test, false, containsString(sampleStrings, "d"))
    assert.Equal(test, false, containsString(sampleStrings, "aa"))
    assert.Equal(test, false, containsString(sampleStrings, "abc"))

    assert.Equal(test, true,  containsString(sampleStrings, "a"))
    assert.Equal(test, true,  containsString(sampleStrings, "b"))
    assert.Equal(test, true,  containsString(sampleStrings, "c"))
}

func TestGetAllOptions(test *testing.T) {
    commands, options := getAllOptions()

    commandLines := strings.Split(commands, "\n")
    assert.Equal(test, 2, len(commandLines) - 1, "only two commands are supported")

    optionLines := strings.Split(options, "\n")
    assert.Equal(test, 4, len(optionLines) - 1, "only four options are supported")
}

func TestIsValidCommand(test *testing.T) {
    for _, item := range ValidCommands {
        assert.Equal(test, true, isValidCommand(item.name), "valid commands should be valid")
    }
    assert.Equal(test, false, isValidCommand("invalid_command"), "invalid commands should be rejected")
}

func TestGetAppUsage(test *testing.T) {
    usageStr := getAppUsageString()
    assert.Contains(test, usageStr, "<command> [<options>]", "usage must contain sample usage str")
}

func TestGetAppVersion(test *testing.T) {
    version := getAppVersionString()
    assert.Contains(test, version, Version, "version must match internal global var")
}

func TestGetIgnoreObjectFromFile(test *testing.T) {
    writeFileToTestDir("test.json", `
{
    "chloe": [
        "node_modules",
        "**/*.out"
    ]
}
`)
    defer cleanupTestDir()

    object, err := getIgnoreObjectFromJSONFile("tmp_test_dir/test.json")
    assert.Nil(test, err, "err should be nil")

    assert.Equal(test, false, object.MatchesPath("foo"), "foo should not match")

    assert.Equal(test, true,  object.MatchesPath("foobar/blah.out"),  "foobar/blah.out should match")
    assert.Equal(test, true,  object.MatchesPath("node_modules/foo"), "node_modules/foo should match")
}
<|endoftext|>


<commit_before>package logdb

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"testing"
	"testing/quick"

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

func TestChunkDataFileSyntax(t *testing.T) {
	quickcheck(t, func(is [2]uint) bool {
		chunkFileName := fmt.Sprintf("%s%s%v%s%v", chunkPrefix, sep, is[0], sep, is[1])
		assert.True(t, isBasenameChunkDataFile(chunkFileName), chunkFileName)
		return true
	})
}

func TestChunkDataFileSyntaxLeadingZero(t *testing.T) {
	quickcheck(t, func(is [2]uint) bool {
		chunkFileName := fmt.Sprintf("%s%s0%v%s%v", chunkPrefix, sep, is[0], sep, is[1])
		assert.False(t, isBasenameChunkDataFile(chunkFileName), chunkFileName)
		return true
	})
}

func TestChunkDataFileSyntaxNoID(t *testing.T) {
	quickcheck(t, func(is [2]uint) bool {
		chunkFileName := fmt.Sprintf("%s%s%s%v", chunkPrefix, sep, sep, is[1])
		assert.False(t, isBasenameChunkDataFile(chunkFileName), chunkFileName)
		return true
	})
}

func TestChunkDataFileSyntaxNoOldest(t *testing.T) {
	quickcheck(t, func(is [2]uint) bool {
		chunkFileName := fmt.Sprintf("%s%s%v%s", chunkPrefix, sep, is[0], sep)
		assert.False(t, isBasenameChunkDataFile(chunkFileName), chunkFileName)
		return true
	})
}

func TestChunkDataFileNext(t *testing.T) {
	quickcheck(t, func(is [3]uint) bool {
		c := &chunk{path: fmt.Sprintf("%s%s%v%s%v", chunkPrefix, sep, is[0], sep, is[1])}
		nextFileName := fmt.Sprintf("%s%s%v%s%v", chunkPrefix, sep, is[0]+1, sep, is[2])
		assert.Equal(t, nextFileName, c.nextDataFileName(uint64(is[2])), "next data file name")
		return true
	})
}

func TestChunkMetaFilePath(t *testing.T) {
	quickcheck(t, func(is [2]uint) bool {
		c := &chunk{path: fmt.Sprintf("%s%s%v%s%v", chunkPrefix, sep, is[0], sep, is[1])}
		assert.Equal(t, metaFilePath(c.path), c.metaFilePath(), "meta file path")
		return true
	})
}

func TestMetadata(t *testing.T) {
	metadata := makeMetadata(t, []int32{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5})
	ends, err := readMetadata(metadata)
	assert.Nil(t, err, "failed to read metadata: %s", err)
	assert.Equal(t, []int32{0, 1, 2, 3, 4, 5}, ends, "ends")
}

func TestMetadataNonContiguousIndices(t *testing.T) {
	metadata := makeMetadata(t, []int32{0, 0, 1, 1, 5, 2})
	ends, err := readMetadata(metadata)
	assert.NotNil(t, err, "expected to not parse that, got: %v", ends)
}

func TestMetadataNonIncreasingEnds(t *testing.T) {
	metadata := makeMetadata(t, []int32{0, 0, 1, 1, 2, 0})
	ends, err := readMetadata(metadata)
	assert.NotNil(t, err, "expected to not parse that, got: %v", ends)
}

func TestMetadataRollback(t *testing.T) {
	metadata := makeMetadata(t, []int32{0, 0, 1, 1, 0, 1})
	ends, err := readMetadata(metadata)
	assert.Nil(t, err, "failed to read metadata: %s", err)
	assert.Equal(t, []int32{1}, ends, "failed to apply rollback, got: %v", ends)
}

func TestMetadataIncomplete(t *testing.T) {
	metadata := makeMetadata(t, []int32{0, 0, 1})
	ends, err := readMetadata(metadata)
	assert.NotNil(t, err, "expected to not parse that, got: %v", ends)
}

func TestMetadataIncompleteRollback(t *testing.T) {
	metadata := makeMetadata(t, []int32{0, 0, 1, 1, 0})
	ends, err := readMetadata(metadata)
	assert.NotNil(t, err, "expected to not parse that, got: %v", ends)
}

/// HELPERS

func quickcheck(t *testing.T, f interface{}) {
	if err := quick.Check(f, nil); err != nil {
		t.Fatal(err)
	}
}

func makeMetadata(t testing.TB, vals []int32) io.Reader {
	buf := new(bytes.Buffer)
	if err := binary.Write(buf, binary.LittleEndian, vals); err != nil {
		t.Fatal(err)
	}
	return buf
}
<commit_msg>A few more chunk tests.<commit_after>package logdb

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"testing"
	"testing/quick"

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

func TestChunkDataFileSyntax(t *testing.T) {
	quickcheck(t, func(is [2]uint) bool {
		chunkFileName := fmt.Sprintf("%s%s%v%s%v", chunkPrefix, sep, is[0], sep, is[1])
		assert.True(t, isBasenameChunkDataFile(chunkFileName), chunkFileName)
		return true
	})
}

func TestChunkDataFileSyntaxLeadingZero(t *testing.T) {
	quickcheck(t, func(is [2]uint) bool {
		chunkFileName := fmt.Sprintf("%s%s0%v%s%v", chunkPrefix, sep, is[0], sep, is[1])
		assert.False(t, isBasenameChunkDataFile(chunkFileName), chunkFileName)
		return true
	})
}

func TestChunkDataFileSyntaxNoID(t *testing.T) {
	quickcheck(t, func(is [2]uint) bool {
		chunkFileName := fmt.Sprintf("%s%s%s%v", chunkPrefix, sep, sep, is[1])
		assert.False(t, isBasenameChunkDataFile(chunkFileName), chunkFileName)
		return true
	})
}

func TestChunkDataFileSyntaxNoOldest(t *testing.T) {
	quickcheck(t, func(is [2]uint) bool {
		chunkFileName := fmt.Sprintf("%s%s%v%s", chunkPrefix, sep, is[0], sep)
		assert.False(t, isBasenameChunkDataFile(chunkFileName), chunkFileName)
		return true
	})
}

func TestChunkDataFileSyntaxIDNotUint(t *testing.T) {
	quickcheck(t, func(is [2]uint) bool {
		chunkFileName := fmt.Sprintf("%s%s~%v%s%v", chunkPrefix, sep, is[0], sep, is[1])
		assert.False(t, isBasenameChunkDataFile(chunkFileName), chunkFileName)
		return true
	})
}

func TestChunkDataFileSyntaxOldestNotUint(t *testing.T) {
	quickcheck(t, func(is [2]uint) bool {
		chunkFileName := fmt.Sprintf("%s%s%v%s~%v", chunkPrefix, sep, is[0], sep, is[1])
		assert.False(t, isBasenameChunkDataFile(chunkFileName), chunkFileName)
		return true
	})
}

func TestChunkDataFileNext(t *testing.T) {
	quickcheck(t, func(is [3]uint) bool {
		c := &chunk{path: fmt.Sprintf("%s%s%v%s%v", chunkPrefix, sep, is[0], sep, is[1])}
		nextFileName := fmt.Sprintf("%s%s%v%s%v", chunkPrefix, sep, is[0]+1, sep, is[2])
		assert.Equal(t, nextFileName, c.nextDataFileName(uint64(is[2])), "next data file name")
		return true
	})
}

func TestChunkMetaFilePath(t *testing.T) {
	quickcheck(t, func(is [2]uint) bool {
		c := &chunk{path: fmt.Sprintf("%s%s%v%s%v", chunkPrefix, sep, is[0], sep, is[1])}
		assert.Equal(t, metaFilePath(c.path), c.metaFilePath(), "meta file path")
		return true
	})
}

func TestMetadata(t *testing.T) {
	metadata := makeMetadata(t, []int32{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5})
	ends, err := readMetadata(metadata)
	assert.Nil(t, err, "failed to read metadata: %s", err)
	assert.Equal(t, []int32{0, 1, 2, 3, 4, 5}, ends, "ends")
}

func TestMetadataNonContiguousIndices(t *testing.T) {
	metadata := makeMetadata(t, []int32{0, 0, 1, 1, 5, 2})
	ends, err := readMetadata(metadata)
	assert.NotNil(t, err, "expected to not parse that, got: %v", ends)
}

func TestMetadataNonIncreasingEnds(t *testing.T) {
	metadata := makeMetadata(t, []int32{0, 0, 1, 1, 2, 0})
	ends, err := readMetadata(metadata)
	assert.NotNil(t, err, "expected to not parse that, got: %v", ends)
}

func TestMetadataRollback(t *testing.T) {
	metadata := makeMetadata(t, []int32{0, 0, 1, 1, 0, 1})
	ends, err := readMetadata(metadata)
	assert.Nil(t, err, "failed to read metadata: %s", err)
	assert.Equal(t, []int32{1}, ends, "failed to apply rollback, got: %v", ends)
}

func TestMetadataIncomplete(t *testing.T) {
	metadata := makeMetadata(t, []int32{0, 0, 1})
	ends, err := readMetadata(metadata)
	assert.NotNil(t, err, "expected to not parse that, got: %v", ends)
}

func TestMetadataIncompleteRollback(t *testing.T) {
	metadata := makeMetadata(t, []int32{0, 0, 1, 1, 0})
	ends, err := readMetadata(metadata)
	assert.NotNil(t, err, "expected to not parse that, got: %v", ends)
}

/// HELPERS

func quickcheck(t *testing.T, f interface{}) {
	if err := quick.Check(f, nil); err != nil {
		t.Fatal(err)
	}
}

func makeMetadata(t testing.TB, vals []int32) io.Reader {
	buf := new(bytes.Buffer)
	if err := binary.Write(buf, binary.LittleEndian, vals); err != nil {
		t.Fatal(err)
	}
	return buf
}
<|endoftext|>


<commit_before>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2018 Red Hat, Inc.
 *
 */

package tests_test

import (
	"flag"
	"fmt"
	"net/http"
	"time"

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

	k8sv1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	k8smetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/json"

	"kubevirt.io/kubevirt/pkg/api/v1"
	"kubevirt.io/kubevirt/pkg/kubecli"
	"kubevirt.io/kubevirt/tests"
)

var _ = Describe("VMPreset", func() {
	flag.Parse()

	virtClient, err := kubecli.GetKubevirtClient()
	tests.PanicOnError(err)

	var vm *v1.VirtualMachine
	var memoryPreset *v1.VirtualMachinePreset
	var cpuPreset *v1.VirtualMachinePreset

	flavorKey := fmt.Sprintf("%s/flavor", v1.GroupName)
	memoryFlavor := "memory-test"
	memory, _ := resource.ParseQuantity("128M")

	cpuFlavor := "cpu-test"
	cores := 7

	BeforeEach(func() {
		tests.BeforeTestCleanup()
		vm = tests.NewRandomVMWithEphemeralDisk(tests.RegistryDiskFor(tests.RegistryDiskAlpine))
		vm.Labels = map[string]string{flavorKey: memoryFlavor}

		selector := k8smetav1.LabelSelector{MatchLabels: map[string]string{flavorKey: memoryFlavor}}
		memoryPreset = &v1.VirtualMachinePreset{
			ObjectMeta: k8smetav1.ObjectMeta{GenerateName: "test-memory-"},
			Spec: v1.VirtualMachinePresetSpec{
				Selector: selector,
				Domain: &v1.DomainSpec{
					Resources: v1.ResourceRequirements{Requests: k8sv1.ResourceList{
						"memory": memory}},
				},
			},
		}

		selector = k8smetav1.LabelSelector{MatchLabels: map[string]string{flavorKey: cpuFlavor}}
		cpuPreset = &v1.VirtualMachinePreset{
			ObjectMeta: k8smetav1.ObjectMeta{GenerateName: "test-cpu-"},
			Spec: v1.VirtualMachinePresetSpec{
				Selector: selector,
				Domain: &v1.DomainSpec{
					CPU: &v1.CPU{Cores: uint32(cores)},
				},
			},
		}
	})

	Context("Preset Matching", func() {

		It("Should be accepted on POST", func() {
			err := virtClient.RestClient().Post().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Body(memoryPreset).Do().Error()
			Expect(err).To(BeNil())
		})

		It("Should reject a second submission of a VMPreset", func() {
			// This test requires an explicit name or the resources won't conflict
			memoryPreset.Name = "test-preset"
			err := virtClient.RestClient().Post().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Body(memoryPreset).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			waitForPreset(virtClient)

			b, err := virtClient.RestClient().Post().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Body(memoryPreset).DoRaw()
			Expect(err).To(HaveOccurred())
			status := k8smetav1.Status{}
			err = json.Unmarshal(b, &status)
			Expect(err).ToNot(HaveOccurred())
		})

		It("Should return 404 if VMPreset does not exist", func() {
			b, err := virtClient.RestClient().Get().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Name("wrong").DoRaw()
			Expect(err).To(HaveOccurred())
			status := k8smetav1.Status{}
			err = json.Unmarshal(b, &status)
			Expect(err).ToNot(HaveOccurred())
			Expect(status.Code).To(Equal(int32(http.StatusNotFound)))
		})

		It("Should reject presets that conflict with VM settings", func() {
			err := virtClient.RestClient().Post().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Body(memoryPreset).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			newPreset := waitForPreset(virtClient)

			err = virtClient.RestClient().Post().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Body(vm).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			newVm := v1.VirtualMachine{}
			err = virtClient.RestClient().Get().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Name(vm.Name).Do().Into(&newVm)
			Expect(err).ToNot(HaveOccurred())

			Expect(newVm.Labels[flavorKey]).To(Equal(memoryFlavor))
			Expect(newPreset.Spec.Selector.MatchLabels[flavorKey]).To(Equal(memoryFlavor))

			// check the annotations
			Expect(len(newVm.Annotations)).To(Equal(0))
		})

		It("Should accept presets that don't conflict with VM settings", func() {
			err := virtClient.RestClient().Post().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Body(cpuPreset).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			newPreset := waitForPreset(virtClient)

			vm = tests.NewRandomVMWithEphemeralDisk("kubevirt/alpine-registry-disk-demo:devel")
			vm.Labels = map[string]string{flavorKey: cpuFlavor}

			err = virtClient.RestClient().Post().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Body(vm).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			newVm := v1.VirtualMachine{}
			err = virtClient.RestClient().Get().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Name(vm.Name).Do().Into(&newVm)
			Expect(err).ToNot(HaveOccurred())

			Expect(newVm.Labels[flavorKey]).To(Equal(cpuFlavor))
			Expect(newPreset.Spec.Selector.MatchLabels[flavorKey]).To(Equal(cpuFlavor))

			// check the annotations
			Expect(len(newVm.Annotations)).To(Equal(1))
			annotationKey := fmt.Sprintf("virtualmachinepreset.%s/%s", v1.GroupName, newPreset.Name)
			Expect(newVm.Annotations[annotationKey]).To(Equal("kubevirt.io/v1alpha1"))

			// check a setting from the preset itself to show it was applied
			Expect(int(newVm.Spec.Domain.CPU.Cores)).To(Equal(cores))
		})

		It("Should ignore VMs that don't match", func() {
			err := virtClient.RestClient().Post().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Body(memoryPreset).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			// reset the label so it will not match
			vm = tests.NewRandomVMWithEphemeralDisk("kubevirt/alpine-registry-disk-demo:devel")
			err = virtClient.RestClient().Post().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Body(vm).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			newVm := v1.VirtualMachine{}
			err = virtClient.RestClient().Get().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Name(vm.Name).Do().Into(&newVm)
			Expect(err).ToNot(HaveOccurred())

			Expect(len(newVm.Annotations)).To(Equal(0))
		})

		It("Should not be applied to existing VMs", func() {
			// create the VM first
			err = virtClient.RestClient().Post().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Body(vm).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			err := virtClient.RestClient().Post().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Body(memoryPreset).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			newVm := v1.VirtualMachine{}
			err = virtClient.RestClient().Get().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Name(vm.Name).Do().Into(&newVm)
			Expect(err).ToNot(HaveOccurred())

			Expect(len(newVm.Annotations)).To(Equal(0))
		})
	})
})

func waitForPreset(virtClient kubecli.KubevirtClient) v1.VirtualMachinePreset {
	preset := v1.VirtualMachinePreset{}
	Eventually(func() bool {
		presetList := v1.VirtualMachinePresetList{}
		err := virtClient.RestClient().Get().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Do().Into(&presetList)
		Expect(err).ToNot(HaveOccurred())
		if len(presetList.Items) == 1 {
			preset = presetList.Items[0]
		}
		return true
	}, time.Duration(60)*time.Second).Should(Equal(true), "Timed out waiting for preset to appear")
	return preset
}
<commit_msg>Fix annotation tests in VMPreset functional tests<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2018 Red Hat, Inc.
 *
 */

package tests_test

import (
	"flag"
	"fmt"
	"net/http"
	"time"

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

	k8sv1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	k8smetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/json"

	"kubevirt.io/kubevirt/pkg/api/v1"
	"kubevirt.io/kubevirt/pkg/kubecli"
	"kubevirt.io/kubevirt/tests"
)

var _ = Describe("VMPreset", func() {
	flag.Parse()

	virtClient, err := kubecli.GetKubevirtClient()
	tests.PanicOnError(err)

	var vm *v1.VirtualMachine
	var memoryPreset *v1.VirtualMachinePreset
	var cpuPreset *v1.VirtualMachinePreset

	flavorKey := fmt.Sprintf("%s/flavor", v1.GroupName)
	memoryFlavor := "memory-test"
	memory, _ := resource.ParseQuantity("128M")

	cpuFlavor := "cpu-test"
	cores := 7

	BeforeEach(func() {
		tests.BeforeTestCleanup()
		vm = tests.NewRandomVMWithEphemeralDisk(tests.RegistryDiskFor(tests.RegistryDiskAlpine))
		vm.Labels = map[string]string{flavorKey: memoryFlavor}

		selector := k8smetav1.LabelSelector{MatchLabels: map[string]string{flavorKey: memoryFlavor}}
		memoryPreset = &v1.VirtualMachinePreset{
			ObjectMeta: k8smetav1.ObjectMeta{GenerateName: "test-memory-"},
			Spec: v1.VirtualMachinePresetSpec{
				Selector: selector,
				Domain: &v1.DomainSpec{
					Resources: v1.ResourceRequirements{Requests: k8sv1.ResourceList{
						"memory": memory}},
				},
			},
		}

		selector = k8smetav1.LabelSelector{MatchLabels: map[string]string{flavorKey: cpuFlavor}}
		cpuPreset = &v1.VirtualMachinePreset{
			ObjectMeta: k8smetav1.ObjectMeta{GenerateName: "test-cpu-"},
			Spec: v1.VirtualMachinePresetSpec{
				Selector: selector,
				Domain: &v1.DomainSpec{
					CPU: &v1.CPU{Cores: uint32(cores)},
				},
			},
		}
	})

	Context("Preset Matching", func() {

		It("Should be accepted on POST", func() {
			err := virtClient.RestClient().Post().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Body(memoryPreset).Do().Error()
			Expect(err).To(BeNil())
		})

		It("Should reject a second submission of a VMPreset", func() {
			// This test requires an explicit name or the resources won't conflict
			memoryPreset.Name = "test-preset"
			err := virtClient.RestClient().Post().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Body(memoryPreset).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			waitForPreset(virtClient)

			b, err := virtClient.RestClient().Post().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Body(memoryPreset).DoRaw()
			Expect(err).To(HaveOccurred())
			status := k8smetav1.Status{}
			err = json.Unmarshal(b, &status)
			Expect(err).ToNot(HaveOccurred())
		})

		It("Should return 404 if VMPreset does not exist", func() {
			b, err := virtClient.RestClient().Get().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Name("wrong").DoRaw()
			Expect(err).To(HaveOccurred())
			status := k8smetav1.Status{}
			err = json.Unmarshal(b, &status)
			Expect(err).ToNot(HaveOccurred())
			Expect(status.Code).To(Equal(int32(http.StatusNotFound)))
		})

		It("Should reject presets that conflict with VM settings", func() {
			err := virtClient.RestClient().Post().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Body(memoryPreset).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			newPreset := waitForPreset(virtClient)

			err = virtClient.RestClient().Post().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Body(vm).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			newVm := v1.VirtualMachine{}
			err = virtClient.RestClient().Get().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Name(vm.Name).Do().Into(&newVm)
			Expect(err).ToNot(HaveOccurred())

			Expect(newVm.Labels[flavorKey]).To(Equal(memoryFlavor))
			Expect(newPreset.Spec.Selector.MatchLabels[flavorKey]).To(Equal(memoryFlavor))

			// check the annotations
			Expect(len(newVm.Annotations)).To(Equal(0))
		})

		It("Should accept presets that don't conflict with VM settings", func() {
			err := virtClient.RestClient().Post().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Body(cpuPreset).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			newPreset := waitForPreset(virtClient)

			vm = tests.NewRandomVMWithEphemeralDisk("kubevirt/alpine-registry-disk-demo:devel")
			vm.Labels = map[string]string{flavorKey: cpuFlavor}

			err = virtClient.RestClient().Post().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Body(vm).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			newVm := v1.VirtualMachine{}
			err = virtClient.RestClient().Get().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Name(vm.Name).Do().Into(&newVm)
			Expect(err).ToNot(HaveOccurred())

			Expect(newVm.Labels[flavorKey]).To(Equal(cpuFlavor))
			Expect(newPreset.Spec.Selector.MatchLabels[flavorKey]).To(Equal(cpuFlavor))

			// check the annotations
			annotationKey := fmt.Sprintf("virtualmachinepreset.%s/%s", v1.GroupName, newPreset.Name)
			Expect(newVm.Annotations[annotationKey]).To(Equal("kubevirt.io/v1alpha1"))

			// check a setting from the preset itself to show it was applied
			Expect(int(newVm.Spec.Domain.CPU.Cores)).To(Equal(cores))
		})

		It("Should ignore VMs that don't match", func() {
			err := virtClient.RestClient().Post().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Body(memoryPreset).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			newPreset := waitForPreset(virtClient)

			// reset the label so it will not match
			vm = tests.NewRandomVMWithEphemeralDisk("kubevirt/alpine-registry-disk-demo:devel")
			err = virtClient.RestClient().Post().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Body(vm).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			newVm := v1.VirtualMachine{}
			err = virtClient.RestClient().Get().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Name(vm.Name).Do().Into(&newVm)
			Expect(err).ToNot(HaveOccurred())

			Expect(len(newVm.Annotations)).To(Equal(0))

			// check the annotations
			annotationKey := fmt.Sprintf("virtualmachinepreset.%s/%s", v1.GroupName, newPreset.Name)
			_, found := newVm.Annotations[annotationKey]
			Expect(found).To(BeFalse())
		})

		It("Should not be applied to existing VMs", func() {
			// create the VM first
			err = virtClient.RestClient().Post().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Body(vm).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			newPreset := waitForPreset(virtClient)

			err := virtClient.RestClient().Post().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Body(memoryPreset).Do().Error()
			Expect(err).ToNot(HaveOccurred())

			newVm := v1.VirtualMachine{}
			err = virtClient.RestClient().Get().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Name(vm.Name).Do().Into(&newVm)
			Expect(err).ToNot(HaveOccurred())

			// check the annotations
			annotationKey := fmt.Sprintf("virtualmachinepreset.%s/%s", v1.GroupName, newPreset.Name)
			_, found := newVm.Annotations[annotationKey]
			Expect(found).To(BeFalse())
		})
	})
})

func waitForPreset(virtClient kubecli.KubevirtClient) v1.VirtualMachinePreset {
	preset := v1.VirtualMachinePreset{}
	Eventually(func() bool {
		presetList := v1.VirtualMachinePresetList{}
		err := virtClient.RestClient().Get().Resource("virtualmachinepresets").Namespace(tests.NamespaceTestDefault).Do().Into(&presetList)
		Expect(err).ToNot(HaveOccurred())
		if len(presetList.Items) == 1 {
			preset = presetList.Items[0]
		}
		return true
	}, time.Duration(60)*time.Second).Should(Equal(true), "Timed out waiting for preset to appear")
	return preset
}
<|endoftext|>


<commit_before>package earlyoom_testsuite

import (
	"io/ioutil"
	"os"
	"strings"
	"syscall"
	"testing"
	"unicode/utf8"
)

// On Fedora 31 (Linux 5.4), /proc/sys/kernel/pid_max = 4194304.
// It's very unlikely that INT32_MAX will be a valid pid anytime soon.
const INT32_MAX = 2147483647
const ENOENT = 2

func TestParseTuple(t *testing.T) {
	tcs := []struct {
		arg        string
		limit      int
		shouldFail bool
		term       float64
		kill       float64
	}{
		{arg: "2,1", limit: 100, term: 2, kill: 1},
		{arg: "20,10", limit: 100, term: 20, kill: 10},
		{arg: "30", limit: 100, term: 30, kill: 15},
		{arg: "30", limit: 20, shouldFail: true},
		// https://github.com/rfjakob/earlyoom/issues/97
		{arg: "22[,20]", limit: 100, shouldFail: true},
		{arg: "220[,160]", limit: 300, shouldFail: true},
		{arg: "180[,170]", limit: 300, shouldFail: true},
		{arg: "5,0", limit: 100, term: 5, kill: 0},
		{arg: "5,9", limit: 100, term: 9, kill: 9},
		{arg: "0,5", limit: 100, term: 5, kill: 5},
		// TERM value is set to KILL value when it is below TERM
		{arg: "4,5", limit: 100, term: 5, kill: 5},
		{arg: "0", limit: 100, shouldFail: true},
		{arg: "0,0", limit: 100, shouldFail: true},
		// Floating point values
		{arg: "4.0,2.0", limit: 100, term: 4, kill: 2},
		{arg: "4,0,2,0", limit: 100, shouldFail: true},
		{arg: "3.1415,2.7182", limit: 100, term: 3.1415, kill: 2.7182},
		{arg: "3.1415", limit: 100, term: 3.1415, kill: 3.1415 / 2},
		{arg: "1." + strings.Repeat("123", 100), limit: 100, shouldFail: true},
		// Leading garbage
		{arg: "x1,x2", limit: 100, shouldFail: true},
		{arg: "1,x2", limit: 100, shouldFail: true},
		// Trailing garbage
		{arg: "1x,2x", limit: 100, shouldFail: true},
		{arg: "1.1.", limit: 100, shouldFail: true},
		{arg: "1,2..", limit: 100, shouldFail: true},
	}
	for _, tc := range tcs {
		err, term, kill := parse_term_kill_tuple(tc.arg, tc.limit)
		hasFailed := (err != nil)
		if tc.shouldFail != hasFailed {
			t.Errorf("case %v: hasFailed=%v", tc, hasFailed)
			continue
		}
		if term != tc.term {
			t.Errorf("case %v: term=%v", tc, term)
		}
		if kill != tc.kill {
			t.Errorf("case %v: kill=%v", tc, kill)
		}
	}
}

func TestIsAlive(t *testing.T) {
	tcs := []struct {
		pid int
		res bool
	}{
		{os.Getpid(), true},
		{1, true},
		{999999, false},
		{0, false},
	}
	for _, tc := range tcs {
		if res := is_alive(tc.pid); res != tc.res {
			t.Errorf("pid %d: expected %v, got %v", tc.pid, tc.res, res)
		}
	}
}

func TestIsAliveMock(t *testing.T) {
	mockProcdir, err := os.MkdirTemp("", t.Name())
	if err != nil {
		t.Fatal(err)
	}
	procdir_path(mockProcdir)
	defer procdir_path("/proc")

	if err := os.Mkdir(mockProcdir+"/100", 0700); err != nil {
		t.Fatal(err)
	}

	testCases := []struct {
		content string
		res     bool
	}{
		{"144815 (bash) S 17620 144815 144815 34817 247882 4194304 20170 1855121 1 3321 28 46 3646 3366 20 0 1 0 10798280 237576192 1065 18446744073709551615 94174652813312 94174653706789 140724247111872 0 0 0 65536 3686404 1266761467 0 0 0 17 0 0 0 9 0 0 94174653946928 94174653994640 94174663303168 140724247119367 140724247119377 140724247119377 140724247121902 0",
			true}, // full string from actual system
		{"123 (bash) R 123 123 123", true}, // truncated for brevity
		{"123 (bash) Z 123 123 123", false},
		// hostile process names that try to fake "I am dead"
		{"123 (foo) Z ) R 123 123 123", true},
		{"123 (foo) Z) R 123 123 123", true},
		{"123 (foo)Z ) R 123 123 123", true},
		{"123 (foo)\nZ\n) R 123 123 123", true},
		{"123 (foo)\tZ\t) R 123 123 123", true},
		{"123 (foo)  Z   ) R 123 123 123", true},
	}

	for _, tc := range testCases {
		statFile := mockProcdir + "/100/stat"
		if err := ioutil.WriteFile(statFile, []byte(tc.content), 0600); err != nil {
			t.Fatal(err)
		}
		if is_alive(100) != tc.res {
			t.Errorf("have=%v, want=%v for /proc/100/stat=%q", is_alive(100), tc.res, tc.content)
		}
	}
}

func Test_fix_truncated_utf8(t *testing.T) {
	// From https://gist.github.com/w-vi/67fe49106c62421992a2
	str := "___😀∮ E⋅da = Q,  n → ∞, 𐍈∑ f(i) = ∏ g(i)"
	// a range loop will split at runes - we *want* broken utf8 so use raw
	// counter.
	for i := 3; i < len(str); i++ {
		truncated := str[:i]
		fixed := fix_truncated_utf8(truncated)
		if len(fixed) < 3 {
			t.Fatalf("truncated: %q", fixed)
		}
		if !utf8.Valid([]byte(fixed)) {
			t.Errorf("Invalid utf8: %q", fixed)
		}
	}
}

func Test_get_vm_rss_kib(t *testing.T) {
	pid := os.Getpid()
	rss := get_vm_rss_kib(pid)
	if rss <= 0 {
		t.Fatalf("our rss can't be <= 0, but we got %d", rss)
	}
	// Error case
	res := get_vm_rss_kib(INT32_MAX)
	if res != -ENOENT {
		t.Fail()
	}
}

func Test_get_oom_score(t *testing.T) {
	res := get_oom_score(os.Getpid())
	// On systems with a lot of RAM, our process may actually have a score of
	// zero. At least check that get_oom_score did not return an error.
	if res < 0 {
		t.Error(res)
	}
	res = get_oom_score(INT32_MAX)
	if res != -ENOENT {
		t.Errorf("want %d, but have %d", syscall.ENOENT, res)
	}
}

func Test_get_comm(t *testing.T) {
	pid := os.Getpid()
	res, comm := get_comm(pid)
	if res != 0 {
		t.Fatalf("error %d", res)
	}
	if len(comm) == 0 {
		t.Fatalf("empty process name %q", comm)
	}
	t.Logf("process name %q", comm)
	// Error case
	res, comm = get_comm(INT32_MAX)
	if res != -ENOENT {
		t.Fail()
	}
	if comm != "" {
		t.Fail()
	}
}

func Benchmark_parse_meminfo(b *testing.B) {
	for n := 0; n < b.N; n++ {
		parse_meminfo()
	}
}

func Benchmark_kill_process(b *testing.B) {
	for n := 0; n < b.N; n++ {
		kill_process()
	}
}

func Benchmark_find_largest_process(b *testing.B) {
	for n := 0; n < b.N; n++ {
		find_largest_process()
	}
}

func Benchmark_get_oom_score(b *testing.B) {
	pid := os.Getpid()
	for n := 0; n < b.N; n++ {
		get_oom_score(pid)
	}
}

func Benchmark_get_oom_score_adj(b *testing.B) {
	pid := os.Getpid()
	for n := 0; n < b.N; n++ {
		var out int
		get_oom_score_adj(pid, &out)
	}
}

func Benchmark_get_vm_rss_kib(b *testing.B) {
	pid := os.Getpid()
	for n := 0; n < b.N; n++ {
		rss := get_vm_rss_kib(pid)
		if rss <= 0 {
			b.Fatalf("rss <= 0: %d", rss)
		}
	}
}

func Benchmark_get_comm(b *testing.B) {
	pid := os.Getpid()
	for n := 0; n < b.N; n++ {
		res, comm := get_comm(pid)
		if len(comm) == 0 {
			b.Fatalf("empty process name %q", comm)
		}
		if res != 0 {
			b.Fatalf("error %d", res)
		}
	}
}
<commit_msg>tests: avoid os.MkdirTemp<commit_after>package earlyoom_testsuite

import (
	"io/ioutil"
	"os"
	"strings"
	"syscall"
	"testing"
	"unicode/utf8"
)

// On Fedora 31 (Linux 5.4), /proc/sys/kernel/pid_max = 4194304.
// It's very unlikely that INT32_MAX will be a valid pid anytime soon.
const INT32_MAX = 2147483647
const ENOENT = 2

func TestParseTuple(t *testing.T) {
	tcs := []struct {
		arg        string
		limit      int
		shouldFail bool
		term       float64
		kill       float64
	}{
		{arg: "2,1", limit: 100, term: 2, kill: 1},
		{arg: "20,10", limit: 100, term: 20, kill: 10},
		{arg: "30", limit: 100, term: 30, kill: 15},
		{arg: "30", limit: 20, shouldFail: true},
		// https://github.com/rfjakob/earlyoom/issues/97
		{arg: "22[,20]", limit: 100, shouldFail: true},
		{arg: "220[,160]", limit: 300, shouldFail: true},
		{arg: "180[,170]", limit: 300, shouldFail: true},
		{arg: "5,0", limit: 100, term: 5, kill: 0},
		{arg: "5,9", limit: 100, term: 9, kill: 9},
		{arg: "0,5", limit: 100, term: 5, kill: 5},
		// TERM value is set to KILL value when it is below TERM
		{arg: "4,5", limit: 100, term: 5, kill: 5},
		{arg: "0", limit: 100, shouldFail: true},
		{arg: "0,0", limit: 100, shouldFail: true},
		// Floating point values
		{arg: "4.0,2.0", limit: 100, term: 4, kill: 2},
		{arg: "4,0,2,0", limit: 100, shouldFail: true},
		{arg: "3.1415,2.7182", limit: 100, term: 3.1415, kill: 2.7182},
		{arg: "3.1415", limit: 100, term: 3.1415, kill: 3.1415 / 2},
		{arg: "1." + strings.Repeat("123", 100), limit: 100, shouldFail: true},
		// Leading garbage
		{arg: "x1,x2", limit: 100, shouldFail: true},
		{arg: "1,x2", limit: 100, shouldFail: true},
		// Trailing garbage
		{arg: "1x,2x", limit: 100, shouldFail: true},
		{arg: "1.1.", limit: 100, shouldFail: true},
		{arg: "1,2..", limit: 100, shouldFail: true},
	}
	for _, tc := range tcs {
		err, term, kill := parse_term_kill_tuple(tc.arg, tc.limit)
		hasFailed := (err != nil)
		if tc.shouldFail != hasFailed {
			t.Errorf("case %v: hasFailed=%v", tc, hasFailed)
			continue
		}
		if term != tc.term {
			t.Errorf("case %v: term=%v", tc, term)
		}
		if kill != tc.kill {
			t.Errorf("case %v: kill=%v", tc, kill)
		}
	}
}

func TestIsAlive(t *testing.T) {
	tcs := []struct {
		pid int
		res bool
	}{
		{os.Getpid(), true},
		{1, true},
		{999999, false},
		{0, false},
	}
	for _, tc := range tcs {
		if res := is_alive(tc.pid); res != tc.res {
			t.Errorf("pid %d: expected %v, got %v", tc.pid, tc.res, res)
		}
	}
}

func TestIsAliveMock(t *testing.T) {
	mockProcdir, err := ioutil.TempDir("", t.Name())
	if err != nil {
		t.Fatal(err)
	}
	procdir_path(mockProcdir)
	defer procdir_path("/proc")

	if err := os.Mkdir(mockProcdir+"/100", 0700); err != nil {
		t.Fatal(err)
	}

	testCases := []struct {
		content string
		res     bool
	}{
		{"144815 (bash) S 17620 144815 144815 34817 247882 4194304 20170 1855121 1 3321 28 46 3646 3366 20 0 1 0 10798280 237576192 1065 18446744073709551615 94174652813312 94174653706789 140724247111872 0 0 0 65536 3686404 1266761467 0 0 0 17 0 0 0 9 0 0 94174653946928 94174653994640 94174663303168 140724247119367 140724247119377 140724247119377 140724247121902 0",
			true}, // full string from actual system
		{"123 (bash) R 123 123 123", true}, // truncated for brevity
		{"123 (bash) Z 123 123 123", false},
		// hostile process names that try to fake "I am dead"
		{"123 (foo) Z ) R 123 123 123", true},
		{"123 (foo) Z) R 123 123 123", true},
		{"123 (foo)Z ) R 123 123 123", true},
		{"123 (foo)\nZ\n) R 123 123 123", true},
		{"123 (foo)\tZ\t) R 123 123 123", true},
		{"123 (foo)  Z   ) R 123 123 123", true},
	}

	for _, tc := range testCases {
		statFile := mockProcdir + "/100/stat"
		if err := ioutil.WriteFile(statFile, []byte(tc.content), 0600); err != nil {
			t.Fatal(err)
		}
		if is_alive(100) != tc.res {
			t.Errorf("have=%v, want=%v for /proc/100/stat=%q", is_alive(100), tc.res, tc.content)
		}
	}
}

func Test_fix_truncated_utf8(t *testing.T) {
	// From https://gist.github.com/w-vi/67fe49106c62421992a2
	str := "___😀∮ E⋅da = Q,  n → ∞, 𐍈∑ f(i) = ∏ g(i)"
	// a range loop will split at runes - we *want* broken utf8 so use raw
	// counter.
	for i := 3; i < len(str); i++ {
		truncated := str[:i]
		fixed := fix_truncated_utf8(truncated)
		if len(fixed) < 3 {
			t.Fatalf("truncated: %q", fixed)
		}
		if !utf8.Valid([]byte(fixed)) {
			t.Errorf("Invalid utf8: %q", fixed)
		}
	}
}

func Test_get_vm_rss_kib(t *testing.T) {
	pid := os.Getpid()
	rss := get_vm_rss_kib(pid)
	if rss <= 0 {
		t.Fatalf("our rss can't be <= 0, but we got %d", rss)
	}
	// Error case
	res := get_vm_rss_kib(INT32_MAX)
	if res != -ENOENT {
		t.Fail()
	}
}

func Test_get_oom_score(t *testing.T) {
	res := get_oom_score(os.Getpid())
	// On systems with a lot of RAM, our process may actually have a score of
	// zero. At least check that get_oom_score did not return an error.
	if res < 0 {
		t.Error(res)
	}
	res = get_oom_score(INT32_MAX)
	if res != -ENOENT {
		t.Errorf("want %d, but have %d", syscall.ENOENT, res)
	}
}

func Test_get_comm(t *testing.T) {
	pid := os.Getpid()
	res, comm := get_comm(pid)
	if res != 0 {
		t.Fatalf("error %d", res)
	}
	if len(comm) == 0 {
		t.Fatalf("empty process name %q", comm)
	}
	t.Logf("process name %q", comm)
	// Error case
	res, comm = get_comm(INT32_MAX)
	if res != -ENOENT {
		t.Fail()
	}
	if comm != "" {
		t.Fail()
	}
}

func Benchmark_parse_meminfo(b *testing.B) {
	for n := 0; n < b.N; n++ {
		parse_meminfo()
	}
}

func Benchmark_kill_process(b *testing.B) {
	for n := 0; n < b.N; n++ {
		kill_process()
	}
}

func Benchmark_find_largest_process(b *testing.B) {
	for n := 0; n < b.N; n++ {
		find_largest_process()
	}
}

func Benchmark_get_oom_score(b *testing.B) {
	pid := os.Getpid()
	for n := 0; n < b.N; n++ {
		get_oom_score(pid)
	}
}

func Benchmark_get_oom_score_adj(b *testing.B) {
	pid := os.Getpid()
	for n := 0; n < b.N; n++ {
		var out int
		get_oom_score_adj(pid, &out)
	}
}

func Benchmark_get_vm_rss_kib(b *testing.B) {
	pid := os.Getpid()
	for n := 0; n < b.N; n++ {
		rss := get_vm_rss_kib(pid)
		if rss <= 0 {
			b.Fatalf("rss <= 0: %d", rss)
		}
	}
}

func Benchmark_get_comm(b *testing.B) {
	pid := os.Getpid()
	for n := 0; n < b.N; n++ {
		res, comm := get_comm(pid)
		if len(comm) == 0 {
			b.Fatalf("empty process name %q", comm)
		}
		if res != 0 {
			b.Fatalf("error %d", res)
		}
	}
}
<|endoftext|>


<commit_before>package main_test

import (
	_ "fmt"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/regiluze/unbeatableTicTacToe-"
)

const ()

var _ = Describe("Tic Tac Toe game board specs", func() {
	var (
		board              *TicTacToeBoard
		irrelevantPosition Position
	)

	BeforeEach(func() {
		board = NewTicTacToeBoard()
		irrelevantPosition = Position{X: 0, Y: 0}
	})

	Describe("Filling the board with tokens", func() {
		Context("when adding a nought", func() {
			It("fills board position with a nought token", func() {
				boardSnapshot, _ := board.PutNought(irrelevantPosition)

				Expect(boardSnapshot[irrelevantPosition.X][irrelevantPosition.Y]).Should(Equal(NOUGHT))
			})
			Context("when the board place is already filled", func() {
				It("returns an error", func() {
					board.PutNought(irrelevantPosition)
					_, err := board.PutNought(irrelevantPosition)

					Expect(err).ShouldNot(BeNil())
				})
			})
		})
		Context("when adding a cross", func() {
			It("fills board position with a cross token", func() {
				boardSnapshot, _ := board.PutCross(irrelevantPosition)

				Expect(boardSnapshot[irrelevantPosition.X][irrelevantPosition.Y]).To(Equal(CROSS))
			})
			Context("when the board place is already filled", func() {
				It("returns an error", func() {
					board.PutCross(irrelevantPosition)
					_, err := board.PutCross(irrelevantPosition)

					Expect(err).ShouldNot(Equal(nil))
				})
			})
		})
	})
	Context("when reset the board", func() {
		It("cleans all tokens from the board", func() {
			board.PutNought(irrelevantPosition)

			board.Reset()

			_, err := board.PutNought(irrelevantPosition)
			Expect(err).Should(BeNil())
		})
	})
	Describe("the game is over", func() {
		Context("when the board is completly full", func() {
			It("returns true and empty string", func() {

				fillAllBoard(board)

				result, winner := board.IsOver()

				Expect(result).Should(BeTrue())
				Expect(winner).Should(BeEmpty())

			})
		})

		Context("when the same type three tokens are in line", func() {
			Context("when there are three crosses on the first line", func() {
				It("returns true and a cross", func() {

					board.PutCross(Position{0, 0})
					board.PutCross(Position{0, 1})
					board.PutCross(Position{0, 2})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(CROSS))

				})
				It("returns true and a cross", func() {

					board.PutNought(Position{0, 0})
					board.PutNought(Position{0, 1})
					board.PutNought(Position{0, 2})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(NOUGHT))

				})
			})
			Context("when there are the same token on the second line", func() {
				It("returns true and a cross", func() {

					board.PutCross(Position{1, 0})
					board.PutCross(Position{1, 1})
					board.PutCross(Position{1, 2})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(CROSS))

				})
			})
			Context("when there are the same token on the third line", func() {
				It("returns true and a hought", func() {

					board.PutNought(Position{2, 0})
					board.PutNought(Position{2, 1})
					board.PutNought(Position{2, 2})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(NOUGHT))

				})
			})
		})
		Context("when three are three cross tokens in column line", func() {
			Context("when there are on the first column", func() {
				It("returns true and a cross", func() {

					board.PutCross(Position{0, 0})
					board.PutCross(Position{1, 0})
					board.PutCross(Position{2, 0})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(CROSS))

				})
			})
			Context("when there are the same token on the second column", func() {
				It("returns true and a cross", func() {

					board.PutCross(Position{0, 1})
					board.PutCross(Position{1, 1})
					board.PutCross(Position{2, 1})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(CROSS))

				})
			})
		})
		Context("when three nought tokens are on cross line", func() {
			Context("when there are on first cross", func() {
				It("returns true and a nought", func() {

					board.PutNought(Position{0, 0})
					board.PutNought(Position{1, 1})
					board.PutNought(Position{2, 2})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(NOUGHT))

				})
			})
			Context("when there are on second cross", func() {
				It("returns true and a nought", func() {

					board.PutNought(Position{0, 2})
					board.PutNought(Position{1, 1})
					board.PutNought(Position{2, 0})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(NOUGHT))

				})
			})
		})
	})
})

func fillAllBoard(board *TicTacToeBoard) {
	token := CROSS
	for row := 0; row < 3; row++ {
		if row == 1 {
			token = CROSS
		}
		for col := 0; col < 3; col++ {
			if token == CROSS {
				board.PutNought(Position{row, col})
				token = NOUGHT
			} else {
				board.PutCross(Position{row, col})
				token = CROSS
			}
		}
	}
}
<commit_msg>specs description refactored<commit_after>package main_test

import (
	_ "fmt"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/regiluze/unbeatableTicTacToe-"
)

const ()

var _ = Describe("Tic Tac Toe game board specs", func() {
	var (
		board              *TicTacToeBoard
		irrelevantPosition Position
	)

	BeforeEach(func() {
		board = NewTicTacToeBoard()
		irrelevantPosition = Position{X: 0, Y: 0}
	})

	Describe("Filling the board with tokens", func() {
		Context("when adding a nought", func() {
			It("fills board position with a nought token", func() {
				boardSnapshot, _ := board.PutNought(irrelevantPosition)

				Expect(boardSnapshot[irrelevantPosition.X][irrelevantPosition.Y]).Should(Equal(NOUGHT))
			})
			Context("when the board place is already filled", func() {
				It("returns an error", func() {
					board.PutNought(irrelevantPosition)
					_, err := board.PutNought(irrelevantPosition)

					Expect(err).ShouldNot(BeNil())
				})
			})
		})
		Context("when adding a cross", func() {
			It("fills board position with a cross token", func() {
				boardSnapshot, _ := board.PutCross(irrelevantPosition)

				Expect(boardSnapshot[irrelevantPosition.X][irrelevantPosition.Y]).To(Equal(CROSS))
			})
			Context("when the board place is already filled", func() {
				It("returns an error", func() {
					board.PutCross(irrelevantPosition)
					_, err := board.PutCross(irrelevantPosition)

					Expect(err).ShouldNot(Equal(nil))
				})
			})
		})
	})
	Context("when reset the board", func() {
		It("cleans all tokens from the board", func() {
			board.PutNought(irrelevantPosition)

			board.Reset()

			_, err := board.PutNought(irrelevantPosition)
			Expect(err).Should(BeNil())
		})
	})
	Describe("the game is over", func() {
		Context("when the board is completly full", func() {
			It("returns true and empty string", func() {

				fillAllBoard(board)

				result, winner := board.IsOver()

				Expect(result).Should(BeTrue())
				Expect(winner).Should(BeEmpty())

			})
		})

		Context("when the same type three tokens are in line", func() {
			Context("when three crosses are on the first line", func() {
				It("returns true and a cross", func() {

					board.PutCross(Position{0, 0})
					board.PutCross(Position{0, 1})
					board.PutCross(Position{0, 2})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(CROSS))

				})
			})
			Context("when there three crosses are on the second line", func() {
				It("returns true and a cross", func() {

					board.PutCross(Position{1, 0})
					board.PutCross(Position{1, 1})
					board.PutCross(Position{1, 2})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(CROSS))

				})
			})
			Context("when three noughts are on the third line", func() {
				It("returns true and a hought", func() {

					board.PutNought(Position{2, 0})
					board.PutNought(Position{2, 1})
					board.PutNought(Position{2, 2})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(NOUGHT))

				})
			})
		})
		Context("when the same type three tokens are on column line", func() {
			Context("when three crosses are on the first column", func() {
				It("returns true and a cross", func() {

					board.PutCross(Position{0, 0})
					board.PutCross(Position{1, 0})
					board.PutCross(Position{2, 0})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(CROSS))

				})
			})
			Context("when three croosses are on the second column", func() {
				It("returns true and a cross", func() {

					board.PutCross(Position{0, 1})
					board.PutCross(Position{1, 1})
					board.PutCross(Position{2, 1})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(CROSS))

				})
			})
		})
		Context("when the same type three tokens  are on cross lines", func() {
			Context("when three noughts are on first cross", func() {
				It("returns true and a nought", func() {

					board.PutNought(Position{0, 0})
					board.PutNought(Position{1, 1})
					board.PutNought(Position{2, 2})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(NOUGHT))

				})
			})
			Context("when three crosses are on second cross", func() {
				It("returns true and a nought", func() {

					board.PutCross(Position{0, 2})
					board.PutCross(Position{1, 1})
					board.PutCross(Position{2, 0})

					result, winner := board.IsOver()

					Expect(result).Should(BeTrue())
					Expect(winner).Should(Equal(CROSS))

				})
			})
		})
	})
})

func fillAllBoard(board *TicTacToeBoard) {
	token := CROSS
	for row := 0; row < 3; row++ {
		if row == 1 {
			token = CROSS
		}
		for col := 0; col < 3; col++ {
			if token == CROSS {
				board.PutNought(Position{row, col})
				token = NOUGHT
			} else {
				board.PutCross(Position{row, col})
				token = CROSS
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
   Copyright 2020 Docker, Inc.

   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 mobycli

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"strings"

	apicontext "github.com/docker/api/context"
	"github.com/docker/api/context/store"
)

var delegatedContextTypes = []string{store.DefaultContextType}

// ComDockerCli name of the classic cli binary
const ComDockerCli = "com.docker.cli"

// ExecIfDefaultCtxType delegates to com.docker.cli if on moby or AWS context (until there is an AWS backend)
func ExecIfDefaultCtxType(ctx context.Context) {
	currentContext := apicontext.CurrentContext(ctx)

	s := store.ContextStore(ctx)

	currentCtx, err := s.Get(currentContext)
	// Only run original docker command if the current context is not ours.
	if err != nil || mustDelegateToMoby(currentCtx.Type()) {
		Exec()
	}
}

func mustDelegateToMoby(ctxType string) bool {
	for _, ctype := range delegatedContextTypes {
		if ctxType == ctype {
			return true
		}
	}
	return false
}

// Exec delegates to com.docker.cli if on moby context
func Exec() {
	cmd := exec.Command(ComDockerCli, os.Args[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	s := make(chan os.Signal)
	signal.Notify(s) // catch all signals
	go func() {
		for sig := range s {
			err := cmd.Process.Signal(sig)
			if err != nil {
				fmt.Printf("WARNING could not forward signal %s to %s : %s\n", sig.String(), ComDockerCli, err.Error())
			}
		}
	}()

	if err := cmd.Run(); err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			os.Exit(exiterr.ExitCode())
		}
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	os.Exit(0)
}

// IsDefaultContextCommand checks if the command exists in the classic cli (issues a shellout --help)
func IsDefaultContextCommand(dockerCommand string) bool {
	cmd := exec.Command(ComDockerCli, dockerCommand, "--help")
	b, e := cmd.CombinedOutput()
	if e != nil {
		fmt.Println(e)
	}
	output := string(b)
	contains := strings.Contains(output, "Usage:\tdocker "+dockerCommand)
	return contains
}

// ExecSilent executes a command and do redirect output to stdOut, return output
func ExecSilent(ctx context.Context) ([]byte, error) {
	cmd := exec.CommandContext(ctx, ComDockerCli, os.Args[1:]...)
	return cmd.CombinedOutput()
}
<commit_msg>Stop forwarding signals to child process when the child terminates<commit_after>/*
   Copyright 2020 Docker, Inc.

   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 mobycli

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"strings"

	apicontext "github.com/docker/api/context"
	"github.com/docker/api/context/store"
)

var delegatedContextTypes = []string{store.DefaultContextType}

// ComDockerCli name of the classic cli binary
const ComDockerCli = "com.docker.cli"

// ExecIfDefaultCtxType delegates to com.docker.cli if on moby or AWS context (until there is an AWS backend)
func ExecIfDefaultCtxType(ctx context.Context) {
	currentContext := apicontext.CurrentContext(ctx)

	s := store.ContextStore(ctx)

	currentCtx, err := s.Get(currentContext)
	// Only run original docker command if the current context is not ours.
	if err != nil || mustDelegateToMoby(currentCtx.Type()) {
		Exec()
	}
}

func mustDelegateToMoby(ctxType string) bool {
	for _, ctype := range delegatedContextTypes {
		if ctxType == ctype {
			return true
		}
	}
	return false
}

// Exec delegates to com.docker.cli if on moby context
func Exec() {
	cmd := exec.Command(ComDockerCli, os.Args[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	signals := make(chan os.Signal)
	childExit := make(chan bool)
	signal.Notify(signals) // catch all signals
	go func() {
		for {
			select {
			case sig := <-signals:
				err := cmd.Process.Signal(sig)
				if err != nil {
					fmt.Printf("WARNING could not forward signal %s to %s : %s\n", sig.String(), ComDockerCli, err.Error())
				}
			case <-childExit:
				return
			}
		}
	}()

	err := cmd.Run()
	childExit <- true
	if err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			os.Exit(exiterr.ExitCode())
		}
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	os.Exit(0)
}

// IsDefaultContextCommand checks if the command exists in the classic cli (issues a shellout --help)
func IsDefaultContextCommand(dockerCommand string) bool {
	cmd := exec.Command(ComDockerCli, dockerCommand, "--help")
	b, e := cmd.CombinedOutput()
	if e != nil {
		fmt.Println(e)
	}
	output := string(b)
	contains := strings.Contains(output, "Usage:\tdocker "+dockerCommand)
	return contains
}

// ExecSilent executes a command and do redirect output to stdOut, return output
func ExecSilent(ctx context.Context) ([]byte, error) {
	cmd := exec.CommandContext(ctx, ComDockerCli, os.Args[1:]...)
	return cmd.CombinedOutput()
}
<|endoftext|>


<commit_before>// Package client is a simple library for http.Client to sign Akamai OPEN Edgegrid API requests
package client

import (
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid"
	"github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1"
)

var (
	libraryVersion = "0.6.2"
	// UserAgent is the User-Agent value sent for all requests
	UserAgent = "Akamai-Open-Edgegrid-golang/" + libraryVersion + " golang/" + strings.TrimPrefix(runtime.Version(), "go")
	// Client is the *http.Client to use
	Client = http.DefaultClient
)

// NewRequest creates an HTTP request that can be sent to Akamai APIs. A relative URL can be provided in path, which will be resolved to the
// Host specified in Config. If body is specified, it will be sent as the request body.
func NewRequest(config edgegrid.Config, method, path string, body io.Reader) (*http.Request, error) {
	var (
		baseURL *url.URL
		err     error
	)

	if strings.HasPrefix(config.Host, "https://") {
		baseURL, err = url.Parse(config.Host)
	} else {
		baseURL, err = url.Parse("https://" + config.Host)
	}

	if err != nil {
		return nil, err
	}

	rel, err := url.Parse(strings.TrimPrefix(path, "/"))
	if err != nil {
		return nil, err
	}

	u := baseURL.ResolveReference(rel)

	req, err := http.NewRequest(method, u.String(), body)
	if err != nil {
		return nil, err
	}

	req.Header.Add("User-Agent", UserAgent)

	return req, nil
}

// NewJSONRequest creates an HTTP request that can be sent to the Akamai APIs with a JSON body
// The JSON body is encoded and the Content-Type/Accept headers are set automatically.
func NewJSONRequest(config edgegrid.Config, method, path string, body interface{}) (*http.Request, error) {
	jsonBody, err := jsonhooks.Marshal(body)
	if err != nil {
		return nil, err
	}

	buf := bytes.NewReader(jsonBody)
	req, err := NewRequest(config, method, path, buf)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json,*/*")

	return req, nil
}

// NewMultiPartFormDataRequest creates an HTTP request that uploads a file to the Akamai API
func NewMultiPartFormDataRequest(config edgegrid.Config, uriPath, filePath string, otherFormParams map[string]string) (*http.Request, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	// TODO: make this field name configurable
	part, err := writer.CreateFormFile("importFile", filepath.Base(filePath))
	if err != nil {
		return nil, err
	}
	_, err = io.Copy(part, file)

	for key, val := range otherFormParams {
		_ = writer.WriteField(key, val)
	}
	err = writer.Close()
	if err != nil {
		return nil, err
	}

	req, err := NewRequest(config, "POST", uriPath, body)
	req.Header.Set("Content-Type", writer.FormDataContentType())
	return req, err
}

// Do performs a given HTTP Request, signed with the Akamai OPEN Edgegrid
// Authorization header. An edgegrid.Response or an error is returned.
func Do(config edgegrid.Config, req *http.Request) (*http.Response, error) {
	Client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		req = edgegrid.AddRequestHeader(config, req)
		return nil
	}

	req = edgegrid.AddRequestHeader(config, req)
	res, err := Client.Do(req)
	if err != nil {
		return nil, err
	}

	return res, nil
}

// BodyJSON unmarshals the Response.Body into a given data structure
func BodyJSON(r *http.Response, data interface{}) error {
	if data == nil {
		return errors.New("You must pass in an interface{}")
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	err = jsonhooks.Unmarshal(body, data)

	return err
}
<commit_msg>Fix issue in new json request where if the body was nil, we'd still pass an empty io reader to it, this affecting the Content-type header of the request - this causes the http request to fail for some api's<commit_after>// Package client is a simple library for http.Client to sign Akamai OPEN Edgegrid API requests
package client

import (
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid"
	"github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1"
)

var (
	libraryVersion = "0.6.2"
	// UserAgent is the User-Agent value sent for all requests
	UserAgent = "Akamai-Open-Edgegrid-golang/" + libraryVersion + " golang/" + strings.TrimPrefix(runtime.Version(), "go")
	// Client is the *http.Client to use
	Client = http.DefaultClient
)

// NewRequest creates an HTTP request that can be sent to Akamai APIs. A relative URL can be provided in path, which will be resolved to the
// Host specified in Config. If body is specified, it will be sent as the request body.
func NewRequest(config edgegrid.Config, method, path string, body io.Reader) (*http.Request, error) {
	var (
		baseURL *url.URL
		err     error
	)

	if strings.HasPrefix(config.Host, "https://") {
		baseURL, err = url.Parse(config.Host)
	} else {
		baseURL, err = url.Parse("https://" + config.Host)
	}

	if err != nil {
		return nil, err
	}

	rel, err := url.Parse(strings.TrimPrefix(path, "/"))
	if err != nil {
		return nil, err
	}

	u := baseURL.ResolveReference(rel)

	req, err := http.NewRequest(method, u.String(), body)
	if err != nil {
		return nil, err
	}

	req.Header.Add("User-Agent", UserAgent)

	return req, nil
}

// NewJSONRequest creates an HTTP request that can be sent to the Akamai APIs with a JSON body
// The JSON body is encoded and the Content-Type/Accept headers are set automatically.
func NewJSONRequest(config edgegrid.Config, method, path string, body interface{}) (*http.Request, error) {
	var req *http.Request
	var err error

	if body != nil {
		jsonBody, err := jsonhooks.Marshal(body)
		if err != nil {
			return nil, err
		}

		buf := bytes.NewReader(jsonBody)
		req, err = NewRequest(config, method, path, buf)
	} else {
		req, err = NewRequest(config, method, path, nil)
	}

	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json,*/*")

	return req, nil
}

// NewMultiPartFormDataRequest creates an HTTP request that uploads a file to the Akamai API
func NewMultiPartFormDataRequest(config edgegrid.Config, uriPath, filePath string, otherFormParams map[string]string) (*http.Request, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	// TODO: make this field name configurable
	part, err := writer.CreateFormFile("importFile", filepath.Base(filePath))
	if err != nil {
		return nil, err
	}
	_, err = io.Copy(part, file)

	for key, val := range otherFormParams {
		_ = writer.WriteField(key, val)
	}
	err = writer.Close()
	if err != nil {
		return nil, err
	}

	req, err := NewRequest(config, "POST", uriPath, body)
	req.Header.Set("Content-Type", writer.FormDataContentType())
	return req, err
}

// Do performs a given HTTP Request, signed with the Akamai OPEN Edgegrid
// Authorization header. An edgegrid.Response or an error is returned.
func Do(config edgegrid.Config, req *http.Request) (*http.Response, error) {
	Client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		req = edgegrid.AddRequestHeader(config, req)
		return nil
	}

	req = edgegrid.AddRequestHeader(config, req)
	res, err := Client.Do(req)
	if err != nil {
		return nil, err
	}

	return res, nil
}

// BodyJSON unmarshals the Response.Body into a given data structure
func BodyJSON(r *http.Response, data interface{}) error {
	if data == nil {
		return errors.New("You must pass in an interface{}")
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	err = jsonhooks.Unmarshal(body, data)

	return err
}
<|endoftext|>


<commit_before>package simple

import (
	"fmt"

	"code.google.com/p/go-uuid/uuid"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/golang/glog"

	routeapi "github.com/openshift/origin/pkg/route/api"
)

// Default DNS suffix to use if no configuration is passed to this plugin.
// Would be better if we could use "v3.openshift.app", someone bought that!
const defaultDNSSuffix = "v3.openshift.com"

// SimpleAllocationPlugin implements the route.AllocationPlugin interface
// to provide a simple unsharded (or single sharded) allocation plugin.
type SimpleAllocationPlugin struct {
	DNSSuffix string
}

// NewSimpleAllocationPlugin creates a new SimpleAllocationPlugin.
func NewSimpleAllocationPlugin(suffix string) (*SimpleAllocationPlugin, error) {
	if len(suffix) == 0 {
		suffix = defaultDNSSuffix
	}

	glog.V(4).Infof("Route plugin initialized with suffix=%s", suffix)

	// Check that the DNS suffix is valid.
	if !util.IsDNS1123Subdomain(suffix) {
		return nil, fmt.Errorf("invalid DNS suffix: %s", suffix)
	}

	return &SimpleAllocationPlugin{DNSSuffix: suffix}, nil
}

// Allocate a router shard for the given route. This plugin always returns
// the "global" router shard.
func (p *SimpleAllocationPlugin) Allocate(route *routeapi.Route) (*routeapi.RouterShard, error) {

	glog.V(4).Infof("Allocating global shard *.%s to Route: %s",
		p.DNSSuffix, route.ServiceName)

	return &routeapi.RouterShard{ShardName: "global", DNSSuffix: p.DNSSuffix}, nil
}

// GenerateHostname generates a host name for a route - using the service name,
// namespace (if provided) and the router shard dns suffix.
func (p *SimpleAllocationPlugin) GenerateHostname(route *routeapi.Route, shard *routeapi.RouterShard) string {

	name := route.ServiceName
	if len(name) == 0 {
		name = uuid.NewUUID().String()
		glog.V(4).Infof("No service name passed, using generated name: %s", name)
	}

	s := ""
	if len(route.Namespace) <= 0 {
		s = fmt.Sprintf("%s.%s", name, shard.DNSSuffix)
	} else {
		s = fmt.Sprintf("%s-%s.%s", name, route.Namespace, shard.DNSSuffix)
	}

	glog.V(4).Infof("Generated hostname=%s for Route: %s", s, route.ServiceName)

	return s
}
<commit_msg>Morse code change - dah to dit (dots).<commit_after>package simple

import (
	"fmt"

	"code.google.com/p/go-uuid/uuid"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/golang/glog"

	routeapi "github.com/openshift/origin/pkg/route/api"
)

// Default DNS suffix to use if no configuration is passed to this plugin.
// Would be better if we could use "v3.openshift.app", someone bought that!
const defaultDNSSuffix = "v3.openshift.com"

// SimpleAllocationPlugin implements the route.AllocationPlugin interface
// to provide a simple unsharded (or single sharded) allocation plugin.
type SimpleAllocationPlugin struct {
	DNSSuffix string
}

// NewSimpleAllocationPlugin creates a new SimpleAllocationPlugin.
func NewSimpleAllocationPlugin(suffix string) (*SimpleAllocationPlugin, error) {
	if len(suffix) == 0 {
		suffix = defaultDNSSuffix
	}

	glog.V(4).Infof("Route plugin initialized with suffix=%s", suffix)

	// Check that the DNS suffix is valid.
	if !util.IsDNS1123Subdomain(suffix) {
		return nil, fmt.Errorf("invalid DNS suffix: %s", suffix)
	}

	return &SimpleAllocationPlugin{DNSSuffix: suffix}, nil
}

// Allocate a router shard for the given route. This plugin always returns
// the "global" router shard.
func (p *SimpleAllocationPlugin) Allocate(route *routeapi.Route) (*routeapi.RouterShard, error) {

	glog.V(4).Infof("Allocating global shard *.%s to Route: %s",
		p.DNSSuffix, route.ServiceName)

	return &routeapi.RouterShard{ShardName: "global", DNSSuffix: p.DNSSuffix}, nil
}

// GenerateHostname generates a host name for a route - using the service name,
// namespace (if provided) and the router shard dns suffix.
func (p *SimpleAllocationPlugin) GenerateHostname(route *routeapi.Route, shard *routeapi.RouterShard) string {

	name := route.ServiceName
	if len(name) == 0 {
		name = uuid.NewUUID().String()
		glog.V(4).Infof("No service name passed, using generated name: %s", name)
	}

	s := ""
	if len(route.Namespace) <= 0 {
		s = fmt.Sprintf("%s.%s", name, shard.DNSSuffix)
	} else {
		s = fmt.Sprintf("%s.%s.%s", name, route.Namespace, shard.DNSSuffix)
	}

	glog.V(4).Infof("Generated hostname=%s for Route: %s", s, route.ServiceName)

	return s
}
<|endoftext|>